summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/printsupport/kernel/qprintengine_win.cpp128
-rw-r--r--tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp79
2 files changed, 159 insertions, 48 deletions
diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp
index acaa32304e..e2446c19b1 100644
--- a/src/printsupport/kernel/qprintengine_win.cpp
+++ b/src/printsupport/kernel/qprintengine_win.cpp
@@ -67,6 +67,8 @@ QT_BEGIN_NAMESPACE
Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
extern QPainterPath qt_regionToPath(const QRegion &region);
+Q_PRINTSUPPORT_EXPORT QSizeF qt_SizeFromUnitToMillimeter(const QSizeF &, QPrinter::Unit, double);
+Q_PRINTSUPPORT_EXPORT double qt_multiplierForUnit(QPrinter::Unit unit, int resolution);
// #define QT_DEBUG_DRAW
@@ -114,6 +116,52 @@ static const struct {
{ 0, QPrinter::Custom }
};
+// Return a list of printer paper sizes in millimeters with the corresponding dmPaperSize value
+static QList<QPair<QSizeF, int> > printerPaperSizes(const QString &printerName)
+{
+ QList<QPair<QSizeF, int> > result;
+ const wchar_t *name = reinterpret_cast<const wchar_t*>(printerName.utf16());
+ DWORD paperNameCount = DeviceCapabilities(name, NULL, DC_PAPERS, NULL, NULL);
+ if ((int)paperNameCount > 0) {
+ // If they are not equal, then there seems to be a problem with the driver
+ if (paperNameCount != DeviceCapabilities(name, NULL, DC_PAPERSIZE, NULL, NULL))
+ return result;
+ QScopedArrayPointer<wchar_t> papersNames(new wchar_t[paperNameCount]);
+ paperNameCount = DeviceCapabilities(name, NULL, DC_PAPERS, papersNames.data(), NULL);
+ result.reserve(paperNameCount);
+ QScopedArrayPointer<POINT> paperSizes(new POINT[paperNameCount]);
+ paperNameCount = DeviceCapabilities(name, NULL, DC_PAPERSIZE, (wchar_t *)paperSizes.data(), NULL);
+ for (int i=0; i <(int)paperNameCount; i++)
+ result.push_back(qMakePair(QSizeF(paperSizes[i].x / 10, paperSizes[i].y / 10), papersNames[i]));
+ }
+ return result;
+}
+
+// Find the best-matching printer paper for size in millimeters.
+static inline int findCustomPaperSize(const QSizeF &needlePt, const QString &printerName)
+{
+ const QList<QPair<QSizeF, int> > sizes = printerPaperSizes(printerName);
+ const qreal nw = needlePt.width();
+ const qreal nh = needlePt.height();
+ for (int i = 0; i < sizes.size(); ++i) {
+ if (qAbs(nw - sizes.at(i).first.width()) <= 1 && qAbs(nh - sizes.at(i).first.height()) <= 1)
+ return sizes.at(i).second;
+ }
+ return -1;
+}
+
+static inline void setDevModePaperFlags(DEVMODE *devMode, bool custom)
+{
+ if (custom) {
+ devMode->dmPaperSize = DMPAPER_USER;
+ devMode->dmFields |= DM_PAPERLENGTH | DM_PAPERWIDTH;
+ } else {
+ devMode->dmFields &= ~(DM_PAPERLENGTH | DM_PAPERWIDTH);
+ devMode->dmPaperLength = 0;
+ devMode->dmPaperWidth = 0;
+ }
+}
+
QPrinter::PaperSize mapDevmodePaperSize(int s)
{
int i = 0;
@@ -1293,6 +1341,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
break;
d->devMode->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
d->has_custom_paper_size = (QPrinter::PaperSize(value.toInt()) == QPrinter::Custom);
+ setDevModePaperFlags(d->devMode, d->has_custom_paper_size);
d->doReinit();
break;
case PPK_PaperName:
@@ -1320,9 +1369,19 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
wchar_t *papers = new wchar_t[size];
size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->name.utf16()),
NULL, DC_PAPERS, papers, NULL);
- d->has_custom_paper_size = false;
- d->devMode->dmPaperSize = papers[paperPos];
- d->doReinit();
+ QScopedArrayPointer<POINT> paperSizes(new POINT[size]);
+ DWORD paperNameCount = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->name.utf16()), NULL, DC_PAPERSIZE, (wchar_t *)paperSizes.data(), NULL);
+ if (paperNameCount == size) {
+ const double multiplier = qt_multiplierForUnit(QPrinter::Millimeter, d->resolution);
+ d->paper_size = QSizeF((paperSizes[paperPos].x / 10.0) * multiplier, (paperSizes[paperPos].y / 10.0) * multiplier);
+ // Our sizes may not match the paper name's size exactly
+ // So we treat it as custom so we know the paper size is correct
+ d->has_custom_paper_size = true;
+ d->devMode->dmPaperSize = papers[paperPos];
+ setDevModePaperFlags(d->devMode, false);
+ d->doReinit();
+ }
+
delete [] papers;
}
}
@@ -1373,6 +1432,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
break;
d->has_custom_paper_size = false;
d->devMode->dmPaperSize = value.toInt();
+ setDevModePaperFlags(d->devMode, d->has_custom_paper_size);
d->doReinit();
break;
@@ -1382,30 +1442,17 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
d->paper_size = value.toSizeF();
if (!d->devMode)
break;
- int orientation = d->devMode->dmOrientation;
- DWORD needed = 0;
- DWORD returned = 0;
- if (!EnumForms(d->hPrinter, 1, 0, 0, &needed, &returned)) {
- BYTE *forms = (BYTE *) malloc(needed);
- if (EnumForms(d->hPrinter, 1, forms, needed, &needed, &returned)) {
- for (DWORD i=0; i< returned; ++i) {
- FORM_INFO_1 *formArray = reinterpret_cast<FORM_INFO_1 *>(forms);
- // the form sizes are specified in 1000th of a mm,
- // convert the size to Points
- QSizeF size((formArray[i].Size.cx * 72/25.4)/1000.0,
- (formArray[i].Size.cy * 72/25.4)/1000.0);
- if (qAbs(d->paper_size.width() - size.width()) <= 2
- && qAbs(d->paper_size.height() - size.height()) <= 2)
- {
- d->devMode->dmPaperSize = i + 1;
- break;
- }
- }
- }
- free(forms);
+ const QSizeF sizeMM = qt_SizeFromUnitToMillimeter(d->paper_size, QPrinter::Point, d->resolution);
+ const int match = findCustomPaperSize(sizeMM, d->name);
+ setDevModePaperFlags(d->devMode, (match >= 0) ? false : true);
+ if (match >= 0) {
+ d->devMode->dmPaperSize = match;
+ if (d->devMode->dmOrientation != DMORIENT_PORTRAIT)
+ qSwap(d->paper_size.rwidth(), d->paper_size.rheight());
+ } else {
+ d->devMode->dmPaperLength = qRound(sizeMM.height() * 10.0);
+ d->devMode->dmPaperWidth = qRound(sizeMM.width() * 10.0);
}
- if (orientation != DMORIENT_PORTRAIT)
- d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
break;
}
@@ -1692,7 +1739,7 @@ QList<QPair<QString, QSizeF> > QWin32PrintEngine::supportedSizesWithNames(const
for (int i=0;i<(int)size;i++) {
wchar_t *paper = papers + (i * 64);
QString str = QString::fromWCharArray(paper, qwcsnlen(paper, 64));
- paperSizes << qMakePair(str, QSizeF(points[i].x / 10, points[i].y / 10));
+ paperSizes << qMakePair(str, QSizeF(points[i].x / 10.0, points[i].y / 10.0));
}
delete [] points;
}
@@ -1908,30 +1955,19 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h
SelectObject(hdc, old_font);
}
-
void QWin32PrintEnginePrivate::updateCustomPaperSize()
{
- uint paperSize = devMode->dmPaperSize;
+ const uint paperSize = devMode->dmPaperSize;
+ has_custom_paper_size = true;
if (paperSize > 0 && mapDevmodePaperSize(paperSize) == QPrinter::Custom) {
- has_custom_paper_size = true;
- DWORD needed = 0;
- DWORD returned = 0;
- if (!EnumForms(hPrinter, 1, 0, 0, &needed, &returned)) {
- BYTE *forms = (BYTE *) malloc(needed);
- if (EnumForms(hPrinter, 1, forms, needed, &needed, &returned)) {
- if (paperSize <= returned) {
- FORM_INFO_1 *formArray = (FORM_INFO_1 *) forms;
- int width = formArray[paperSize - 1].Size.cx; // 1/1000 of a mm
- int height = formArray[paperSize - 1].Size.cy; // 1/1000 of a mm
- paper_size = QSizeF((width * 72 /25.4) / 1000.0, (height * 72 / 25.4) / 1000.0);
- } else {
- has_custom_paper_size = false;
- }
+ const QList<QPair<QSizeF, int> > paperSizes = printerPaperSizes(name);
+ for (int i=0; i<paperSizes.size(); i++) {
+ if ((uint)paperSizes.at(i).second == paperSize) {
+ paper_size = paperSizes.at(paperSize).first;
+ has_custom_paper_size = false;
+ break;
}
- free(forms);
}
- } else {
- has_custom_paper_size = false;
}
}
diff --git a/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp b/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp
index 7251cca528..644cd33e5c 100644
--- a/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp
+++ b/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp
@@ -113,6 +113,8 @@ private slots:
void testCustomPageSizes();
void customPaperSizeAndMargins_data();
void customPaperSizeAndMargins();
+ void customPaperNameSettingBySize();
+ void customPaperNameSettingByName();
#if !defined(QT_NO_COMPLETER) && !defined(QT_NO_FILEDIALOG)
void printDialogCompleter();
#endif
@@ -967,6 +969,13 @@ void tst_QPrinter::errorReporting()
painter.end();
}
+static QByteArray msgSizeMismatch(const QSizeF &actual, const QSizeF &expected)
+{
+ QString result;
+ QDebug(&result) << "Paper size mismatch" << actual << "!=" << expected;
+ return result.toLocal8Bit();
+}
+
void tst_QPrinter::testCustomPageSizes()
{
QPrinter p;
@@ -975,12 +984,16 @@ void tst_QPrinter::testCustomPageSizes()
p.setPaperSize(customSize, QPrinter::Inch);
QSizeF paperSize = p.paperSize(QPrinter::Inch);
- QCOMPARE(paperSize, customSize);
+ // Due to the different calculations, the sizes may be off by a fraction so we have to check it manually
+ // instead of relying on QSizeF comparison
+ QVERIFY2(sqrt(pow(paperSize.width() - customSize.width(), 2.0) + pow(paperSize.height() - customSize.height(), 2.0)) < 0.01,
+ msgSizeMismatch(paperSize, customSize));
QPrinter p2(QPrinter::HighResolution);
p2.setPaperSize(customSize, QPrinter::Inch);
paperSize = p.paperSize(QPrinter::Inch);
- QCOMPARE(paperSize, customSize);
+ QVERIFY2(sqrt(pow(paperSize.width() - customSize.width(), 2.0) + pow(paperSize.height() - customSize.height(), 2.0)) < 0.01,
+ msgSizeMismatch(paperSize, customSize));
}
void tst_QPrinter::customPaperSizeAndMargins_data()
@@ -1193,6 +1206,68 @@ void tst_QPrinter::testPageMetrics()
QCOMPARE(printer.pageSizeMM(), QSizeF(widthMMf, heightMMf));
}
+void tst_QPrinter::customPaperNameSettingBySize()
+{
+#ifndef Q_OS_WIN
+ QSKIP("Currently this triggers a problem on non Windows platforms, this will be fixed separately - QTBUG-34521");
+#endif
+ QPrinter printer(QPrinter::HighResolution);
+ QPrinterInfo info(printer);
+ QList<QPair<QString, QSizeF> > sizes = info.supportedSizesWithNames();
+ if (sizes.size() == 0)
+ QSKIP("No printers installed on this machine");
+ for (int i=0; i<sizes.size(); i++) {
+ printer.setPaperSize(sizes.at(i).second, QPrinter::Millimeter);
+ QCOMPARE(sizes.at(i).second, printer.paperSize(QPrinter::Millimeter));
+ // Some printers have the same size under different names which can cause a problem for the test
+ // So we iterate up to the current position to check
+ QSizeF paperSize = sizes.at(i).second;
+ QString paperName = printer.paperName();
+ bool paperNameFound = (sizes.at(i).first == paperName);
+ if (!paperNameFound) {
+ for (int j=0; j<i; j++) {
+ if (sizes.at(j).second == paperSize && sizes.at(j).first == paperName) {
+ paperNameFound = true;
+ break;
+ }
+ }
+ }
+ // Fail with the original values
+ if (!paperNameFound)
+ QCOMPARE(sizes.at(i).first, printer.paperName());
+ }
+
+ // Check setting a custom size after setting a standard one works
+ QSizeF customSize(200, 200);
+ printer.setPaperSize(customSize, QPrinter::Millimeter);
+ QCOMPARE(printer.paperSize(QPrinter::Millimeter), customSize);
+ QCOMPARE(printer.paperSize(), QPrinter::Custom);
+
+ // Finally check setting a standard size after a custom one works
+ printer.setPaperSize(sizes.at(0).second, QPrinter::Millimeter);
+ QCOMPARE(printer.paperName(), sizes.at(0).first);
+ QCOMPARE(printer.paperSize(QPrinter::Millimeter), sizes.at(0).second);
+}
+
+void tst_QPrinter::customPaperNameSettingByName()
+{
+#ifndef Q_OS_WIN
+ QSKIP("Currently this triggers a problem on non Windows platforms, this will be fixed separately - QTBUG-34521");
+#endif
+ QPrinter printer(QPrinter::HighResolution);
+ QPrinterInfo info(printer);
+ QList<QPair<QString, QSizeF> > sizes = info.supportedSizesWithNames();
+ if (sizes.size() == 0)
+ QSKIP("No printers installed on this machine");
+ for (int i=0; i<sizes.size(); i++) {
+ printer.setPaperName(sizes.at(i).first);
+ QCOMPARE(sizes.at(i).first, printer.paperName());
+ QSizeF paperSize = printer.paperSize(QPrinter::Millimeter);
+ QVERIFY2(sqrt(pow(sizes.at(i).second.width() - paperSize.width(), 2.0) + pow(sizes.at(i).second.height() - paperSize.height(), 2.0)) < 0.01,
+ msgSizeMismatch(sizes.at(i).second, paperSize));
+ }
+}
+
#endif // QT_NO_PRINTER
QTEST_MAIN(tst_QPrinter)