diff options
-rw-r--r-- | src/svg/qsvgtinydocument.cpp | 14 | ||||
-rw-r--r-- | tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 39 | ||||
-rw-r--r-- | tests/libfuzzer/svg/qsvgrenderer/render/main.cpp | 2 |
3 files changed, 46 insertions, 9 deletions
diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index 3143ad2..56960bf 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -338,7 +338,7 @@ void QSvgTinyDocument::setHeight(int len, bool percent) void QSvgTinyDocument::setViewBox(const QRectF &rect) { m_viewBox = rect; - m_implicitViewBox = false; + m_implicitViewBox = rect.isNull(); } void QSvgTinyDocument::addSvgFont(QSvgFont *font) @@ -420,7 +420,9 @@ void QSvgTinyDocument::mapSourceToTarget(QPainter *p, const QRectF &targetRect, source = viewBox(); if (source != target && !source.isNull()) { - if (m_implicitViewBox) { + if (m_implicitViewBox || !sourceRect.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). QTransform transform; transform.scale(target.width() / source.width(), target.height() / source.height()); @@ -434,10 +436,6 @@ void QSvgTinyDocument::mapSourceToTarget(QPainter *p, const QRectF &targetRect, // but the entire document. This attempts to emulate the default values of the <preserveAspectRatio> // tag that's implicitly defined when <viewbox> is used. - // Apply the view box translation if specified. - p->translate(target.x() - source.x(), - target.y() - source.y()); - // Scale the view box into the view port (target) by preserve the aspect ratio. QSizeF viewBoxSize = source.size(); viewBoxSize.scale(target.width(), target.height(), Qt::KeepAspectRatio); @@ -448,6 +446,10 @@ void QSvgTinyDocument::mapSourceToTarget(QPainter *p, const QRectF &targetRect, 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()); } } } diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index cf19213..309c646 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -59,6 +59,7 @@ private slots: void testStrokeWidth(); void testMapViewBoxToTarget(); void testRenderElement(); + void testRenderElementToBounds(); void constructorQXmlStreamReader() const; void loadQXmlStreamReader() const; void nestedQXmlStreamReader() const; @@ -269,14 +270,13 @@ void tst_QSvgRenderer::testMapViewBoxToTarget() } { // Viewport and viewBox specified -> scale 500x500 square to 1000x750 while preserving aspect ratio gives 750x750 - // however the box is centered at 375, 250 data = "<svg width=\"1000\" height=\"750\" viewBox=\"-250 -250 500 500\"><g><rect x=\"0\" y=\"0\" width=\"500\" height=\"500\" /></g></svg>"; QPicture picture; QPainter painter(&picture); QSvgRenderer rend(data); rend.render(&painter); painter.end(); - QCOMPARE(picture.boundingRect(), QRect(375, 250, 750, 750)); + QCOMPARE(picture.boundingRect(), QRect(500, 375, 750, 750)); } } @@ -337,6 +337,41 @@ void tst_QSvgRenderer::testRenderElement() } +void tst_QSvgRenderer::testRenderElementToBounds() +{ + // QTBUG-79933 + QImage reference(400, 200, QImage::Format_ARGB32); + { + reference.fill(Qt::transparent); + QPainter p(&reference); + p.fillRect( 0, 0, 200, 100, Qt::blue); + p.fillRect(200, 100, 200, 100, Qt::blue); + p.fillRect( 0, 0, 100, 50, Qt::red); + p.fillRect(100, 50, 100, 50, Qt::red); + p.fillRect(200, 100, 100, 50, Qt::red); + p.fillRect(300, 150, 100, 50, Qt::red); + } + + QImage rendering(400, 200, QImage::Format_ARGB32); + { + const char *const src = + "<svg viewBox=\"0 0 100 100\">" // Presence of a viewBox triggered QTBUG-79933 + "<path id=\"el1\" d=\"M 80,10 H 0 V 0 h 40 v 20 h 40 z\" fill=\"red\" />" + "<path id=\"el2\" d=\"M 90,100 V 20 h 10 V 60 H 80 v 40 z\" fill=\"blue\" />" + "</svg>"; + const QByteArray data(src); + QSvgRenderer rend(data); + rendering.fill(Qt::transparent); + QPainter p(&rendering); + rend.render(&p, "el1", QRectF( 0, 0, 200, 100)); + rend.render(&p, "el2", QRectF( 0, 0, 200, 100)); + rend.render(&p, "el1", QRectF(200, 100, 200, 100)); + rend.render(&p, "el2", QRectF(200, 100, 200, 100)); + } + + QCOMPARE(reference, rendering); +} + void tst_QSvgRenderer::constructorQXmlStreamReader() const { const QByteArray data(src); diff --git a/tests/libfuzzer/svg/qsvgrenderer/render/main.cpp b/tests/libfuzzer/svg/qsvgrenderer/render/main.cpp index 0197115..2439e52 100644 --- a/tests/libfuzzer/svg/qsvgrenderer/render/main.cpp +++ b/tests/libfuzzer/svg/qsvgrenderer/render/main.cpp @@ -36,7 +36,7 @@ extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) { static QApplication a(c, nullptr); static QImage image(377, 233, QImage::Format_RGB32); static QPainter painter(&image); - QSvgRenderer renderer(QByteArray(Data, Size)); + QSvgRenderer renderer(QByteArray::fromRawData(Data, Size)); renderer.render(&painter); return 0; } |