From 247453e7d5c84837b80444c26b1afd6165f63477 Mon Sep 17 00:00:00 2001 From: Matthias Rauter Date: Wed, 6 Mar 2024 13:17:18 +0100 Subject: Enable elements in and propagate state to mask children The use node could not be created within a mask due to a missing entry in a switch statement. This is corrected with this patch. The mask element was implemented such that states do not propagate to it's children. This is not correct and states are propagated correctly with this patch. Pick-to: 6.7 6.7.0 Fixes: QTBUG-123010 Change-Id: I4aab070c73b2e8a9bd0c642c70ea5b28eaef3416 Reviewed-by: Eirik Aavitsland --- src/svg/qsvghandler.cpp | 1 + src/svg/qsvgnode.cpp | 26 ++++++++++++++++++++++ src/svg/qsvgnode_p.h | 3 +++ src/svg/qsvgstructure.cpp | 16 ++++++------- src/svg/qsvgtinydocument.cpp | 8 +------ tests/baseline/data/bugs/maskuseandinheritance.svg | 21 +++++++++++++++++ 6 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 tests/baseline/data/bugs/maskuseandinheritance.svg diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index 99c6a4f..666865c 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -4146,6 +4146,7 @@ static QSvgNode *createUseNode(QSvgNode *parent, case QSvgNode::Defs: case QSvgNode::Group: case QSvgNode::Switch: + case QSvgNode::Mask: group = static_cast(parent); break; default: diff --git a/src/svg/qsvgnode.cpp b/src/svg/qsvgnode.cpp index deb4d71..f6b52e9 100644 --- a/src/svg/qsvgnode.cpp +++ b/src/svg/qsvgnode.cpp @@ -233,6 +233,22 @@ void QSvgNode::applyStyle(QPainter *p, QSvgExtraStates &states) const m_style.apply(p, this, states); } +/*! + \internal + + Apply the styles of all parents to the painter and the states. + The styles are applied from the top level node to the current node. + This function can be used to set the correct style for a node + if it's draw function is triggered out of the ordinary draw context, + for example the mask node, that is cross-referenced. +*/ +void QSvgNode::applyStyleRecursive(QPainter *p, QSvgExtraStates &states) const +{ + if (parent()) + parent()->applyStyleRecursive(p, states); + applyStyle(p, states); +} + void QSvgNode::revertStyle(QPainter *p, QSvgExtraStates &states) const { m_style.revert(p, states); @@ -591,6 +607,16 @@ qreal QSvgNode::strokeWidth(QPainter *p) return pen.widthF(); } +void QSvgNode::initPainter(QPainter *p) +{ + QPen pen(Qt::NoBrush, 1, Qt::SolidLine, Qt::FlatCap, Qt::SvgMiterJoin); + pen.setMiterLimit(4); + p->setPen(pen); + p->setBrush(Qt::black); + p->setRenderHint(QPainter::Antialiasing); + p->setRenderHint(QPainter::SmoothPixmapTransform); +} + bool QSvgNode::shouldDrawNode(QPainter *p, QSvgExtraStates &states) const { static bool alwaysDraw = qEnvironmentVariableIntValue("QT_SVG_DISABLE_SIZE_LIMIT"); diff --git a/src/svg/qsvgnode_p.h b/src/svg/qsvgnode_p.h index c0fa35c..f616a45 100644 --- a/src/svg/qsvgnode_p.h +++ b/src/svg/qsvgnode_p.h @@ -101,6 +101,7 @@ public: void appendStyleProperty(QSvgStyleProperty *prop, const QString &id); void applyStyle(QPainter *p, QSvgExtraStates &states) const; + void applyStyleRecursive(QPainter *p, QSvgExtraStates &states) const; void revertStyle(QPainter *p, QSvgExtraStates &states) const; QSvgStyleProperty *styleProperty(QSvgStyleProperty::Type type) const; QSvgPaintStyleProperty *styleProperty(const QString &id) const; @@ -169,6 +170,8 @@ protected: mutable QSvgStyle m_style; static qreal strokeWidth(QPainter *p); + static void initPainter(QPainter *p); + private: QSvgNode *m_parent; diff --git a/src/svg/qsvgstructure.cpp b/src/svg/qsvgstructure.cpp index 02e6b64..01fe1f5 100644 --- a/src/svg/qsvgstructure.cpp +++ b/src/svg/qsvgstructure.cpp @@ -743,17 +743,17 @@ QImage QSvgMask::createMask(QPainter *p, QSvgExtraStates &states, const QRectF & mask.fill(Qt::transparent); QPainter painter(&mask); + initPainter(&painter); - painter.setRenderHints(p->renderHints()); + QSvgExtraStates maskNodeStates; + applyStyleRecursive(&painter, maskNodeStates); + + // The transformation of the mask node is not relevant. What matters are the contentUnits + // and the position/scale of the node that the mask is applied to. + painter.resetTransform(); painter.translate(-imageBound.topLeft()); painter.setTransform(p->transform(), true); - // This is required because the QPen is scaled if contentUnits is objectBoundingBox, - // which does not match Chrome and Firefox. - painter.setPen(Qt::NoPen); - - QSvgExtraStates states2; // Fake states so scopes do not propagate - QTransform oldT = painter.transform(); if (m_contentUnits == QtSvg::UnitTypes::objectBoundingBox){ painter.translate(localRect.topLeft()); @@ -765,7 +765,7 @@ QImage QSvgMask::createMask(QPainter *p, QSvgExtraStates &states, const QRectF & while (itr != m_renderers.end()) { QSvgNode *node = *itr; if ((node->isVisible()) && (node->displayMode() != QSvgNode::NoneMode)) - node->draw(&painter, states2); + node->draw(&painter, maskNodeStates); ++itr; } diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index e45a4fd..246df7b 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -235,12 +235,7 @@ void QSvgTinyDocument::draw(QPainter *p, const QRectF &bounds) //sets default style on the painter //### not the most optimal way mapSourceToTarget(p, bounds); - QPen pen(Qt::NoBrush, 1, Qt::SolidLine, Qt::FlatCap, Qt::SvgMiterJoin); - pen.setMiterLimit(4); - p->setPen(pen); - p->setBrush(Qt::black); - p->setRenderHint(QPainter::Antialiasing); - p->setRenderHint(QPainter::SmoothPixmapTransform); + initPainter(p); QList::iterator itr = m_renderers.begin(); applyStyle(p, m_states); while (itr != m_renderers.end()) { @@ -311,7 +306,6 @@ void QSvgTinyDocument::draw(QPainter *p, const QString &id, p->restore(); } - QSvgNode::Type QSvgTinyDocument::type() const { return Doc; diff --git a/tests/baseline/data/bugs/maskuseandinheritance.svg b/tests/baseline/data/bugs/maskuseandinheritance.svg new file mode 100644 index 0000000..84df8c5 --- /dev/null +++ b/tests/baseline/data/bugs/maskuseandinheritance.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3