Add devicePixelRatio metric to QPaintDevice.

Previously QPainter computed the devicePixelRatio
based on the physical and logical dpi, and expected
that the ratio between them would be either 1x or
2x.

This was problematic for paint devices like printers
where the physical dpi can be much higher than the
logical dpi, and also for QScreen where the physical
dpi would have to be defined as a multiple of the
logical dpi.

Add QPaintDevice::PdmDevicePixelRatio and QPaintDevice::
devicePixelRatio() getter and implement it for the
QPaintDevice subclasses. Use it when calculating the
highdpi scale transform in qpainter.cpp and when scaling
the clip rect in qwidget.cpp.

Remove physical dpi scaling for QImage, QPixmap and
QOpenGLPaintDevice, reverting to the old behavior.

Change-Id: I6c97510613196d4536ff39d08e9750b8782283d4
Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
This commit is contained in:
Morten Johan Sørvig 2013-01-24 09:26:45 +01:00 committed by The Qt Project
parent 1f3a67e870
commit cea58f4b77
17 changed files with 73 additions and 26 deletions

View File

@ -4994,12 +4994,17 @@ int QImage::metric(PaintDeviceMetric metric) const
break; break;
case PdmPhysicalDpiX: case PdmPhysicalDpiX:
return qRound(d->dpmx * 0.0254 * d->devicePixelRatio); return qRound(d->dpmx * 0.0254);
break; break;
case PdmPhysicalDpiY: case PdmPhysicalDpiY:
return qRound(d->dpmy * 0.0254 * d->devicePixelRatio); return qRound(d->dpmy * 0.0254);
break; break;
case PdmDevicePixelRatio:
return d->devicePixelRatio;
break;
default: default:
qWarning("QImage::metric(): Unhandled metric type %d", metric); qWarning("QImage::metric(): Unhandled metric type %d", metric);
break; break;

View File

@ -956,6 +956,9 @@ int QPicture::metric(PaintDeviceMetric m) const
case PdmDepth: case PdmDepth:
val = 24; val = 24;
break; break;
case PdmDevicePixelRatio:
val = 1;
break;
default: default:
val = 0; val = 0;
qWarning("QPicture::metric: Invalid metric command"); qWarning("QPicture::metric: Invalid metric command");

View File

@ -120,6 +120,8 @@ int QBlittablePlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) con
case QPaintDevice::PdmDpiY: // fall-through case QPaintDevice::PdmDpiY: // fall-through
case QPaintDevice::PdmPhysicalDpiY: case QPaintDevice::PdmPhysicalDpiY:
return qt_defaultDpiY(); return qt_defaultDpiY();
case QPaintDevice::PdmDevicePixelRatio:
return 1;
default: default:
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric); qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
break; break;

View File

@ -278,11 +278,13 @@ int QRasterPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
case QPaintDevice::PdmDpiX: case QPaintDevice::PdmDpiX:
return qt_defaultDpiX(); return qt_defaultDpiX();
case QPaintDevice::PdmPhysicalDpiX: case QPaintDevice::PdmPhysicalDpiX:
return qt_defaultDpiX() * image.devicePixelRatio(); return qt_defaultDpiX();
case QPaintDevice::PdmDpiY: case QPaintDevice::PdmDpiY:
return qt_defaultDpiX(); return qt_defaultDpiX();
case QPaintDevice::PdmPhysicalDpiY: case QPaintDevice::PdmPhysicalDpiY:
return qt_defaultDpiY() * image.devicePixelRatio(); return qt_defaultDpiY();
case QPaintDevice::PdmDevicePixelRatio:
return image.devicePixelRatio();
default: default:
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric); qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
break; break;

View File

@ -282,9 +282,11 @@ int QOpenGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const
case PdmDpiY: case PdmDpiY:
return qRound(d_ptr->dpmy * 0.0254); return qRound(d_ptr->dpmy * 0.0254);
case PdmPhysicalDpiX: case PdmPhysicalDpiX:
return qRound(d_ptr->dpmx * 0.0254 * d_ptr->devicePixelRatio); return qRound(d_ptr->dpmx * 0.0254);
case PdmPhysicalDpiY: case PdmPhysicalDpiY:
return qRound(d_ptr->dpmy * 0.0254 * d_ptr->devicePixelRatio); return qRound(d_ptr->dpmy * 0.0254);
case PdmDevicePixelRatio:
return 1;
default: default:
qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric); qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric);
return 0; return 0;

