diff options
author | Eirik Aavitsland <eirik.aavitsland@qt.io> | 2019-12-20 16:43:48 +0100 |
---|---|---|
committer | Alessandro Portale <alessandro.portale@qt.io> | 2020-01-03 15:09:44 +0100 |
commit | acb66cad2280bda20d26d08d606a66b9660b17aa (patch) | |
tree | 9dfb4ea681ab2af549f2e8941487f2279890ba08 | |
parent | 2eba1572ee49c22f4734b1fb80aa8023d60a8e70 (diff) | |
download | qtsvg-acb66cad2280bda20d26d08d606a66b9660b17aa.tar.gz |
Fix yet another viewbox scaling issue, for render to bounds
The recent introduction of keepAspectRation scaling led to wrong
output (outside bounds) in the case of an explicitly specified target
bounds rect, i.e. QSVGRenderer::render(QPainter *p, QRectF bounds).
Fix by reverting to old code path in this case, i.e. allow the user to
override the keepAspectRatio behavior by explicitly specifying target
bounds.
As a driveby, also fix the keepAspectRatio code path in case of a
target rect having non-zero x/y coordinates. Now the fix above means
that this will never happen in the code as it stands, but it may come
in handy later.
[ChangeLog][QSVGRenderer] From Qt 5.14.0, normal rendering will keep
aspect ratio implied by the viewbox. The render() methods taking an
explicit target bounds QRectF parameter can now be used to override
that behavior. They will scale the output to the bounds while ignoring
aspect ratio, as was the default rendering prior to 5.14.0.
Fixes: QTBUG-80888
Change-Id: I399b05ca50d290b8e4b01bdc47b5b6f74c890c9a
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
-rw-r--r-- | src/svg/qsvgrenderer.cpp | 8 | ||||
-rw-r--r-- | src/svg/qsvgtinydocument.cpp | 12 | ||||
-rw-r--r-- | tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 31 |
3 files changed, 41 insertions, 10 deletions
diff --git a/src/svg/qsvgrenderer.cpp b/src/svg/qsvgrenderer.cpp index d4ad373..da31a31 100644 --- a/src/svg/qsvgrenderer.cpp +++ b/src/svg/qsvgrenderer.cpp @@ -401,10 +401,10 @@ void QSvgRenderer::render(QPainter *painter, const QString &elementId, } /*! - Renders the current document, or the current frame of an animated - document, using the given \a painter on the specified \a bounds within - the painter. If the bounding rectangle is not specified - the SVG file is mapped to the whole paint device. + Renders the current document, or the current frame of an animated document, + using the given \a painter on the specified \a bounds within the painter. + If \a bounds is not empty, the output will be scaled to fill it, ignoring + any aspect ratio implied by the SVG. */ void QSvgRenderer::render(QPainter *painter, const QRectF &bounds) { diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index 56960bf..173baaa 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -420,9 +420,10 @@ void QSvgTinyDocument::mapSourceToTarget(QPainter *p, const QRectF &targetRect, source = viewBox(); if (source != target && !source.isNull()) { - if (m_implicitViewBox || !sourceRect.isNull()) { + if (m_implicitViewBox || !sourceRect.isNull() || !targetRect.isNull()) { // Code path used when no view box is set, or when an explicit source size is given which - // overrides it (which is the case when we're rendering only a specific element by id). + // overrides it (which is the case when we're rendering only a specific element by id), + // or when user has given explicit target bounds that overrides viebox aspect ratio QTransform transform; transform.scale(target.width() / source.width(), target.height() / source.height()); @@ -441,15 +442,14 @@ void QSvgTinyDocument::mapSourceToTarget(QPainter *p, const QRectF &targetRect, viewBoxSize.scale(target.width(), target.height(), Qt::KeepAspectRatio); // Center the view box in the view port - p->translate((target.width() - viewBoxSize.width()) / 2, - (target.height() - viewBoxSize.height()) / 2); + p->translate(target.x() + (target.width() - viewBoxSize.width()) / 2, + target.y() + (target.height() - viewBoxSize.height()) / 2); p->scale(viewBoxSize.width() / source.width(), viewBoxSize.height() / source.height()); // Apply the view box translation if specified. - p->translate(target.x() - source.x(), - target.y() - source.y()); + p->translate(-source.x(), -source.y()); } } } diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index 309c646..8ad74f2 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -60,6 +60,7 @@ private slots: void testMapViewBoxToTarget(); void testRenderElement(); void testRenderElementToBounds(); + void testRenderDocumentWithSizeToBounds(); void constructorQXmlStreamReader() const; void loadQXmlStreamReader() const; void nestedQXmlStreamReader() const; @@ -372,6 +373,36 @@ void tst_QSvgRenderer::testRenderElementToBounds() QCOMPARE(reference, rendering); } +void tst_QSvgRenderer::testRenderDocumentWithSizeToBounds() +{ + // QTBUG-80888 + QImage reference(400, 200, QImage::Format_ARGB32); + { + reference.fill(Qt::transparent); + QPainter p(&reference); + p.fillRect(100, 100, 100, 50, Qt::blue); + p.fillRect(200, 50, 100, 50, Qt::blue); + } + + QImage rendering(400, 200, QImage::Format_ARGB32); + { + const char *const src = R"src( + <svg width="20" height="80"> + <g transform="translate(-100,-100)"> + <path d="m 110,180 v -80 h 10 v 40 h -20 v 40 z" fill="blue" /> + </g> + </svg> + )src"; + const QByteArray data(src); + QSvgRenderer rend(data); + rendering.fill(Qt::transparent); + QPainter p(&rendering); + rend.render(&p, QRectF(100, 50, 200, 100)); + } + + QCOMPARE(reference, rendering); +} + void tst_QSvgRenderer::constructorQXmlStreamReader() const { const QByteArray data(src); |