Match up the specified paper size to an existing one if possible
When EnumForms was used then the dmPaperSize was not always correct for the custom paper sizes available on some printers. By using DeviceCapabilities we can be sure that the information is correct in this respect. This also fixes respecting of the custom paper size if one is given and there is no corresponding existing paper size for it. Task-number: QTBUG-34276 Change-Id: I9924d5be8527027fc434261e37f6c7aae66210c3 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
This commit is contained in:
parent
127c18ff11
commit
3396ba5612
@ -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 ®ion);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user