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();
|
||||
break;
|
||||
|
||||
case PdmDevicePixelRatioF_EncodedA:
|
||||
Q_FALLTHROUGH();
|
||||
case PdmDevicePixelRatioF_EncodedB:
|
||||
return QPaintDevice::encodeMetricF(metric, d->devicePixelRatio);
|
||||
break;
|
||||
|
||||
default:
|
||||
qWarning("QImage::metric(): Unhandled metric type %d", metric);
|
||||
break;
|
||||
|
@ -88,6 +88,10 @@ int QBlittablePlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) con
|
||||
return devicePixelRatio();
|
||||
case QPaintDevice::PdmDevicePixelRatioScaled:
|
||||
return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
|
||||
case QPaintDevice::PdmDevicePixelRatioF_EncodedA:
|
||||
Q_FALLTHROUGH();
|
||||
case QPaintDevice::PdmDevicePixelRatioF_EncodedB:
|
||||
return QPaintDevice::encodeMetricF(metric, devicePixelRatio());
|
||||
default:
|
||||
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
|
||||
break;
|
||||
|
@ -253,6 +253,10 @@ int QRasterPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
|
||||
return image.devicePixelRatio();
|
||||
case QPaintDevice::PdmDevicePixelRatioScaled:
|
||||
return image.devicePixelRatio() * QPaintDevice::devicePixelRatioFScale();
|
||||
case QPaintDevice::PdmDevicePixelRatioF_EncodedA:
|
||||
Q_FALLTHROUGH();
|
||||
case QPaintDevice::PdmDevicePixelRatioF_EncodedB:
|
||||
return QPaintDevice::encodeMetricF(metric, image.devicePixelRatio());
|
||||
|
||||
default:
|
||||
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
|
||||
|
@ -136,6 +136,11 @@ int QPaintDeviceWindow::metric(PaintDeviceMetric metric) const
|
||||
case PdmDevicePixelRatioScaled:
|
||||
return int(QWindow::devicePixelRatio() * devicePixelRatioFScale());
|
||||
break;
|
||||
case PdmDevicePixelRatioF_EncodedA:
|
||||
Q_FALLTHROUGH();
|
||||
case PdmDevicePixelRatioF_EncodedB:
|
||||
return QPaintDevice::encodeMetricF(metric, QWindow::devicePixelRatio());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -17,6 +17,39 @@ QPaintDevice::~QPaintDevice()
|
||||
"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
|
||||
@ -64,6 +97,8 @@ int QPaintDevice::metric(PaintDeviceMetric m) const
|
||||
return 256;
|
||||
} else if (m == PdmDevicePixelRatio) {
|
||||
return 1;
|
||||
} else if (m == PdmDevicePixelRatioF_EncodedA || m == PdmDevicePixelRatioF_EncodedB) {
|
||||
return 0;
|
||||
} else {
|
||||
qDebug("Unrecognised metric %d!",m);
|
||||
return 0;
|
||||
|
@ -29,7 +29,9 @@ public:
|
||||
PdmPhysicalDpiX,
|
||||
PdmPhysicalDpiY,
|
||||
PdmDevicePixelRatio,
|
||||
PdmDevicePixelRatioScaled
|
||||
PdmDevicePixelRatioScaled,
|
||||
PdmDevicePixelRatioF_EncodedA,
|
||||
PdmDevicePixelRatioF_EncodedB
|
||||
};
|
||||
|
||||
virtual ~QPaintDevice();
|
||||
@ -46,18 +48,20 @@ public:
|
||||
int logicalDpiY() const { return metric(PdmDpiY); }
|
||||
int physicalDpiX() const { return metric(PdmPhysicalDpiX); }
|
||||
int physicalDpiY() const { return metric(PdmPhysicalDpiY); }
|
||||
qreal devicePixelRatio() const { return metric(PdmDevicePixelRatioScaled) / devicePixelRatioFScale(); }
|
||||
qreal devicePixelRatio() const;
|
||||
qreal devicePixelRatioF() const { return devicePixelRatio(); }
|
||||
int colorCount() const { return metric(PdmNumColors); }
|
||||
int depth() const { return metric(PdmDepth); }
|
||||
|
||||
static inline qreal devicePixelRatioFScale() { return 0x10000; }
|
||||
static inline int encodeMetricF(PaintDeviceMetric metric, double value);
|
||||
protected:
|
||||
QPaintDevice() noexcept;
|
||||
virtual int metric(PaintDeviceMetric metric) const;
|
||||
virtual void initPainter(QPainter *painter) const;
|
||||
virtual QPaintDevice *redirected(QPoint *offset) const;
|
||||
virtual QPainter *sharedPainter() const;
|
||||
double getDecodedMetricF(PaintDeviceMetric metricA, PaintDeviceMetric metricB) const;
|
||||
|
||||
ushort painters; // refcount
|
||||
private:
|
||||
@ -80,6 +84,14 @@ inline int QPaintDevice::devType() const
|
||||
inline bool QPaintDevice::paintingActive() const
|
||||
{ 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
|
||||
|
||||
#endif // QPAINTDEVICE_H
|
||||
|
@ -99,6 +99,14 @@
|
||||
The constant scaling factor used is devicePixelRatioFScale(). This enum value
|
||||
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()
|
||||
*/
|
||||
|
||||
@ -288,3 +296,15 @@
|
||||
|
||||
\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;
|
||||
case PdmDevicePixelRatioScaled:
|
||||
return d_ptr->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
|
||||
case PdmDevicePixelRatioF_EncodedA:
|
||||
Q_FALLTHROUGH();
|
||||
case PdmDevicePixelRatioF_EncodedB:
|
||||
return QPaintDevice::encodeMetricF(metric, d_ptr->devicePixelRatio);
|
||||
|
||||
default:
|
||||
qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric);
|
||||
|
@ -1640,6 +1640,10 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
|
||||
return QWidget::metric(metric);
|
||||
case PdmDevicePixelRatioScaled:
|
||||
return QWidget::metric(metric);
|
||||
case PdmDevicePixelRatioF_EncodedA:
|
||||
Q_FALLTHROUGH();
|
||||
case PdmDevicePixelRatioF_EncodedB:
|
||||
return QWidget::metric(metric);
|
||||
default:
|
||||
qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);
|
||||
return 0;
|
||||
|
@ -84,10 +84,12 @@ QT_WARNING_POP
|
||||
case QPaintDevice::PdmDevicePixelRatio:
|
||||
return 1;
|
||||
case QPaintDevice::PdmDevicePixelRatioScaled:
|
||||
return qRound(devicePixelRatioFScale());
|
||||
return int(devicePixelRatioFScale());
|
||||
case QPaintDevice::PdmWidthMM:
|
||||
case QPaintDevice::PdmHeightMM:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -12956,6 +12956,10 @@ int QWidget::metric(PaintDeviceMetric m) const
|
||||
return resolveDevicePixelRatio();
|
||||
case PdmDevicePixelRatioScaled:
|
||||
return QPaintDevice::devicePixelRatioFScale() * resolveDevicePixelRatio();
|
||||
case PdmDevicePixelRatioF_EncodedA:
|
||||
Q_FALLTHROUGH();
|
||||
case PdmDevicePixelRatioF_EncodedB:
|
||||
return QPaintDevice::encodeMetricF(m, resolveDevicePixelRatio());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user