From fde7475bcf9c10522a8170e6eb8fb9a8fadc21cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 5 May 2009 15:36:30 +0200 Subject: Ensured correct rounding of scaled image drawing at non-integer coords. Images coordinates should simply be rounded and are not to be subject to the aliased coordinate delta. The patch also adds a tiny delta in QSpanData::setupMatrix() to ensure coordinates for fetching from source images are rounded the opposite direction of the target rectangle. This removes a lot of artifacts when trying to do border-image based drawing on non-integer coordinates. A new qps test for border-image drawing is included. Task-number: 251561 Reviewed-by: Trond --- src/gui/painting/qpaintengine_raster.cpp | 14 +++- src/gui/painting/qpainter.cpp | 63 +++++++++----- tests/arthur/common/images.qrc | 1 + tests/arthur/common/images/borderimage.png | Bin 0 -> 826 bytes tests/arthur/data/qps/borderimage.qps | 129 +++++++++++++++++++++++++++++ tests/arthur/data/qps/borderimage_qps.png | Bin 0 -> 88788 bytes 6 files changed, 182 insertions(+), 25 deletions(-) create mode 100644 tests/arthur/common/images/borderimage.png create mode 100644 tests/arthur/data/qps/borderimage.qps create mode 100644 tests/arthur/data/qps/borderimage_qps.png diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index e249b3e..788b722 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2664,7 +2664,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe QRectF rr = r; rr.translate(s->matrix.dx(), s->matrix.dy()); - fillRect_normalized(toRect_normalized(rr), &d->image_filler, d); + + const int x1 = qRound(rr.x()); + const int y1 = qRound(rr.y()); + const int x2 = qRound(rr.right()); + const int y2 = qRound(rr.bottom()); + + fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d); } } @@ -5147,7 +5153,11 @@ void QSpanData::adjustSpanMethods() void QSpanData::setupMatrix(const QTransform &matrix, int bilin) { - QTransform inv = matrix.inverted(); + QTransform delta; + // make sure we round off correctly in qdrawhelper.cpp + delta.translate(1.0 / 65536, 1.0 / 65536); + + QTransform inv = (delta * matrix).inverted(); m11 = inv.m11(); m12 = inv.m12(); m13 = inv.m13(); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 759bd7e..afc4211 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5142,6 +5142,11 @@ void QPainter::drawConvexPolygon(const QPointF *points, int pointCount) d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode); } +static inline QPointF roundInDeviceCoordinates(const QPointF &p, const QTransform &m) +{ + return m.inverted().map(QPointF(m.map(p).toPoint())); +} + /*! \fn void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source) @@ -5210,11 +5215,12 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm) || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))) { save(); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. - if (d->state->matrix.type() <= QTransform::TxTranslate) { - x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); - y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); + x = p.x(); + y = p.y(); } translate(x, y); setBackgroundMode(Qt::TransparentMode); @@ -5324,16 +5330,21 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform))) { save(); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); + x = p.x(); + y = p.y(); + } + if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) { - x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); - y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); sx = qRound(sx); sy = qRound(sy); sw = qRound(sw); sh = qRound(sh); } + translate(x, y); scale(w / sw, h / sh); setBackgroundMode(Qt::TransparentMode); @@ -5483,11 +5494,12 @@ void QPainter::drawImage(const QPointF &p, const QImage &image) || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))) { save(); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. - if (d->state->matrix.type() <= QTransform::TxTranslate) { - x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); - y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); + x = p.x(); + y = p.y(); } translate(x, y); setBackgroundMode(Qt::TransparentMode); @@ -5586,11 +5598,15 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))) { save(); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); + x = p.x(); + y = p.y(); + } + if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) { - x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); - y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); sx = qRound(sx); sy = qRound(sy); sw = qRound(sw); @@ -6333,17 +6349,18 @@ void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPo setBrush(QBrush(d->state->pen.color(), pixmap)); setPen(Qt::NoPen); - // If there is no scaling or transformation involved we have to make sure we use the + // If there is no rotation involved we have to make sure we use the // antialiased and not the aliased coordinate system by rounding the coordinates. - if (d->state->matrix.type() <= QTransform::TxTranslate) { - qreal x = qRound(r.x() + d->state->matrix.dx()) - d->state->matrix.dx(); - qreal y = qRound(r.y() + d->state->matrix.dy()) - d->state->matrix.dy(); - qreal w = qRound(r.width()); - qreal h = qRound(r.height()); - sx = qRound(sx); - sy = qRound(sy); + if (d->state->matrix.type() <= QTransform::TxScale) { + const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix); + + if (d->state->matrix.type() <= QTransform::TxTranslate) { + sx = qRound(sx); + sy = qRound(sy); + } + setBrushOrigin(QPointF(r.x()-sx, r.y()-sy)); - drawRect(QRectF(x, y, w, h)); + drawRect(QRectF(p, r.size())); } else { setBrushOrigin(QPointF(r.x()-sx, r.y()-sy)); drawRect(r); diff --git a/tests/arthur/common/images.qrc b/tests/arthur/common/images.qrc index 8e94760..060b52c 100644 --- a/tests/arthur/common/images.qrc +++ b/tests/arthur/common/images.qrc @@ -3,6 +3,7 @@ images/alpha.png images/border.png + images/borderimage.png images/dome_argb32.png images/dome_indexed.png images/dome_mono_palette.png diff --git a/tests/arthur/common/images/borderimage.png b/tests/arthur/common/images/borderimage.png new file mode 100644 index 0000000..f7f6b66 Binary files /dev/null and b/tests/arthur/common/images/borderimage.png differ diff --git a/tests/arthur/data/qps/borderimage.qps b/tests/arthur/data/qps/borderimage.qps new file mode 100644 index 0000000..747a74d --- /dev/null +++ b/tests/arthur/data/qps/borderimage.qps @@ -0,0 +1,129 @@ +image_load borderimage.png borderimage + +translate -128 -128 +begin_block draw_border + +# top +drawImage borderimage 0 0 16 16 0 0 16 16 +drawImage borderimage 16 0 36 16 16 0 32 16 +drawImage borderimage 52 0 16 16 48 0 16 16 + +# sides +drawImage borderimage 0 16 16 16 0 16 16 32 +drawImage borderimage 52 16 16 16 48 16 16 32 + +#bottom +drawImage borderimage 0 32 16 16 0 48 16 16 +drawImage borderimage 16 32 36 16 16 48 32 16 +drawImage borderimage 52 32 16 16 48 48 16 16 + +end_block draw_border + +resetMatrix + +begin_block draw_column + +translate 1 1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border +translate 0.1 64.1 +repeat_block draw_border + +end_block draw_column + +setRenderHint Antialiasing + +resetMatrix +translate 72 0 + +repeat_block draw_column + +resetMatrix +scale 1.25 1.25 +translate 144 0 + +repeat_block draw_border + +resetMatrix +scale 1.25 1.25 +translate 246 0 +rotate 30 + +repeat_block draw_border + +setRenderHint SmoothPixmapTransform + +resetMatrix +scale 1.25 1.25 +translate 144 120 + +repeat_block draw_border + +resetMatrix +scale 1.25 1.25 +translate 246 120 +rotate 30 + +repeat_block draw_border + +resetMatrix +translate 215 260 +scale 3.55 3.55 +rotate 30 + +repeat_block draw_border + +resetMatrix +setRenderHint SmoothPixmapTransform off +setRenderHint Antialiasing off + +translate 480 627 +rotate 180 +repeat_block draw_column + +resetMatrix +setRenderHint Antialiasing + +translate 552 627 +rotate 180 +repeat_block draw_column + +resetMatrix +setRenderHint Antialiasing off + +setPen red + +drawRect 0 0 70 680 +drawText 10 670 "aa off" + +drawRect 72 0 70 680 +drawText 80 670 "aa on" + +drawRect 409 0 70 680 +drawText 419 650 "rot 180" +drawText 419 670 "aa off" + +drawRect 481 0 70 680 +drawText 491 650 "rot 180" +drawText 491 670 "aa on" + +drawRect 164 0 224 124 +drawText 174 114 "smoothpixmaptransform off" + +drawRect 164 128 224 134 +drawText 174 252 "smoothpixmaptransform on" diff --git a/tests/arthur/data/qps/borderimage_qps.png b/tests/arthur/data/qps/borderimage_qps.png new file mode 100644 index 0000000..89a8eba Binary files /dev/null and b/tests/arthur/data/qps/borderimage_qps.png differ -- cgit v0.12