Add QPaintDevice metric query to get precise fractional DPR value
For compatibility reasons, QPaintDevice needs to query subclasses for device metrics as int values. To report fractional DPR values, they have been multiplied with a large constant and divided back afterwards. However, the loss of accuracy introduced by this, though tiny, could still lead to rounding errors and painting artefacts when the values where multiplied up for large coordinates. Avoid this issue by adding a metric query that transports the full floating point value encoded as two ints. [ChangeLog][QtGui] Added new QPaintDevice metrics for querying fractional device pixel ratios with high precision. Custom paintdevice classes that support fractional DPRs are recommended to implement support for these queries in metric(). Others can ignore them. Fixes: QTBUG-124342 Change-Id: Ia6fa46e68e9fe981bdcbafb41daf080b4d1fb6d7 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
890c270b9b
commit
a5953d20e2
@ -4323,6 +4323,12 @@ int QImage::metric(PaintDeviceMetric metric) const
|
|||||||
return d->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
|
return d->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PdmDevicePixelRatioF_EncodedA:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case PdmDevicePixelRatioF_EncodedB:
|
||||||
|
return QPaintDevice::encodeMetricF(metric, d->devicePixelRatio);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qWarning("QImage::metric(): Unhandled metric type %d", metric);
|
qWarning("QImage::metric(): Unhandled metric type %d", metric);
|
||||||
break;
|
break;
|
||||||
|
@ -88,6 +88,10 @@ int QBlittablePlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) con
|
|||||||
return devicePixelRatio();
|
return devicePixelRatio();
|
||||||
case QPaintDevice::PdmDevicePixelRatioScaled:
|
case QPaintDevice::PdmDevicePixelRatioScaled:
|
||||||
return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
|
return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
|
||||||
|
case QPaintDevice::PdmDevicePixelRatioF_EncodedA:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QPaintDevice::PdmDevicePixelRatioF_EncodedB:
|
||||||
|
return QPaintDevice::encodeMetricF(metric, devicePixelRatio());
|
||||||
default:
|
default:
|
||||||
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
|
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
|
||||||
break;
|
break;
|
||||||
|
@ -253,6 +253,10 @@ int QRasterPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
|
|||||||
return image.devicePixelRatio();
|
return image.devicePixelRatio();
|
||||||
case QPaintDevice::PdmDevicePixelRatioScaled:
|
case QPaintDevice::PdmDevicePixelRatioScaled:
|
||||||
return image.devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
|
return image.devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
|
||||||
|
case QPaintDevice::PdmDevicePixelRatioF_EncodedA:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QPaintDevice::PdmDevicePixelRatioF_EncodedB:
|
||||||
|
return QPaintDevice::encodeMetricF(metric, image.devicePixelRatio());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
|
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
|
||||||
|
@ -136,6 +136,11 @@ int QPaintDeviceWindow::metric(PaintDeviceMetric metric) const
|
|||||||
case PdmDevicePixelRatioScaled:
|
case PdmDevicePixelRatioScaled:
|
||||||
return int(QWindow::devicePixelRatio() * devicePixelRatioFScale());
|
return int(QWindow::devicePixelRatio() * devicePixelRatioFScale());
|
||||||
break;
|
break;
|
||||||
|
case PdmDevicePixelRatioF_EncodedA:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case PdmDevicePixelRatioF_EncodedB:
|
||||||
|
return QPaintDevice::encodeMetricF(metric, QWindow::devicePixelRatio());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,39 @@ QPaintDevice::~QPaintDevice()
|
|||||||
"painted");
|
"painted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
// ### Qt 7: Replace this workaround mechanism: virtual devicePixelRatio() and virtual metricF()
|
||||||
|
inline double QPaintDevice::getDecodedMetricF(PaintDeviceMetric metricA, PaintDeviceMetric metricB) const
|
||||||
|
{
|
||||||
|
qint32 buf[2];
|
||||||
|
// The Encoded metric enum values come in pairs of one odd and one even value.
|
||||||
|
// We map those to the 0 and 1 indexes of buf by taking just the least significant bit.
|
||||||
|
// Same mapping here as in the encodeMetricF() function, to ensure correct order.
|
||||||
|
buf[metricA & 1] = metric(metricA);
|
||||||
|
buf[metricB & 1] = metric(metricB);
|
||||||
|
double res;
|
||||||
|
memcpy(&res, buf, sizeof(res));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal QPaintDevice::devicePixelRatio() const
|
||||||
|
{
|
||||||
|
Q_STATIC_ASSERT((PdmDevicePixelRatioF_EncodedA & 1) != (PdmDevicePixelRatioF_EncodedB & 1));
|
||||||
|
double res;
|
||||||
|
int scaledDpr = metric(PdmDevicePixelRatioScaled);
|
||||||
|
if (scaledDpr == int(devicePixelRatioFScale())) {
|
||||||
|
res = 1; // Shortcut for common case
|
||||||
|
} else if (scaledDpr == 2 * int(devicePixelRatioFScale())) {
|
||||||
|
res = 2; // Shortcut for common case
|
||||||
|
} else {
|
||||||
|
res = getDecodedMetricF(PdmDevicePixelRatioF_EncodedA, PdmDevicePixelRatioF_EncodedB);
|
||||||
|
if (res <= 0) // These metrics not implemented, fall back to PdmDevicePixelRatioScaled
|
||||||
|
res = scaledDpr / devicePixelRatioFScale();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
@ -64,6 +97,8 @@ int QPaintDevice::metric(PaintDeviceMetric m) const
|
|||||||
return 256;
|
return 256;
|
||||||
} else if (m == PdmDevicePixelRatio) {
|
} else if (m == PdmDevicePixelRatio) {
|
||||||
return 1;
|
return 1;
|
||||||
|
} else if (m == PdmDevicePixelRatioF_EncodedA || m == PdmDevicePixelRatioF_EncodedB) {
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
qDebug("Unrecognised metric %d!",m);
|
qDebug("Unrecognised metric %d!",m);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -29,7 +29,9 @@ public:
|
|||||||
PdmPhysicalDpiX,
|
PdmPhysicalDpiX,
|
||||||
PdmPhysicalDpiY,
|
PdmPhysicalDpiY,
|
||||||
PdmDevicePixelRatio,
|
PdmDevicePixelRatio,
|
||||||
PdmDevicePixelRatioScaled
|
PdmDevicePixelRatioScaled,
|
||||||
|
PdmDevicePixelRatioF_EncodedA,
|
||||||
|
PdmDevicePixelRatioF_EncodedB
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~QPaintDevice();
|
virtual ~QPaintDevice();
|
||||||
@ -46,18 +48,20 @@ 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); }
|
||||||
qreal devicePixelRatio() const { return metric(PdmDevicePixelRatioScaled) / devicePixelRatioFScale(); }
|
qreal devicePixelRatio() const;
|
||||||
qreal devicePixelRatioF() const { return devicePixelRatio(); }
|
qreal devicePixelRatioF() const { return devicePixelRatio(); }
|
||||||
int colorCount() const { return metric(PdmNumColors); }
|
int colorCount() const { return metric(PdmNumColors); }
|
||||||
int depth() const { return metric(PdmDepth); }
|
int depth() const { return metric(PdmDepth); }
|
||||||
|
|
||||||
static inline qreal devicePixelRatioFScale() { return 0x10000; }
|
static inline qreal devicePixelRatioFScale() { return 0x10000; }
|
||||||
|
static inline int encodeMetricF(PaintDeviceMetric metric, double value);
|
||||||
protected:
|
protected:
|
||||||
QPaintDevice() noexcept;
|
QPaintDevice() noexcept;
|
||||||
virtual int metric(PaintDeviceMetric metric) const;
|
virtual int metric(PaintDeviceMetric metric) const;
|
||||||
virtual void initPainter(QPainter *painter) const;
|
virtual void initPainter(QPainter *painter) const;
|
||||||
virtual QPaintDevice *redirected(QPoint *offset) const;
|
virtual QPaintDevice *redirected(QPoint *offset) const;
|
||||||
virtual QPainter *sharedPainter() const;
|
virtual QPainter *sharedPainter() const;
|
||||||
|
double getDecodedMetricF(PaintDeviceMetric metricA, PaintDeviceMetric metricB) const;
|
||||||
|
|
||||||
ushort painters; // refcount
|
ushort painters; // refcount
|
||||||
private:
|
private:
|
||||||
@ -80,6 +84,14 @@ inline int QPaintDevice::devType() const
|
|||||||
inline bool QPaintDevice::paintingActive() const
|
inline bool QPaintDevice::paintingActive() const
|
||||||
{ return painters != 0; }
|
{ return painters != 0; }
|
||||||
|
|
||||||
|
inline int QPaintDevice::encodeMetricF(PaintDeviceMetric metric, double value)
|
||||||
|
{
|
||||||
|
qint32 buf[2];
|
||||||
|
Q_STATIC_ASSERT(sizeof(buf) == sizeof(double));
|
||||||
|
memcpy(buf, &value, sizeof(buf));
|
||||||
|
return buf[metric & 1];
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // QPAINTDEVICE_H
|
#endif // QPAINTDEVICE_H
|
||||||
|
@ -99,6 +99,14 @@
|
|||||||
The constant scaling factor used is devicePixelRatioFScale(). This enum value
|
The constant scaling factor used is devicePixelRatioFScale(). This enum value
|
||||||
has been introduced in Qt 5.6.
|
has been introduced in Qt 5.6.
|
||||||
|
|
||||||
|
\value [since 6.8] PdmDevicePixelRatioF_EncodedA This enum item, together with the
|
||||||
|
corresponding \c B item, are used together for the device pixel ratio of the device, as an
|
||||||
|
encoded \c double floating point value. A QPaintDevice subclass that supports \e fractional DPR
|
||||||
|
values should implement support for these two enum items in its override of the metric()
|
||||||
|
function. The return value is expected to be the result of the encodeMetricF() function.
|
||||||
|
|
||||||
|
\value [since 6.8] PdmDevicePixelRatioF_EncodedB See PdmDevicePixelRatioF_EncodedA.
|
||||||
|
|
||||||
\sa metric(), devicePixelRatio()
|
\sa metric(), devicePixelRatio()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -288,3 +296,15 @@
|
|||||||
|
|
||||||
\since 5.6
|
\since 5.6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn int QPaintDevice::encodeMetricF(PaintDeviceMetric metric, double value)
|
||||||
|
|
||||||
|
\internal
|
||||||
|
|
||||||
|
Returns \a value encoded for the metric \a metric. Subclasses implementing metric() should use
|
||||||
|
this function to encode \value as an integer return value when the query metric specifies an
|
||||||
|
encoded floating-point value.
|
||||||
|
|
||||||
|
\since 6.8
|
||||||
|
*/
|
||||||
|
@ -247,6 +247,10 @@ int QOpenGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const
|
|||||||
return d_ptr->devicePixelRatio;
|
return d_ptr->devicePixelRatio;
|
||||||
case PdmDevicePixelRatioScaled:
|
case PdmDevicePixelRatioScaled:
|
||||||
return d_ptr->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
|
return d_ptr->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
|
||||||
|
case PdmDevicePixelRatioF_EncodedA:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case PdmDevicePixelRatioF_EncodedB:
|
||||||
|
return QPaintDevice::encodeMetricF(metric, d_ptr->devicePixelRatio);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric);
|
qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric);
|
||||||
|
@ -1640,6 +1640,10 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
|
|||||||
return QWidget::metric(metric);
|
return QWidget::metric(metric);
|
||||||
case PdmDevicePixelRatioScaled:
|
case PdmDevicePixelRatioScaled:
|
||||||
return QWidget::metric(metric);
|
return QWidget::metric(metric);
|
||||||
|
case PdmDevicePixelRatioF_EncodedA:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case PdmDevicePixelRatioF_EncodedB:
|
||||||
|
return QWidget::metric(metric);
|
||||||
default:
|
default:
|
||||||
qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);
|
qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -84,10 +84,12 @@ QT_WARNING_POP
|
|||||||
case QPaintDevice::PdmDevicePixelRatio:
|
case QPaintDevice::PdmDevicePixelRatio:
|
||||||
return 1;
|
return 1;
|
||||||
case QPaintDevice::PdmDevicePixelRatioScaled:
|
case QPaintDevice::PdmDevicePixelRatioScaled:
|
||||||
return qRound(devicePixelRatioFScale());
|
return int(devicePixelRatioFScale());
|
||||||
case QPaintDevice::PdmWidthMM:
|
case QPaintDevice::PdmWidthMM:
|
||||||
case QPaintDevice::PdmHeightMM:
|
case QPaintDevice::PdmHeightMM:
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -12956,6 +12956,10 @@ int QWidget::metric(PaintDeviceMetric m) const
|
|||||||
return resolveDevicePixelRatio();
|
return resolveDevicePixelRatio();
|
||||||
case PdmDevicePixelRatioScaled:
|
case PdmDevicePixelRatioScaled:
|
||||||
return QPaintDevice::devicePixelRatioFScale() * resolveDevicePixelRatio();
|
return QPaintDevice::devicePixelRatioFScale() * resolveDevicePixelRatio();
|
||||||
|
case PdmDevicePixelRatioF_EncodedA:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case PdmDevicePixelRatioF_EncodedB:
|
||||||
|
return QPaintDevice::encodeMetricF(m, resolveDevicePixelRatio());
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user