diff options
author | Morten Johan Sørvig <morten.sorvig@digia.com> | 2012-11-20 11:34:52 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2012-12-01 08:33:20 +0100 |
commit | 5e61bbe586519c3d9bc636153d32e810da4e59a3 (patch) | |
tree | 67d67ef644be72ee5b3d685c9a22538d7ec1e01d /src/gui/painting | |
parent | c8dc41bacdc30026cb79d0d6c72255312084bfe3 (diff) |
Basic high-dpi "retina" support for Qt 5.
Bring Qt 5 on par with Qt 4, prepare for more comprehensive
support later on.
Introduce device independent pixels (dips), device pixels,
and devicePixelRatio. Add high-dpi support to QPainter,
QGLWidget, the cocoa platform plugin, mac and fusion styles.
Dips are similar to CSS pixels, Apple points and
Android density-independent pixels. Device pixels
are pixels in the backing store/physical pixels on screen.
devicePixelRatio is the ratio between them, which is
1.0 on standard displays and 2.0 on "retina" displays.
New API:
QImage::devicePixelRatio() and setDevicePixelRatio()
QPixmap::devicePixelRatio() and setDevicePixelRatio()
QWindow::devicePixelRatio()
QScreen::devicePixelRatio()
QGuiApplicaiton::devicePixelRatio()
Change-Id: If98c3ca9bfdf0e1bdbcf7574cd5b912c9ff63856
Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/qpaintengine_raster.cpp | 29 | ||||
-rw-r--r-- | src/gui/painting/qpaintengineex.cpp | 4 | ||||
-rw-r--r-- | src/gui/painting/qpainter.cpp | 48 | ||||
-rw-r--r-- | src/gui/painting/qpainter_p.h | 1 |
4 files changed, 65 insertions, 17 deletions
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 2841a583d5..46648fe297 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1072,9 +1072,11 @@ void QRasterPaintEnginePrivate::systemStateChanged() exDeviceRect = deviceRect; Q_Q(QRasterPaintEngine); - q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion; - q->state()->fillFlags |= QPaintEngine::DirtyClipRegion; - q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion; + if (q->state()) { + q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion; + q->state()->fillFlags |= QPaintEngine::DirtyClipRegion; + q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion; + } } void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m) @@ -2143,9 +2145,10 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img) Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); + qreal scale = img.devicePixelRatio(); - if (s->matrix.type() > QTransform::TxTranslate) { - drawImage(QRectF(p.x(), p.y(), img.width(), img.height()), + if (scale > 1.0 || s->matrix.type() > QTransform::TxTranslate) { + drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale), img, QRectF(0, 0, img.width(), img.height())); } else { @@ -2349,6 +2352,22 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe return; } } else { + // Test for optimized high-dpi case: 2x source on 2x target. (Could be generalized to nX.) + bool sourceRect2x = r.width() * 2 == sr.width() && r.height() * 2 == sr.height(); + bool scale2x = (s->matrix.m11() == qreal(2)) && (s->matrix.m22() == qreal(2)); + if (s->matrix.type() == QTransform::TxScale && sourceRect2x && scale2x) { + SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()]; + if (func) { + QPointF pt(r.x() * 2 + s->matrix.dx(), r.y() * 2 + s->matrix.dy()); + if (!clip) { + d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect()); + return; + } else if (clip->hasRectClip) { + d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect()); + return; + } + } + } SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()]; if (func && (!clip || clip->hasRectClip)) { func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 113cbd8a8e..2c41ab9ff2 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -939,12 +939,12 @@ void QPaintEngineEx::drawPolygon(const QPoint *points, int pointCount, PolygonDr void QPaintEngineEx::drawPixmap(const QPointF &pos, const QPixmap &pm) { - drawPixmap(QRectF(pos, pm.size()), pm, pm.rect()); + drawPixmap(QRectF(pos, pm.size() / pm.devicePixelRatio()), pm, pm.rect()); } void QPaintEngineEx::drawImage(const QPointF &pos, const QImage &image) { - drawImage(QRectF(pos, image.size()), image, image.rect()); + drawImage(QRectF(pos, image.size() / image.devicePixelRatio()), image, image.rect()); } void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 0cfe953e43..8ec9c1648f 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -225,6 +225,18 @@ QTransform QPainterPrivate::viewTransform() const return QTransform(); } +QTransform QPainterPrivate::hidpiScaleTransform() const +{ +#ifdef Q_OS_MAC + // Limited feature introduction for Qt 5.0.0, remove ifdef in a later release. + if (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(); +} /* \internal @@ -641,6 +653,8 @@ void QPainterPrivate::updateMatrix() else state->dirtyFlags |= QPaintEngine::DirtyTransform; + state->matrix *= hidpiScaleTransform(); + // printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF); // qDebug() << " --- using matrix" << state->matrix << redirection_offset; } @@ -1827,7 +1841,14 @@ bool QPainter::begin(QPaintDevice *pd) Q_ASSERT(d->engine->isActive()); - if (!d->state->redirectionMatrix.isIdentity()) +#ifdef Q_OS_MAC + // Limited feature introduction for Qt 5.0.0, remove ifdef in a later release. + const bool isHighDpi = (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(); Q_ASSERT(d->engine->isActive()); @@ -5092,7 +5113,8 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm) x += d->state->matrix.dx(); y += d->state->matrix.dy(); } - d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(0, 0, w, h)); + int scale = pm.devicePixelRatio(); + d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h)); } } @@ -5122,6 +5144,11 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) qreal sw = sr.width(); qreal sh = sr.height(); + // Get pixmap scale. Use it when calculating the target + // rect size from pixmap size. For example, a 2X 64x64 pixel + // pixmap should result in a 32x32 point target rect. + const qreal pmscale = pm.devicePixelRatio(); + // Sanity-check clipping if (sw <= 0) sw = pm.width() - sx; @@ -5130,9 +5157,9 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) sh = pm.height() - sy; if (w < 0) - w = sw; + w = sw / pmscale; if (h < 0) - h = sh; + h = sh / pmscale; if (sx < 0) { qreal w_ratio = sx * w/sw; @@ -5345,6 +5372,7 @@ void QPainter::drawImage(const QPointF &p, const QImage &image) int w = image.width(); int h = image.height(); + qreal scale = image.devicePixelRatio(); d->updateState(d->state); @@ -5368,8 +5396,7 @@ void QPainter::drawImage(const QPointF &p, const QImage &image) setBrush(brush); setPen(Qt::NoPen); setBrushOrigin(QPointF(0, 0)); - - drawRect(image.rect()); + drawRect(QRect(QPoint(0, 0), image.size() / scale)); restore(); return; } @@ -5380,7 +5407,7 @@ void QPainter::drawImage(const QPointF &p, const QImage &image) y += d->state->matrix.dy(); } - d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(0, 0, w, h), Qt::AutoColor); + d->engine->drawImage(QRectF(x, y, w / scale, h / scale), image, QRectF(0, 0, w, h), Qt::AutoColor); } void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, @@ -5399,6 +5426,7 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR qreal sy = sourceRect.y(); qreal sw = sourceRect.width(); qreal sh = sourceRect.height(); + qreal imageScale = image.devicePixelRatio(); // Sanity-check clipping if (sw <= 0) @@ -5408,9 +5436,9 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR sh = image.height() - sy; if (w < 0) - w = sw; + w = sw / imageScale; if (h < 0) - h = sh; + h = sh / imageScale; if (sx < 0) { qreal w_ratio = sx * w/sw; @@ -8235,7 +8263,7 @@ QTransform QPainter::combinedTransform() const qWarning("QPainter::combinedTransform: Painter not active"); return QTransform(); } - return d->state->worldMatrix * d->viewTransform(); + return d->state->worldMatrix * d->viewTransform() * d->hidpiScaleTransform(); } /*! diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 0e46cee4b5..fd5d560141 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -249,6 +249,7 @@ public: } QTransform viewTransform() const; + QTransform hidpiScaleTransform() const; static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev); void detachPainterPrivate(QPainter *q); |