View File

@ -95,6 +95,8 @@ int QPaintDevice::metric(PaintDeviceMetric m) const
} else if (m == PdmNumColors) { } else if (m == PdmNumColors) {
// FIXME: does this need to be a real value? // FIXME: does this need to be a real value?
return 256; return 256;
} else if (m == PdmDevicePixelRatio) {
return 1;
} else { } else {
qDebug("Unrecognised metric %d!",m); qDebug("Unrecognised metric %d!",m);
return 0; return 0;

View File

@ -65,7 +65,8 @@ public:
PdmDpiX, PdmDpiX,
PdmDpiY, PdmDpiY,
PdmPhysicalDpiX, PdmPhysicalDpiX,
PdmPhysicalDpiY PdmPhysicalDpiY,
PdmDevicePixelRatio
}; };
virtual ~QPaintDevice(); virtual ~QPaintDevice();
@ -82,6 +83,7 @@ public:
int logicalDpiY() const { return metric(PdmDpiY); } int logicalDpiY() const { return metric(PdmDpiY); }
int physicalDpiX() const { return metric(PdmPhysicalDpiX); } int physicalDpiX() const { return metric(PdmPhysicalDpiX); }
int physicalDpiY() const { return metric(PdmPhysicalDpiY); } int physicalDpiY() const { return metric(PdmPhysicalDpiY); }
int devicePixelRatio() const { return metric(PdmDevicePixelRatio); }
int colorCount() const { return metric(PdmNumColors); } int colorCount() const { return metric(PdmNumColors); }
int depth() const { return metric(PdmDepth); } int depth() const { return metric(PdmDepth); }

View File

@ -114,6 +114,10 @@
\value PdmPhysicalDpiY The vertical resolution of the device in \value PdmPhysicalDpiY The vertical resolution of the device in
dots per inch. See also physicalDpiY(). dots per inch. See also physicalDpiY().
\value PdmDevicePixelRatio The device pixel ratio for device. Common
values are 1 for normal-dpi displays and 2 for high-dpi "retina"
displays.
\sa metric() \sa metric()
*/ */
@ -273,3 +277,12 @@
\sa physicalDpiX(), logicalDpiY() \sa physicalDpiX(), logicalDpiY()
*/ */
/*!
\fn int QPaintDevice::devicePixelRatio() const
Returns the device pixel ratio for device.
Common values are 1 for normal-dpi displays and 2 for high-dpi
"retina" displays.
*/

View File

