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

Last change on this file since 754 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 55.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia 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 d->devMode->dmCopies = d->num_copies;
203
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 if (StartPage(d->hdc) <= 0) {
216 qErrnoWarning("QWin32PrintEngine::begin: StartPage failed");
217 ok = false;
218 }
219
220 if (!ok) {
221 d->state = QPrinter::Idle;
222 } else {
223 d->state = QPrinter::Active;
224 }
225
226 d->matrix = QTransform();
227 d->has_pen = true;
228 d->pen = QColor(Qt::black);
229 d->has_brush = false;
230
231 d->complex_xform = false;
232
233 updateMatrix(d->matrix);
234
235 if (!ok)
236 cleanUp();
237
238 return ok;
239}
240
241bool QWin32PrintEngine::end()
242{
243 Q_D(QWin32PrintEngine);
244
245 if (d->hdc) {
246 if (d->state == QPrinter::Aborted) {
247 cleanUp();
248 AbortDoc(d->hdc);
249 return true;
250 }
251 }
252
253 QAlphaPaintEngine::end();
254 if (!continueCall())
255 return true;
256
257 if (d->hdc) {
258 EndPage(d->hdc); // end; printing done
259 EndDoc(d->hdc);
260 }
261
262 d->state = QPrinter::Idle;
263 d->reinit = true;
264 return true;
265}
266
267bool QWin32PrintEngine::newPage()
268{
269 Q_D(QWin32PrintEngine);
270 Q_ASSERT(isActive());
271
272 Q_ASSERT(d->hdc);
273
274 flushAndInit();
275
276 bool transparent = GetBkMode(d->hdc) == TRANSPARENT;
277
278 if (!EndPage(d->hdc)) {
279 qErrnoWarning("QWin32PrintEngine::newPage: EndPage failed");
280 return false;
281 }
282
283 if (d->reinit) {
284 if (!d->resetDC()) {
285 qErrnoWarning("QWin32PrintEngine::newPage: ResetDC failed");
286 return false;
287 }
288 d->reinit = false;
289 }
290
291 if (!StartPage(d->hdc)) {
292 qErrnoWarning("Win32PrintEngine::newPage: StartPage failed");
293 return false;
294 }
295
296 SetTextAlign(d->hdc, TA_BASELINE);
297 if (transparent)
298 SetBkMode(d->hdc, TRANSPARENT);
299
300 // ###
301 return true;
302
303 bool success = false;
304 if (d->hdc && d->state == QPrinter::Active) {
305 if (EndPage(d->hdc) != SP_ERROR) {
306 // reinitialize the DC before StartPage if needed,
307 // because resetdc is disabled between calls to the StartPage and EndPage functions
308 // (see StartPage documentation in the Platform SDK:Windows GDI)
309// state = PST_ACTIVEDOC;
310// reinit();
311// state = PST_ACTIVE;
312 // start the new page now
313 if (d->reinit) {
314 if (!d->resetDC())
315 qErrnoWarning("QWin32PrintEngine::newPage(), ResetDC failed (2)");
316 d->reinit = false;
317 }
318 success = (StartPage(d->hdc) != SP_ERROR);
319 }
320 if (!success) {
321 d->state = QPrinter::Aborted;
322 return false;
323 }
324 }
325 return true;
326}
327
328bool QWin32PrintEngine::abort()
329{
330 // do nothing loop.
331 return false;
332}
333
334void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
335{
336 Q_D(const QWin32PrintEngine);
337
338 QAlphaPaintEngine::drawTextItem(p, textItem);
339 if (!continueCall())
340 return;
341
342 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
343 QRgb brushColor = state->pen().brush().color().rgb();
344 bool fallBack = state->pen().brush().style() != Qt::SolidPattern
345 || qAlpha(brushColor) != 0xff
346 || d->txop >= QTransform::TxProject
347 || ti.fontEngine->type() != QFontEngine::Win;
348
349
350 if (!fallBack) {
351 QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine);
352
353 // Try selecting the font to see if we get a substitution font
354 SelectObject(d->hdc, fe->hfont);
355
356 if (GetDeviceCaps(d->hdc, TECHNOLOGY) != DT_CHARSTREAM) {
357 wchar_t n[64];
358 GetTextFace(d->hdc, 64, n);
359 fallBack = QString::fromWCharArray(n)
360 != QString::fromWCharArray(fe->logfont.lfFaceName);
361 }
362 }
363
364
365 if (fallBack) {
366 QPaintEngine::drawTextItem(p, textItem);
367 return ;
368 }
369
370 // We only want to convert the glyphs to text if the entire string is compatible with ASCII
371 bool convertToText = true;
372 for (int i=0; i < ti.num_chars; ++i) {
373 if (ti.chars[i].unicode() >= 0x80) {
374 convertToText = false;
375 break;
376 }
377
378 if (ti.logClusters[i] != i) {
379 convertToText = false;
380 break;
381 }
382 }
383
384 COLORREF cf = RGB(qRed(brushColor), qGreen(brushColor), qBlue(brushColor));
385 SelectObject(d->hdc, CreateSolidBrush(cf));
386 SelectObject(d->hdc, CreatePen(PS_SOLID, 1, cf));
387 SetTextColor(d->hdc, cf);
388
389 draw_text_item_win(p, ti, d->hdc, convertToText, d->matrix, d->devPaperRect.topLeft());
390 DeleteObject(SelectObject(d->hdc,GetStockObject(HOLLOW_BRUSH)));
391 DeleteObject(SelectObject(d->hdc,GetStockObject(BLACK_PEN)));
392}
393
394static inline qreal mmToInches(double mm)
395{
396 return mm*0.039370147;
397}
398
399static inline qreal inchesToMM(double in)
400{
401 return in/0.039370147;
402}
403
404int QWin32PrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
405{
406 Q_D(const QWin32PrintEngine);
407
408 if (!d->hdc)
409 return 0;
410
411 int val;
412 int res = d->resolution;
413
414 switch (m) {
415 case QPaintDevice::PdmWidth:
416 if (d->has_custom_paper_size) {
417 val = qRound(d->paper_size.width() * res / 72.0);
418 } else {
419 int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
420 if (logPixelsX == 0) {
421 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
422 "might be a driver problem");
423 logPixelsX = 600; // Reasonable default
424 }
425 val = res
426 * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALWIDTH : HORZRES)
427 / logPixelsX;
428 }
429 if (d->pageMarginsSet)
430 val -= int(mmToInches((d->previousDialogMargins.left() +
431 d->previousDialogMargins.width()) / 100.0) * res);
432 break;
433 case QPaintDevice::PdmHeight:
434 if (d->has_custom_paper_size) {
435 val = qRound(d->paper_size.height() * res / 72.0);
436 } else {
437 int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
438 if (logPixelsY == 0) {
439 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
440 "might be a driver problem");
441 logPixelsY = 600; // Reasonable default
442 }
443 val = res
444 * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALHEIGHT : VERTRES)
445 / logPixelsY;
446 }
447 if (d->pageMarginsSet)
448 val -= int(mmToInches((d->previousDialogMargins.top() +
449 d->previousDialogMargins.height()) / 100.0) * res);
450 break;
451 case QPaintDevice::PdmDpiX:
452 val = res;
453 break;
454 case QPaintDevice::PdmDpiY:
455 val = res;
456 break;
457 case QPaintDevice::PdmPhysicalDpiX:
458 val = GetDeviceCaps(d->hdc, LOGPIXELSX);
459 break;
460 case QPaintDevice::PdmPhysicalDpiY:
461 val = GetDeviceCaps(d->hdc, LOGPIXELSY);
462 break;
463 case QPaintDevice::PdmWidthMM:
464 if (d->has_custom_paper_size) {
465 val = qRound(d->paper_size.width()*25.4/72);
466 } else {
467 if (!d->fullPage) {
468 val = GetDeviceCaps(d->hdc, HORZSIZE);
469 } else {
470 float wi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALWIDTH);
471 int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
472 if (logPixelsX == 0) {
473 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
474 "might be a driver problem");
475 logPixelsX = 600; // Reasonable default
476 }
477 val = qRound(wi / logPixelsX);
478 }
479 }
480 if (d->pageMarginsSet)
481 val -= (d->previousDialogMargins.left() +
482 d->previousDialogMargins.width()) / 100.0;
483 break;
484 case QPaintDevice::PdmHeightMM:
485 if (d->has_custom_paper_size) {
486 val = qRound(d->paper_size.height()*25.4/72);
487 } else {
488 if (!d->fullPage) {
489 val = GetDeviceCaps(d->hdc, VERTSIZE);
490 } else {
491 float hi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALHEIGHT);
492 int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
493 if (logPixelsY == 0) {
494 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
495 "might be a driver problem");
496 logPixelsY = 600; // Reasonable default
497 }
498 val = qRound(hi / logPixelsY);
499 }
500 }
501 if (d->pageMarginsSet)
502 val -= (d->previousDialogMargins.top() +
503 d->previousDialogMargins.height()) / 100.0;
504 break;
505 case QPaintDevice::PdmNumColors:
506 {
507 int bpp = GetDeviceCaps(d->hdc, BITSPIXEL);
508 if(bpp==32)
509 val = INT_MAX;
510 else if(bpp<=8)
511 val = GetDeviceCaps(d->hdc, NUMCOLORS);
512 else
513 val = 1 << (bpp * GetDeviceCaps(d->hdc, PLANES));
514 }
515 break;
516 case QPaintDevice::PdmDepth:
517 val = GetDeviceCaps(d->hdc, PLANES);
518 break;
519 default:
520 qWarning("QPrinter::metric: Invalid metric command");
521 return 0;
522 }
523 return val;
524}
525
526void QWin32PrintEngine::updateState(const QPaintEngineState &state)
527{
528 Q_D(QWin32PrintEngine);
529
530 QAlphaPaintEngine::updateState(state);
531 if (!continueCall())
532 return;
533
534 if (state.state() & DirtyTransform) {
535 updateMatrix(state.transform());
536 }
537
538 if (state.state() & DirtyPen) {
539 d->pen = state.pen();
540 d->has_pen = d->pen.style() != Qt::NoPen && d->pen.isSolid();
541 }
542
543 if (state.state() & DirtyBrush) {
544 QBrush brush = state.brush();
545 d->has_brush = brush.style() == Qt::SolidPattern;
546 d->brush_color = brush.color();
547 }
548
549 if (state.state() & DirtyClipEnabled) {
550 if (state.isClipEnabled())
551 updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
552 else
553 updateClipPath(QPainterPath(), Qt::NoClip);
554 }
555
556 if (state.state() & DirtyClipPath) {
557 updateClipPath(state.clipPath(), state.clipOperation());
558 }
559
560 if (state.state() & DirtyClipRegion) {
561 QRegion clipRegion = state.clipRegion();
562 QPainterPath clipPath = qt_regionToPath(clipRegion);
563 updateClipPath(clipPath, state.clipOperation());
564 }
565}
566
567void QWin32PrintEngine::updateClipPath(const QPainterPath &clipPath, Qt::ClipOperation op)
568{
569 Q_D(QWin32PrintEngine);
570
571 bool doclip = true;
572 if (op == Qt::NoClip) {
573 SelectClipRgn(d->hdc, 0);
574 doclip = false;
575 }
576
577 if (doclip) {
578 QPainterPath xformed = clipPath * d->matrix;
579
580 if (xformed.isEmpty()) {
581 QRegion empty(-0x1000000, -0x1000000, 1, 1);
582 SelectClipRgn(d->hdc, empty.handle());
583 } else {
584 d->composeGdiPath(xformed);
585 const int ops[] = {
586 -1, // Qt::NoClip, covered above
587 RGN_COPY, // Qt::ReplaceClip
588 RGN_AND, // Qt::IntersectClip
589 RGN_OR // Qt::UniteClip
590 };
591 Q_ASSERT(op > 0 && unsigned(op) <= sizeof(ops) / sizeof(int));
592 SelectClipPath(d->hdc, ops[op]);
593 }
594 }
595
596 QPainterPath aclip = qt_regionToPath(alphaClipping());
597 if (!aclip.isEmpty()) {
598 QTransform tx(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
599 d->composeGdiPath(tx.map(aclip));
600 SelectClipPath(d->hdc, RGN_DIFF);
601 }
602}
603
604void QWin32PrintEngine::updateMatrix(const QTransform &m)
605{
606 Q_D(QWin32PrintEngine);
607
608 QTransform stretch(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
609 d->painterMatrix = m;
610 d->matrix = d->painterMatrix * stretch;
611 d->txop = d->matrix.type();
612 d->complex_xform = (d->txop > QTransform::TxScale);
613}
614
615void QWin32PrintEngine::drawPixmap(const QRectF &targetRect,
616 const QPixmap &originalPixmap,
617 const QRectF &sourceRect)
618{
619 Q_D(QWin32PrintEngine);
620
621 QAlphaPaintEngine::drawPixmap(targetRect, originalPixmap, sourceRect);
622 if (!continueCall())
623 return;
624
625 const int tileSize = 2048;
626
627 QRectF r = targetRect;
628 QRectF sr = sourceRect;
629
630 QPixmap pixmap = originalPixmap;
631 if (sr.size() != pixmap.size()) {
632 pixmap = pixmap.copy(sr.toRect());
633 }
634
635 qreal scaleX = 1.0f;
636 qreal scaleY = 1.0f;
637
638 QTransform scaleMatrix = QTransform::fromScale(r.width() / pixmap.width(), r.height() / pixmap.height());
639 QTransform adapted = QPixmap::trueMatrix(d->painterMatrix * scaleMatrix,
640 pixmap.width(), pixmap.height());
641
642 qreal xform_offset_x = adapted.dx();
643 qreal xform_offset_y = adapted.dy();
644
645 if (d->complex_xform) {
646 pixmap = pixmap.transformed(adapted);
647 scaleX = d->stretch_x;
648 scaleY = d->stretch_y;
649 } else {
650 scaleX = d->stretch_x * (r.width() / pixmap.width()) * d->painterMatrix.m11();
651 scaleY = d->stretch_y * (r.height() / pixmap.height()) * d->painterMatrix.m22();
652 }
653
654 QPointF topLeft = r.topLeft() * d->painterMatrix;
655 int tx = int(topLeft.x() * d->stretch_x + d->origin_x);
656 int ty = int(topLeft.y() * d->stretch_y + d->origin_y);
657 int tw = qAbs(int(pixmap.width() * scaleX));
658 int th = qAbs(int(pixmap.height() * scaleY));
659
660 xform_offset_x *= d->stretch_x;
661 xform_offset_y *= d->stretch_y;
662
663 int dc_state = SaveDC(d->hdc);
664
665 int tilesw = pixmap.width() / tileSize;
666 int tilesh = pixmap.height() / tileSize;
667 ++tilesw;
668 ++tilesh;
669
670 int txinc = tileSize*scaleX;
671 int tyinc = tileSize*scaleY;
672
673 for (int y = 0; y < tilesh; ++y) {
674 int tposy = ty + (y * tyinc);
675 int imgh = tileSize;
676 int height = tyinc;
677 if (y == (tilesh - 1)) {
678 imgh = pixmap.height() - (y * tileSize);
679 height = (th - (y * tyinc));
680 }
681 for (int x = 0; x < tilesw; ++x) {
682 int tposx = tx + (x * txinc);
683 int imgw = tileSize;
684 int width = txinc;
685 if (x == (tilesw - 1)) {
686 imgw = pixmap.width() - (x * tileSize);
687 width = (tw - (x * txinc));
688 }
689
690 QPixmap p = pixmap.copy(tileSize * x, tileSize * y, imgw, imgh);
691 HBITMAP hbitmap = p.toWinHBITMAP(QPixmap::NoAlpha);
692 HDC display_dc = GetDC(0);
693 HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
694 HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
695
696 ReleaseDC(0, display_dc);
697
698 if (!StretchBlt(d->hdc, qRound(tposx - xform_offset_x), qRound(tposy - xform_offset_y), width, height,
699 hbitmap_hdc, 0, 0, p.width(), p.height(), SRCCOPY))
700 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
701
702 SelectObject(hbitmap_hdc, null_bitmap);
703 DeleteObject(hbitmap);
704 DeleteDC(hbitmap_hdc);
705 }
706 }
707
708 RestoreDC(d->hdc, dc_state);
709}
710
711
712void QWin32PrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &pos)
713{
714 Q_D(QWin32PrintEngine);
715
716 QAlphaPaintEngine::drawTiledPixmap(r, pm, pos);
717 if (!continueCall())
718 return;
719
720 if (d->complex_xform || !pos.isNull()) {
721 QPaintEngine::drawTiledPixmap(r, pm, pos);
722 } else {
723 int dc_state = SaveDC(d->hdc);
724
725 HDC display_dc = GetDC(0);
726 HBITMAP hbitmap = pm.toWinHBITMAP(QPixmap::NoAlpha);
727 HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
728 HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
729
730 ReleaseDC(0, display_dc);
731
732 QRectF trect = d->painterMatrix.mapRect(r);
733 int tx = int(trect.left() * d->stretch_x + d->origin_x);
734 int ty = int(trect.top() * d->stretch_y + d->origin_y);
735
736 int xtiles = int(trect.width() / pm.width()) + 1;
737 int ytiles = int(trect.height() / pm.height()) + 1;
738 int xinc = int(pm.width() * d->stretch_x);
739 int yinc = int(pm.height() * d->stretch_y);
740
741 for (int y = 0; y < ytiles; ++y) {
742 int ity = ty + (yinc * y);
743 int ith = pm.height();
744 if (y == (ytiles - 1)) {
745 ith = int(trect.height() - (pm.height() * y));
746 }
747
748 for (int x = 0; x < xtiles; ++x) {
749 int itx = tx + (xinc * x);
750 int itw = pm.width();
751 if (x == (xtiles - 1)) {
752 itw = int(trect.width() - (pm.width() * x));
753 }
754
755 if (!StretchBlt(d->hdc, itx, ity, int(itw * d->stretch_x), int(ith * d->stretch_y),
756 hbitmap_hdc, 0, 0, itw, ith, SRCCOPY))
757 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
758
759 }
760 }
761
762 SelectObject(hbitmap_hdc, null_bitmap);
763 DeleteObject(hbitmap);
764 DeleteDC(hbitmap_hdc);
765
766 RestoreDC(d->hdc, dc_state);
767 }
768}
769
770
771void QWin32PrintEnginePrivate::composeGdiPath(const QPainterPath &path)
772{
773 if (!BeginPath(hdc))
774 qErrnoWarning("QWin32PrintEnginePrivate::drawPath: BeginPath failed");
775
776 // Drawing the subpaths
777 int start = -1;
778 for (int i=0; i<path.elementCount(); ++i) {
779 const QPainterPath::Element &elm = path.elementAt(i);
780 switch (elm.type) {
781 case QPainterPath::MoveToElement:
782 if (start >= 0
783 && path.elementAt(start).x == path.elementAt(i-1).x
784 && path.elementAt(start).y == path.elementAt(i-1).y)
785 CloseFigure(hdc);
786 start = i;
787 MoveToEx(hdc, qRound(elm.x), qRound(elm.y), 0);
788 break;
789 case QPainterPath::LineToElement:
790 LineTo(hdc, qRound(elm.x), qRound(elm.y));
791 break;
792 case QPainterPath::CurveToElement: {
793 POINT pts[3] = {
794 { qRound(elm.x), qRound(elm.y) },
795 { qRound(path.elementAt(i+1).x), qRound(path.elementAt(i+1).y) },
796 { qRound(path.elementAt(i+2).x), qRound(path.elementAt(i+2).y) }
797 };
798 i+=2;
799 PolyBezierTo(hdc, pts, 3);
800 break;
801 }
802 default:
803 qFatal("QWin32PaintEngine::drawPath: Unhandled type: %d", elm.type);
804 }
805 }
806
807 if (start >= 0
808 && path.elementAt(start).x == path.elementAt(path.elementCount()-1).x
809 && path.elementAt(start).y == path.elementAt(path.elementCount()-1).y)
810 CloseFigure(hdc);
811
812 if (!EndPath(hdc))
813 qErrnoWarning("QWin32PaintEngine::drawPath: EndPath failed");
814
815 SetPolyFillMode(hdc, path.fillRule() == Qt::WindingFill ? WINDING : ALTERNATE);
816}
817
818
819void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QColor &color)
820{
821#ifdef QT_DEBUG_DRAW
822 qDebug() << " --- QWin32PrintEnginePrivate::fillPath() bound:" << path.boundingRect() << color;
823#endif
824
825 composeGdiPath(path);
826
827 HBRUSH brush = CreateSolidBrush(RGB(color.red(), color.green(), color.blue()));
828 HGDIOBJ old_brush = SelectObject(hdc, brush);
829 FillPath(hdc);
830 DeleteObject(SelectObject(hdc, old_brush));
831}
832
833void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth)
834{
835 composeGdiPath(path);
836 LOGBRUSH brush;
837 brush.lbStyle = BS_SOLID;
838 brush.lbColor = RGB(color.red(), color.green(), color.blue());
839 DWORD capStyle = PS_ENDCAP_SQUARE;
840 DWORD joinStyle = PS_JOIN_BEVEL;
841 if (pen.capStyle() == Qt::FlatCap)
842 capStyle = PS_ENDCAP_FLAT;
843 else if (pen.capStyle() == Qt::RoundCap)
844 capStyle = PS_ENDCAP_ROUND;
845
846 if (pen.joinStyle() == Qt::MiterJoin)
847 joinStyle = PS_JOIN_MITER;
848 else if (pen.joinStyle() == Qt::RoundJoin)
849 joinStyle = PS_JOIN_ROUND;
850
851 HPEN pen = ExtCreatePen(((penWidth == 0) ? PS_COSMETIC : PS_GEOMETRIC)
852 | PS_SOLID | capStyle | joinStyle,
853 penWidth, &brush, 0, 0);
854
855 HGDIOBJ old_pen = SelectObject(hdc, pen);
856 StrokePath(hdc);
857 DeleteObject(SelectObject(hdc, old_pen));
858}
859
860
861void QWin32PrintEnginePrivate::fillPath(const QPainterPath &path, const QColor &color)
862{
863 fillPath_dev(path * matrix, color);
864}
865
866void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor &color)
867{
868 QPainterPathStroker stroker;
869 if (pen.style() == Qt::CustomDashLine) {
870 stroker.setDashPattern(pen.dashPattern());
871 stroker.setDashOffset(pen.dashOffset());
872 } else {
873 stroker.setDashPattern(pen.style());
874 }
875 stroker.setCapStyle(pen.capStyle());
876 stroker.setJoinStyle(pen.joinStyle());
877 stroker.setMiterLimit(pen.miterLimit());
878
879 QPainterPath stroke;
880 qreal width = pen.widthF();
881 if (pen.style() == Qt::SolidLine && (pen.isCosmetic() || matrix.type() < QTransform::TxScale)) {
882 strokePath_dev(path * matrix, color, width);
883 } else {
884 stroker.setWidth(width);
885 if (pen.isCosmetic()) {
886 stroke = stroker.createStroke(path * matrix);
887 } else {
888 stroke = stroker.createStroke(path) * painterMatrix;
889 QTransform stretch(stretch_x, 0, 0, stretch_y, origin_x, origin_y);
890 stroke = stroke * stretch;
891 }
892
893 if (stroke.isEmpty())
894 return;
895
896 fillPath_dev(stroke, color);
897 }
898}
899
900
901void QWin32PrintEngine::drawPath(const QPainterPath &path)
902{
903#ifdef QT_DEBUG_DRAW
904 qDebug() << " - QWin32PrintEngine::drawPath(), bounds: " << path.boundingRect();
905#endif
906
907 Q_D(QWin32PrintEngine);
908
909 QAlphaPaintEngine::drawPath(path);
910 if (!continueCall())
911 return;
912
913 if (d->has_brush)
914 d->fillPath(path, d->brush_color);
915
916 if (d->has_pen)
917 d->strokePath(path, d->pen.color());
918}
919
920
921void QWin32PrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
922{
923#ifdef QT_DEBUG_DRAW
924 qDebug() << " - QWin32PrintEngine::drawPolygon(), pointCount: " << pointCount;
925#endif
926
927 QAlphaPaintEngine::drawPolygon(points, pointCount, mode);
928 if (!continueCall())
929 return;
930
931 Q_ASSERT(pointCount > 1);
932
933 QPainterPath path(points[0]);
934
935 for (int i=1; i<pointCount; ++i) {
936 path.lineTo(points[i]);
937 }
938
939 Q_D(QWin32PrintEngine);
940
941 bool has_brush = d->has_brush;
942
943 if (mode == PolylineMode)
944 d->has_brush = false; // No brush for polylines
945 else
946 path.closeSubpath(); // polygons are should always be closed.
947
948 drawPath(path);
949 d->has_brush = has_brush;
950}
951
952void QWin32PrintEnginePrivate::queryDefault()
953{
954 /* Read the default printer name, driver and port with the intuitive function
955 * Strings "windows" and "device" are specified in the MSDN under EnumPrinters()
956 */
957 QString noPrinters(QLatin1String("qt_no_printers"));
958 wchar_t buffer[256];
959 GetProfileString(L"windows", L"device",
960 reinterpret_cast<const wchar_t *>(noPrinters.utf16()),
961 buffer, 256);
962 QString output = QString::fromWCharArray(buffer);
963 if (output.isEmpty() || output == noPrinters) // no printers
964 return;
965
966 QStringList info = output.split(QLatin1Char(','));
967 if (info.size() > 0) {
968 if (name.isEmpty())
969 name = info.at(0);
970 if (program.isEmpty())
971 program = info.at(1);
972 if (port.isEmpty())
973 port = info.at(2);
974 }
975}
976
977QWin32PrintEnginePrivate::~QWin32PrintEnginePrivate()
978{
979 if (hdc)
980 release();
981}
982
983void 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
1046void 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
1080void 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
1099void 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
1111QRect 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
1122void 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
1145QList<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
1172void QWin32PrintEnginePrivate::doReinit()
1173{
1174 if (state == QPrinter::Active) {
1175 reinit = true;
1176 } else {
1177 resetDC();
1178 initDevRects();
1179 reinit = false;
1180 }
1181}
1182
1183void 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
1204void 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_NumberOfCopies:
1244 if (!d->devMode)
1245 break;
1246 d->num_copies = value.toInt();
1247 d->devMode->dmCopies = d->num_copies;
1248 d->doReinit();
1249 break;
1250
1251 case PPK_Orientation:
1252 {
1253 if (!d->devMode)
1254 break;
1255 int orientation = value.toInt() == QPrinter::Landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
1256 int old_orientation = d->devMode->dmOrientation;
1257 d->devMode->dmOrientation = orientation;
1258 if (d->has_custom_paper_size && old_orientation != orientation)
1259 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1260 d->doReinit();
1261 }
1262 break;
1263
1264 case PPK_OutputFileName:
1265 if (isActive()) {
1266 qWarning("QWin32PrintEngine: Cannot change filename while printing");
1267 } else {
1268 d->fileName = value.toString();
1269 d->printToFile = !value.toString().isEmpty();
1270 }
1271 break;
1272
1273 case PPK_PaperSize:
1274 if (!d->devMode)
1275 break;
1276 d->devMode->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
1277 d->has_custom_paper_size = (QPrinter::PaperSize(value.toInt()) == QPrinter::Custom);
1278 d->doReinit();
1279 break;
1280
1281 case PPK_PaperSource:
1282 {
1283 if (!d->devMode)
1284 break;
1285 int dmMapped = DMBIN_AUTO;
1286
1287 QList<QVariant> v = property(PPK_PaperSources).toList();
1288 if (v.contains(value))
1289 dmMapped = mapPaperSourceDevmode(QPrinter::PaperSource(value.toInt()));
1290
1291 d->devMode->dmDefaultSource = dmMapped;
1292 d->doReinit();
1293 }
1294 break;
1295
1296 case PPK_PrinterName:
1297 d->name = value.toString();
1298 if(d->name.isEmpty())
1299 d->queryDefault();
1300 d->initialize();
1301 break;
1302
1303 case PPK_Resolution:
1304 {
1305 d->resolution = value.toInt();
1306
1307 d->stretch_x = d->dpi_x / double(d->resolution);
1308 d->stretch_y = d->dpi_y / double(d->resolution);
1309 }
1310 break;
1311
1312 case PPK_SelectionOption:
1313
1314 break;
1315
1316 case PPK_SupportedResolutions:
1317
1318 break;
1319
1320
1321 case PPK_WindowsPageSize:
1322 if (!d->devMode)
1323 break;
1324 d->has_custom_paper_size = false;
1325 d->devMode->dmPaperSize = value.toInt();
1326 d->doReinit();
1327 break;
1328
1329 case PPK_CustomPaperSize:
1330 {
1331 d->has_custom_paper_size = true;
1332 d->paper_size = value.toSizeF();
1333 if (!d->devMode)
1334 break;
1335 int orientation = d->devMode->dmOrientation;
1336 DWORD needed = 0;
1337 DWORD returned = 0;
1338 if (!EnumForms(d->hPrinter, 1, 0, 0, &needed, &returned)) {
1339 BYTE *forms = (BYTE *) malloc(needed);
1340 if (EnumForms(d->hPrinter, 1, forms, needed, &needed, &returned)) {
1341 for (DWORD i=0; i< returned; ++i) {
1342 FORM_INFO_1 *formArray = reinterpret_cast<FORM_INFO_1 *>(forms);
1343 // the form sizes are specified in 1000th of a mm,
1344 // convert the size to Points
1345 QSizeF size((formArray[i].Size.cx * 72/25.4)/1000.0,
1346 (formArray[i].Size.cy * 72/25.4)/1000.0);
1347 if (qAbs(d->paper_size.width() - size.width()) <= 2
1348 && qAbs(d->paper_size.height() - size.height()) <= 2)
1349 {
1350 d->devMode->dmPaperSize = i + 1;
1351 break;
1352 }
1353 }
1354 }
1355 free(forms);
1356 }
1357 if (orientation != DMORIENT_PORTRAIT)
1358 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1359 break;
1360 }
1361
1362 case PPK_PageMargins:
1363 {
1364 QList<QVariant> margins(value.toList());
1365 Q_ASSERT(margins.size() == 4);
1366 int left, top, right, bottom;
1367 // specified in 1/100 mm
1368 left = (margins.at(0).toReal()*25.4/72.0) * 100;
1369 top = (margins.at(1).toReal()*25.4/72.0) * 100;
1370 right = (margins.at(2).toReal()*25.4/72.0) * 100;
1371 bottom = (margins.at(3).toReal()*25.4/72.0) * 100;
1372 d->setPageMargins(left, top, right, bottom);
1373 break;
1374 }
1375 default:
1376 // Do nothing
1377 break;
1378 }
1379}
1380
1381QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const
1382{
1383 Q_D(const QWin32PrintEngine);
1384 QVariant value;
1385 switch (key) {
1386
1387 case PPK_CollateCopies:
1388 value = false;
1389 break;
1390
1391 case PPK_ColorMode:
1392 {
1393 if (!d->devMode) {
1394 value = QPrinter::Color;
1395 } else {
1396 value = (d->devMode->dmColor == DMCOLOR_COLOR) ? QPrinter::Color : QPrinter::GrayScale;
1397 }
1398 }
1399 break;
1400
1401 case PPK_DocumentName:
1402 value = d->docName;
1403 break;
1404
1405 case PPK_FullPage:
1406 value = d->fullPage;
1407 break;
1408
1409 case PPK_NumberOfCopies:
1410 value = 1;
1411 break;
1412
1413 case PPK_Orientation:
1414 {
1415 if (!d->devMode) {
1416 value = QPrinter::Portrait;
1417 } else {
1418 value = (d->devMode->dmOrientation == DMORIENT_LANDSCAPE) ? QPrinter::Landscape : QPrinter::Portrait;
1419 }
1420 }
1421 break;
1422
1423 case PPK_OutputFileName:
1424 value = d->fileName;
1425 break;
1426
1427 case PPK_PageRect:
1428 if (d->has_custom_paper_size) {
1429 QRect rect(0, 0,
1430 qRound(d->paper_size.width() * d->resolution / 72.0),
1431 qRound(d->paper_size.height() * d->resolution / 72.0));
1432 if (d->pageMarginsSet) {
1433 rect = rect.adjusted(qRound(mmToInches(d->previousDialogMargins.left()/100.0) * d->resolution),
1434 qRound(mmToInches(d->previousDialogMargins.top()/100.0) * d->resolution),
1435 -qRound(mmToInches(d->previousDialogMargins.width()/100.0) * d->resolution),
1436 -qRound(mmToInches(d->previousDialogMargins.height()/100.0) * d->resolution));
1437 }
1438 value = rect;
1439 } else {
1440 value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0)
1441 .mapRect(d->fullPage ? d->devPhysicalPageRect : d->devPageRect);
1442 }
1443 break;
1444
1445 case PPK_PaperSize:
1446 if (d->has_custom_paper_size) {
1447 value = QPrinter::Custom;
1448 } else {
1449 if (!d->devMode) {
1450 value = QPrinter::A4;
1451 } else {
1452 value = mapDevmodePaperSize(d->devMode->dmPaperSize);
1453 }
1454 }
1455 break;
1456
1457 case PPK_PaperRect:
1458 if (d->has_custom_paper_size) {
1459 value = QRect(0, 0,
1460 qRound(d->paper_size.width() * d->resolution / 72.0),
1461 qRound(d->paper_size.height() * d->resolution / 72.0));
1462 } else {
1463 value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0).mapRect(d->devPaperRect);
1464 }
1465 break;
1466
1467 case PPK_PaperSource:
1468 if (!d->devMode) {
1469 value = QPrinter::Auto;
1470 } else {
1471 value = mapDevmodePaperSource(d->devMode->dmDefaultSource);
1472 }
1473 break;
1474
1475 case PPK_PrinterName:
1476 value = d->name;
1477 break;
1478
1479 case PPK_Resolution:
1480 if (d->resolution || !d->name.isEmpty())
1481 value = d->resolution;
1482 break;
1483
1484 case PPK_SupportedResolutions:
1485 value = d->queryResolutions();
1486 break;
1487
1488 case PPK_WindowsPageSize:
1489 if (!d->devMode) {
1490 value = -1;
1491 } else {
1492 value = d->devMode->dmPaperSize;
1493 }
1494 break;
1495
1496 case PPK_PaperSources:
1497 {
1498 int available = DeviceCapabilities((const wchar_t *)d->name.utf16(),
1499 (const wchar_t *)d->port.utf16(), DC_BINS, 0, d->devMode);
1500
1501 if (available <= 0)
1502 break;
1503
1504 wchar_t *data = new wchar_t[available];
1505 int count = DeviceCapabilities((const wchar_t *)d->name.utf16(),
1506 (const wchar_t *)d->port.utf16(), DC_BINS, data, d->devMode);
1507
1508 QList<QVariant> out;
1509 for (int i=0; i<count; ++i) {
1510 QPrinter::PaperSource src = mapDevmodePaperSource(data[i]);
1511 if (src != -1)
1512 out << (int) src;
1513 }
1514 value = out;
1515
1516 delete [] data;
1517 }
1518 break;
1519
1520 case PPK_CustomPaperSize:
1521 value = d->paper_size;
1522 break;
1523
1524 case PPK_PageMargins:
1525 {
1526 QList<QVariant> margins;
1527 QRect pageMargins(d->getPageMargins());
1528
1529 // specified in 1/100 mm
1530 margins << (mmToInches(pageMargins.left()/100.0) * 72)
1531 << (mmToInches(pageMargins.top()/100.0) * 72)
1532 << (mmToInches(pageMargins.width()/100.0) * 72)
1533 << (mmToInches(pageMargins.height()/100.0) * 72);
1534 value = margins;
1535 break;
1536 }
1537 default:
1538 // Do nothing
1539 break;
1540 }
1541 return value;
1542}
1543
1544QPrinter::PrinterState QWin32PrintEngine::printerState() const
1545{
1546 return d_func()->state;
1547}
1548
1549HDC QWin32PrintEngine::getDC() const
1550{
1551 return d_func()->hdc;
1552}
1553
1554void QWin32PrintEngine::releaseDC(HDC) const
1555{
1556
1557}
1558
1559HGLOBAL *QWin32PrintEnginePrivate::createDevNames()
1560{
1561 int size = sizeof(DEVNAMES)
1562 + program.length() * 2 + 2
1563 + name.length() * 2 + 2
1564 + port.length() * 2 + 2;
1565 HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size);
1566 DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal);
1567
1568 dn->wDriverOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
1569 dn->wDeviceOffset = dn->wDriverOffset + program.length() + 1;
1570 dn->wOutputOffset = dn->wDeviceOffset + name.length() + 1;
1571
1572 memcpy((ushort*)dn + dn->wDriverOffset, program.utf16(), program.length() * 2 + 2);
1573 memcpy((ushort*)dn + dn->wDeviceOffset, name.utf16(), name.length() * 2 + 2);
1574 memcpy((ushort*)dn + dn->wOutputOffset, port.utf16(), port.length() * 2 + 2);
1575 dn->wDefault = 0;
1576
1577 GlobalUnlock(hGlobal);
1578
1579// printf("QPrintDialogWinPrivate::createDevNames()\n"
1580// " -> wDriverOffset: %d\n"
1581// " -> wDeviceOffset: %d\n"
1582// " -> wOutputOffset: %d\n",
1583// dn->wDriverOffset,
1584// dn->wDeviceOffset,
1585// dn->wOutputOffset);
1586
1587// printf("QPrintDialogWinPrivate::createDevNames(): %s, %s, %s\n",
1588// QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset).latin1(),
1589// QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset).latin1(),
1590// QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset).latin1());
1591
1592 return hGlobal;
1593}
1594
1595void QWin32PrintEnginePrivate::readDevnames(HGLOBAL globalDevnames)
1596{
1597 if (globalDevnames) {
1598 DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevnames);
1599 name = QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset);
1600 port = QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset);
1601 program = QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset);
1602 GlobalUnlock(globalDevnames);
1603 }
1604}
1605
1606void QWin32PrintEnginePrivate::readDevmode(HGLOBAL globalDevmode)
1607{
1608 if (globalDevmode) {
1609 DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevmode);
1610 release();
1611 globalDevMode = globalDevmode;
1612 devMode = dm;
1613 hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1614 reinterpret_cast<const wchar_t *>(name.utf16()), 0, dm);
1615
1616 num_copies = devMode->dmCopies;
1617 if (!OpenPrinter((wchar_t*)name.utf16(), &hPrinter, 0))
1618 qWarning("QPrinter: OpenPrinter() failed after reading DEVMODE.");
1619 }
1620
1621 if (hdc)
1622 initHDC();
1623}
1624
1625static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
1626 bool convertToText, const QTransform &xform, const QPointF &topLeft)
1627{
1628 QFontEngine *fe = ti.fontEngine;
1629 QPointF baseline_pos = xform.inverted().map(xform.map(pos) - topLeft);
1630
1631 SetTextAlign(hdc, TA_BASELINE);
1632 SetBkMode(hdc, TRANSPARENT);
1633
1634 bool has_kerning = ti.f && ti.f->kerning();
1635 QFontEngineWin *winfe = (fe->type() == QFontEngine::Win) ? static_cast<QFontEngineWin *>(fe) : 0;
1636
1637 HFONT hfont;
1638 bool ttf = false;
1639
1640 if (winfe) {
1641 hfont = winfe->hfont;
1642 ttf = winfe->ttf;
1643 } else {
1644 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1645 }
1646
1647 HGDIOBJ old_font = SelectObject(hdc, hfont);
1648 unsigned int options = (ttf && !convertToText) ? ETO_GLYPH_INDEX : 0;
1649 wchar_t *convertedGlyphs = (wchar_t *)ti.chars;
1650 QGlyphLayout glyphs = ti.glyphs;
1651
1652 bool fast = !has_kerning && !(ti.flags & QTextItem::RightToLeft);
1653 for (int i = 0; fast && i < glyphs.numGlyphs; i++) {
1654 if (glyphs.offsets[i].x != 0 || glyphs.offsets[i].y != 0 || glyphs.justifications[i].space_18d6 != 0
1655 || glyphs.attributes[i].dontPrint) {
1656 fast = false;
1657 break;
1658 }
1659 }
1660
1661#if !defined(Q_OS_WINCE)
1662 // Scale, rotate and translate here.
1663 XFORM win_xform;
1664 win_xform.eM11 = xform.m11();
1665 win_xform.eM12 = xform.m12();
1666 win_xform.eM21 = xform.m21();
1667 win_xform.eM22 = xform.m22();
1668 win_xform.eDx = xform.dx();
1669 win_xform.eDy = xform.dy();
1670
1671 SetGraphicsMode(hdc, GM_ADVANCED);
1672 SetWorldTransform(hdc, &win_xform);
1673#endif
1674
1675 if (fast) {
1676 // fast path
1677 QVarLengthArray<wchar_t> g(glyphs.numGlyphs);
1678 for (int i = 0; i < glyphs.numGlyphs; ++i)
1679 g[i] = glyphs.glyphs[i];
1680 ExtTextOut(hdc,
1681 qRound(baseline_pos.x() + glyphs.offsets[0].x.toReal()),
1682 qRound(baseline_pos.y() + glyphs.offsets[0].y.toReal()),
1683 options, 0, convertToText ? convertedGlyphs : g.data(), glyphs.numGlyphs, 0);
1684 } else {
1685 QVarLengthArray<QFixedPoint> positions;
1686 QVarLengthArray<glyph_t> _glyphs;
1687
1688 QTransform matrix = QTransform::fromTranslate(baseline_pos.x(), baseline_pos.y());
1689 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags,
1690 _glyphs, positions);
1691 if (_glyphs.size() == 0) {
1692 SelectObject(hdc, old_font);
1693 return;
1694 }
1695
1696 convertToText = convertToText && glyphs.numGlyphs == _glyphs.size();
1697 bool outputEntireItem = _glyphs.size() > 0;
1698
1699 if (outputEntireItem) {
1700 options |= ETO_PDY;
1701 QVarLengthArray<INT> glyphDistances(_glyphs.size() * 2);
1702 QVarLengthArray<wchar_t> g(_glyphs.size());
1703 for (int i=0; i<_glyphs.size() - 1; ++i) {
1704 glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x);
1705 glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y);
1706 g[i] = _glyphs[i];
1707 }
1708 glyphDistances[(_glyphs.size() - 1) * 2] = 0;
1709 glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0;
1710 g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1];
1711 ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0,
1712 convertToText ? convertedGlyphs : g.data(), _glyphs.size(),
1713 glyphDistances.data());
1714 } else {
1715 int i = 0;
1716 while(i < _glyphs.size()) {
1717 wchar_t g = _glyphs[i];
1718
1719 ExtTextOut(hdc, qRound(positions[i].x),
1720 qRound(positions[i].y), options, 0,
1721 convertToText ? convertedGlyphs + i : &g, 1, 0);
1722 ++i;
1723 }
1724 }
1725 }
1726
1727#if !defined(Q_OS_WINCE)
1728 win_xform.eM11 = win_xform.eM22 = 1.0;
1729 win_xform.eM12 = win_xform.eM21 = win_xform.eDx = win_xform.eDy = 0.0;
1730 SetWorldTransform(hdc, &win_xform);
1731#endif
1732
1733 SelectObject(hdc, old_font);
1734}
1735
1736
1737void QWin32PrintEnginePrivate::updateCustomPaperSize()
1738{
1739 uint paperSize = devMode->dmPaperSize;
1740 if (paperSize > 0 && mapDevmodePaperSize(paperSize) == QPrinter::Custom) {
1741 has_custom_paper_size = true;
1742 DWORD needed = 0;
1743 DWORD returned = 0;
1744 if (!EnumForms(hPrinter, 1, 0, 0, &needed, &returned)) {
1745 BYTE *forms = (BYTE *) malloc(needed);
1746 if (EnumForms(hPrinter, 1, forms, needed, &needed, &returned)) {
1747 if (paperSize <= returned) {
1748 FORM_INFO_1 *formArray = (FORM_INFO_1 *) forms;
1749 int width = formArray[paperSize - 1].Size.cx; // 1/1000 of a mm
1750 int height = formArray[paperSize - 1].Size.cy; // 1/1000 of a mm
1751 paper_size = QSizeF((width * 72 /25.4) / 1000.0, (height * 72 / 25.4) / 1000.0);
1752 } else {
1753 has_custom_paper_size = false;
1754 }
1755 }
1756 free(forms);
1757 }
1758 } else {
1759 has_custom_paper_size = false;
1760 }
1761}
1762
1763QT_END_NAMESPACE
1764
1765#endif // QT_NO_PRINTER
Note: See TracBrowser for help on using the repository browser.