@ -225,17 +225,24 @@ QTransform QPainterPrivate::viewTransform() const
return QTransform(); return QTransform();
} }
int QPainterPrivate::effectiveDevicePixelRatio() const
{
// Limited feature introduction for Qt 5.0.0, remove ifdef in a later release.
#ifdef Q_OS_MAC
// Special cases for devices that does not support PdmDevicePixelRatio go here:
if (device->devType() == QInternal::Printer)
return 1;
return qMax(1, device->metric(QPaintDevice::PdmDevicePixelRatio));
#else
return 1;
#endif
}
QTransform QPainterPrivate::hidpiScaleTransform() const QTransform QPainterPrivate::hidpiScaleTransform() const
{ {
#ifdef Q_OS_MAC int devicePixelRatio = effectiveDevicePixelRatio();
// Limited feature introduction for Qt 5.0.0, remove ifdef in a later release. return QTransform::fromScale(devicePixelRatio, devicePixelRatio);
if (device->devType() == QInternal::Printer || device->physicalDpiX() == 0 || device->logicalDpiX() == 0)
return QTransform();
const qreal deviceScale = (device->physicalDpiX() / device->logicalDpiX());
if (deviceScale > 1.0)
return QTransform::fromScale(deviceScale, deviceScale);
#endif
return QTransform();
} }
/* /*
@ -1837,14 +1844,7 @@ bool QPainter::begin(QPaintDevice *pd)
Q_ASSERT(d->engine->isActive()); Q_ASSERT(d->engine->isActive());
#ifdef Q_OS_MAC if (!d->state->redirectionMatrix.isIdentity() || d->effectiveDevicePixelRatio() > 1)
// Limited feature introduction for Qt 5.0.0, remove ifdef in a later release.
const bool isHighDpi = (pd->devType() == QInternal::Printer || d->device->physicalDpiX() == 0 || d->device->logicalDpiX() == 0) ?
false : (d->device->physicalDpiX() / d->device->logicalDpiX() > 1);
#else
const bool isHighDpi = false;
#endif
if (!d->state->redirectionMatrix.isIdentity() || isHighDpi)
d->updateMatrix(); d->updateMatrix();
Q_ASSERT(d->engine->isActive()); Q_ASSERT(d->engine->isActive());

View File

@ -249,6 +249,7 @@ public:
} }
QTransform viewTransform() const; QTransform viewTransform() const;
int effectiveDevicePixelRatio() const;
QTransform hidpiScaleTransform() const; QTransform hidpiScaleTransform() const;
static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev); static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev);
void detachPainterPrivate(QPainter *q); void detachPainterPrivate(QPainter *q);

View File

@ -1455,6 +1455,9 @@ int QPdfEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
case QPaintDevice::PdmDepth: case QPaintDevice::PdmDepth:
val = 32; val = 32;
break; break;
case QPaintDevice::PdmDevicePixelRatio:
val = 1;
break;
default: default:
qWarning("QPdfWriter::metric: Invalid metric command"); qWarning("QPdfWriter::metric: Invalid metric command");
return 0; return 0;

View File

@ -1232,6 +1232,9 @@ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
case PdmPhysicalDpiY: case PdmPhysicalDpiY:
return qRound(dpmy * 0.0254); return qRound(dpmy * 0.0254);
case QPaintDevice::PdmDevicePixelRatio:
return 1;
default: default:
qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric); qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
break; break;

View File

@ -67,6 +67,8 @@ int QGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const
const QGLFormat f = format(); const QGLFormat f = format();
return f.redBufferSize() + f.greenBufferSize() + f.blueBufferSize() + f.alphaBufferSize(); return f.redBufferSize() + f.greenBufferSize() + f.blueBufferSize() + f.alphaBufferSize();
} }
case PdmDevicePixelRatio:
return 1;
default: default:
qWarning("QGLPaintDevice::metric() - metric %d not known", metric); qWarning("QGLPaintDevice::metric() - metric %d not known", metric);
return 0; return 0;

View File

@ -462,6 +462,9 @@ int QGLPixelBuffer::metric(PaintDeviceMetric metric) const
case PdmPhysicalDpiY: case PdmPhysicalDpiY:
return qRound(dpmy * 0.0254); return qRound(dpmy * 0.0254);
case QPaintDevice::PdmDevicePixelRatio:
return 1;
default: default:
qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric); qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric);
break; break;

View File

@ -364,6 +364,9 @@ int QMacPrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
case QPaintDevice::PdmDepth: case QPaintDevice::PdmDepth:
val = 24; val = 24;
break; break;
case QPaintDevice::PdmDevicePixelRatio:
val = 1;
break;
default: default:
val = 0; val = 0;
qWarning("QPrinter::metric: Invalid metric command"); qWarning("QPrinter::metric: Invalid metric command");

View File

@ -1811,9 +1811,8 @@ void QWidgetPrivate::setSystemClip(QPaintDevice *paintDevice, const QRegion &reg
// it has been tested. // it has been tested.
QPaintEngine *paintEngine = paintDevice->paintEngine(); QPaintEngine *paintEngine = paintDevice->paintEngine();
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
const qreal devicePixelRatio = (paintDevice->physicalDpiX() == 0 || paintDevice->logicalDpiX() == 0) ?
1.0 : (paintDevice->physicalDpiX() / paintDevice->logicalDpiX());
QTransform scaleTransform; QTransform scaleTransform;
const qreal devicePixelRatio = paintDevice->devicePixelRatio();
scaleTransform.scale(devicePixelRatio, devicePixelRatio); scaleTransform.scale(devicePixelRatio, devicePixelRatio);
paintEngine->d_func()->systemClip = scaleTransform.map(region); paintEngine->d_func()->systemClip = scaleTransform.map(region);
#else #else

View File

@ -836,6 +836,8 @@ int QWidget::metric(PaintDeviceMetric m) const
return qRound(screen->physicalDotsPerInchX()); return qRound(screen->physicalDotsPerInchX());
} else if (m == PdmPhysicalDpiY) { } else if (m == PdmPhysicalDpiY) {
return qRound(screen->physicalDotsPerInchY()); return qRound(screen->physicalDotsPerInchY());
} else if (m == PdmDevicePixelRatio) {
return screen->devicePixelRatio();
} else { } else {
val = QPaintDevice::metric(m);// XXX val = QPaintDevice::metric(m);// XXX
} }