From ab35f0f8b0d872bc2e963c6ef869fade71b83e3f Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Mon, 14 Sep 2009 17:50:30 +0200 Subject: Fixed gradient referencing in SVGs. An SVG element can now reference a gradient or solid-color defined anywhere in the same SVG file. Task-number: 245602 Reviewed-by: Trond --- src/svg/qsvghandler.cpp | 94 +++++++++++++++++------------------- src/svg/qsvghandler_p.h | 1 + src/svg/qsvgnode.cpp | 110 ++++++++++++++++++++----------------------- src/svg/qsvgnode_p.h | 6 +-- src/svg/qsvgstructure.cpp | 50 ++++---------------- src/svg/qsvgstructure_p.h | 3 +- src/svg/qsvgstyle.cpp | 4 +- src/svg/qsvgtinydocument.cpp | 20 ++++++++ src/svg/qsvgtinydocument_p.h | 6 +++ 9 files changed, 135 insertions(+), 159 deletions(-) diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index f287d5e..a6e4855 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -975,15 +975,7 @@ static void parseColor(QSvgNode *, static QSvgStyleProperty *styleFromUrl(QSvgNode *node, const QString &url) { - while (node && (node->type() != QSvgNode::DOC && - node->type() != QSvgNode::G && - node->type() != QSvgNode::DEFS && - node->type() != QSvgNode::SWITCH)) { - node = node->parent(); - } - if (!node) - return 0; - return static_cast(node)->scopeStyle(idFromUrl(url)); + return node ? node->styleProperty(idFromUrl(url)) : 0; } static void parseBrush(QSvgNode *node, @@ -3559,10 +3551,9 @@ void QSvgHandler::parse() case QXmlStreamReader::ProcessingInstruction: processingInstruction(xml->processingInstructionTarget().toString(), xml->processingInstructionData().toString()); break; - default: - ; } } + resolveGradients(m_doc); } bool QSvgHandler::startElement(const QString &localName, @@ -3672,7 +3663,7 @@ bool QSvgHandler::startElement(const QString &localName, QSvgStyleProperty *prop = method(m_nodes.top(), attributes, this); if (prop) { m_style = prop; - m_nodes.top()->appendStyleProperty(prop, someId(attributes), true); + m_nodes.top()->appendStyleProperty(prop, someId(attributes)); } else { qWarning("Could not parse node: %s", qPrintable(localName)); } @@ -3713,53 +3704,52 @@ bool QSvgHandler::endElement(const QStringRef &localName) if (m_inStyle && localName == QLatin1String("style")) m_inStyle = false; - if (node == Graphics) { - // Iterate through the m_renderers to resolve any unresolved gradients. - QSvgNode* curNode = static_cast(m_nodes.top()); - if (curNode->type() == QSvgNode::DOC || - curNode->type() == QSvgNode::G || - curNode->type() == QSvgNode::DEFS || - curNode->type() == QSvgNode::SWITCH) { - QSvgStructureNode* structureNode = static_cast(curNode); - QList ren = structureNode->renderers(); - QList::iterator itr = ren.begin(); - while (itr != ren.end()) { - QSvgNode *eleNode = *itr++; - QSvgFillStyle *fill = static_cast(eleNode->styleProperty(QSvgStyleProperty::FILL)); - if (fill && !(fill->isGradientResolved())) { - QString id = fill->gradientId(); - QSvgStyleProperty *style = structureNode->scopeStyle(id); - if (style) { - if (style->type() == QSvgStyleProperty::SOLID_COLOR || style->type() == QSvgStyleProperty::GRADIENT) - fill->setFillStyle(reinterpret_cast(style)); - } else { - qWarning("Could not resolve property : %s",qPrintable(id)); - fill->setBrush(QBrush(Qt::NoBrush)); - } - } - QSvgStrokeStyle *stroke = static_cast(eleNode->styleProperty(QSvgStyleProperty::STROKE)); - if (stroke && !(stroke->isGradientResolved())) { - QString id = stroke->gradientId(); - QSvgStyleProperty *style = structureNode->scopeStyle(id); - if (style) { - if (style->type() == QSvgStyleProperty::SOLID_COLOR || style->type() == QSvgStyleProperty::GRADIENT) - stroke->setStyle(reinterpret_cast(style)); - } else { - qWarning("Could not resolve property : %s",qPrintable(id)); - stroke->setStroke(QBrush(Qt::NoBrush)); - } - } - } - } + if (node == Graphics) m_nodes.pop(); - } - else if (m_style && !m_skipNodes.isEmpty() && m_skipNodes.top() != Style) m_style = 0; return true; } +void QSvgHandler::resolveGradients(QSvgNode *node) +{ + if (!node || (node->type() != QSvgNode::DOC && node->type() != QSvgNode::G + && node->type() != QSvgNode::DEFS && node->type() != QSvgNode::SWITCH)) { + return; + } + QSvgStructureNode *structureNode = static_cast(node); + + QList ren = structureNode->renderers(); + for (QList::iterator it = ren.begin(); it != ren.end(); ++it) { + QSvgFillStyle *fill = static_cast((*it)->styleProperty(QSvgStyleProperty::FILL)); + if (fill && !fill->isGradientResolved()) { + QString id = fill->gradientId(); + QSvgFillStyleProperty *style = structureNode->styleProperty(id); + if (style) { + fill->setFillStyle(style); + } else { + qWarning("Could not resolve property : %s", qPrintable(id)); + fill->setBrush(Qt::NoBrush); + } + } + + QSvgStrokeStyle *stroke = static_cast((*it)->styleProperty(QSvgStyleProperty::STROKE)); + if (stroke && !stroke->isGradientResolved()) { + QString id = stroke->gradientId(); + QSvgFillStyleProperty *style = structureNode->styleProperty(id); + if (style) { + stroke->setStyle(style); + } else { + qWarning("Could not resolve property : %s", qPrintable(id)); + stroke->setStroke(Qt::NoBrush); + } + } + + resolveGradients(*it); + } +} + bool QSvgHandler::characters(const QStringRef &str) { if (m_inStyle) { diff --git a/src/svg/qsvghandler_p.h b/src/svg/qsvghandler_p.h index aff6f1d..daf1b1c 100644 --- a/src/svg/qsvghandler_p.h +++ b/src/svg/qsvghandler_p.h @@ -172,6 +172,7 @@ private: QXmlStreamReader *const xml; QCss::Parser m_cssParser; void parse(); + void resolveGradients(QSvgNode *node); QPen m_defaultPen; /** diff --git a/src/svg/qsvgnode.cpp b/src/svg/qsvgnode.cpp index 6b8254e..2e27cd5 100644 --- a/src/svg/qsvgnode.cpp +++ b/src/svg/qsvgnode.cpp @@ -60,56 +60,57 @@ QSvgNode::~QSvgNode() } -void QSvgNode::appendStyleProperty(QSvgStyleProperty *prop, const QString &id, - bool justLink) +void QSvgNode::appendStyleProperty(QSvgStyleProperty *prop, const QString &id) { //qDebug()<<"appending "<type()<< " ("<< id <<") "<<"to "<type(); - if (!justLink) { - switch (prop->type()) { - case QSvgStyleProperty::QUALITY: - m_style.quality = static_cast(prop); - break; - case QSvgStyleProperty::FILL: - m_style.fill = static_cast(prop); - break; - case QSvgStyleProperty::VIEWPORT_FILL: - m_style.viewportFill = static_cast(prop); - break; - case QSvgStyleProperty::FONT: - m_style.font = static_cast(prop); - break; - case QSvgStyleProperty::STROKE: - m_style.stroke = static_cast(prop); - break; - case QSvgStyleProperty::SOLID_COLOR: - m_style.solidColor = static_cast(prop); - break; - case QSvgStyleProperty::GRADIENT: - m_style.gradient = static_cast(prop); - break; - case QSvgStyleProperty::TRANSFORM: - m_style.transform = static_cast(prop); - break; - case QSvgStyleProperty::ANIMATE_COLOR: - m_style.animateColor = static_cast(prop); - break; - case QSvgStyleProperty::ANIMATE_TRANSFORM: - m_style.animateTransforms.append( - static_cast(prop)); - break; - case QSvgStyleProperty::OPACITY: - m_style.opacity = static_cast(prop); - break; - case QSvgStyleProperty::COMP_OP: - m_style.compop = static_cast(prop); - break; - default: - qDebug("QSvgNode: Trying to append unknown property!"); - break; - } - } - if (!id.isEmpty()) { - m_styles.insert(id, prop); + QSvgTinyDocument *doc; + switch (prop->type()) { + case QSvgStyleProperty::QUALITY: + m_style.quality = static_cast(prop); + break; + case QSvgStyleProperty::FILL: + m_style.fill = static_cast(prop); + break; + case QSvgStyleProperty::VIEWPORT_FILL: + m_style.viewportFill = static_cast(prop); + break; + case QSvgStyleProperty::FONT: + m_style.font = static_cast(prop); + break; + case QSvgStyleProperty::STROKE: + m_style.stroke = static_cast(prop); + break; + case QSvgStyleProperty::SOLID_COLOR: + m_style.solidColor = static_cast(prop); + doc = document(); + if (doc && !id.isEmpty()) + doc->addNamedStyle(id, m_style.solidColor); + break; + case QSvgStyleProperty::GRADIENT: + m_style.gradient = static_cast(prop); + doc = document(); + if (doc && !id.isEmpty()) + doc->addNamedStyle(id, m_style.gradient); + break; + case QSvgStyleProperty::TRANSFORM: + m_style.transform = static_cast(prop); + break; + case QSvgStyleProperty::ANIMATE_COLOR: + m_style.animateColor = static_cast(prop); + break; + case QSvgStyleProperty::ANIMATE_TRANSFORM: + m_style.animateTransforms.append( + static_cast(prop)); + break; + case QSvgStyleProperty::OPACITY: + m_style.opacity = static_cast(prop); + break; + case QSvgStyleProperty::COMP_OP: + m_style.compop = static_cast(prop); + break; + default: + qDebug("QSvgNode: Trying to append unknown property!"); + break; } } @@ -185,20 +186,13 @@ QSvgStyleProperty * QSvgNode::styleProperty(QSvgStyleProperty::Type type) const return 0; } -QSvgStyleProperty * QSvgNode::styleProperty(const QString &id) const +QSvgFillStyleProperty * QSvgNode::styleProperty(const QString &id) const { QString rid = id; if (rid.startsWith(QLatin1Char('#'))) rid.remove(0, 1); - const QSvgNode *node = this; - while (node) { - QSvgStyleProperty *style = node->m_styles[rid]; - if (style) - return style; - node = node->parent(); - } - - return 0; + QSvgTinyDocument *doc = document(); + return doc ? doc->namedStyle(rid) : 0; } QRectF QSvgNode::bounds() const diff --git a/src/svg/qsvgnode_p.h b/src/svg/qsvgnode_p.h index 2831e65..1f5606a 100644 --- a/src/svg/qsvgnode_p.h +++ b/src/svg/qsvgnode_p.h @@ -117,12 +117,11 @@ public: QSvgNode *parent() const; - void appendStyleProperty(QSvgStyleProperty *prop, const QString &id, - bool justLink=false); + void appendStyleProperty(QSvgStyleProperty *prop, const QString &id); void applyStyle(QPainter *p, QSvgExtraStates &states); void revertStyle(QPainter *p, QSvgExtraStates &states); QSvgStyleProperty *styleProperty(QSvgStyleProperty::Type type) const; - QSvgStyleProperty *styleProperty(const QString &id) const; + QSvgFillStyleProperty *styleProperty(const QString &id) const; QSvgTinyDocument *document() const; @@ -162,7 +161,6 @@ protected: qreal strokeWidth() const; private: QSvgNode *m_parent; - QHash > m_styles; QStringList m_requiredFeatures; QStringList m_requiredExtensions; diff --git a/src/svg/qsvgstructure.cpp b/src/svg/qsvgstructure.cpp index 47a544f..82c800d 100644 --- a/src/svg/qsvgstructure.cpp +++ b/src/svg/qsvgstructure.cpp @@ -45,6 +45,7 @@ #include "qsvgnode_p.h" #include "qsvgstyle_p.h" +#include "qsvgtinydocument_p.h" #include "qpainter.h" #include "qlocale.h" @@ -90,35 +91,20 @@ QSvgStructureNode::QSvgStructureNode(QSvgNode *parent) QSvgNode * QSvgStructureNode::scopeNode(const QString &id) const { - const QSvgStructureNode *group = this; - while (group && group->type() != QSvgNode::DOC) { - group = static_cast(group->parent()); - } - if (group) - return group->m_scope[id]; - return 0; + QSvgTinyDocument *doc = document(); + return doc ? doc->namedNode(id) : 0; } -void QSvgStructureNode::addChild(QSvgNode *child, const QString &id, bool def) +void QSvgStructureNode::addChild(QSvgNode *child, const QString &id) { - if (!def) - m_renderers.append(child); - - if (child->type() == QSvgNode::DEFS) { - QSvgDefs *defs = - static_cast(child); - m_linkedScopes.append(defs); - } + m_renderers.append(child); if (id.isEmpty()) return; //we can't add it to scope without id - QSvgStructureNode *group = this; - while (group && group->type() != QSvgNode::DOC) { - group = static_cast(group->parent()); - } - if (group) - group->m_scope.insert(id, child); + QSvgTinyDocument *doc = document(); + if (doc) + doc->addNamedNode(id, child); } QSvgDefs::QSvgDefs(QSvgNode *parent) @@ -136,26 +122,6 @@ QSvgNode::Type QSvgDefs::type() const return DEFS; } -QSvgStyleProperty * QSvgStructureNode::scopeStyle(const QString &id) const -{ - const QSvgStructureNode *group = this; - while (group) { - QSvgStyleProperty *prop = group->styleProperty(id); - if (prop) - return prop; - QList::const_iterator itr = group->m_linkedScopes.constBegin(); - while (itr != group->m_linkedScopes.constEnd()) { - prop = (*itr)->styleProperty(id); - if (prop) - return prop; - ++itr; - } - group = static_cast(group->parent()); - } - return 0; -} - - /* Below is a lookup function based on the gperf output using the following set: diff --git a/src/svg/qsvgstructure_p.h b/src/svg/qsvgstructure_p.h index d873f54..444f885 100644 --- a/src/svg/qsvgstructure_p.h +++ b/src/svg/qsvgstructure_p.h @@ -73,8 +73,7 @@ public: QSvgStructureNode(QSvgNode *parent); ~QSvgStructureNode(); QSvgNode *scopeNode(const QString &id) const; - QSvgStyleProperty *scopeStyle(const QString &id) const; - void addChild(QSvgNode *child, const QString &id, bool def = false); + void addChild(QSvgNode *child, const QString &id); virtual QRectF bounds() const; QSvgNode *previousSiblingNode(QSvgNode *n) const; QList renderers() const { return m_renderers; } diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp index 564bf24..f834016 100644 --- a/src/svg/qsvgstyle.cpp +++ b/src/svg/qsvgstyle.cpp @@ -934,7 +934,7 @@ void QSvgGradientStyle::setStopLink(const QString &link, QSvgTinyDocument *doc) void QSvgGradientStyle::resolveStops() { if (!m_link.isEmpty() && m_doc) { - QSvgStyleProperty *prop = m_doc->scopeStyle(m_link); + QSvgStyleProperty *prop = m_doc->styleProperty(m_link); if (prop) { if (prop->type() == QSvgStyleProperty::GRADIENT) { QSvgGradientStyle *st = @@ -943,6 +943,8 @@ void QSvgGradientStyle::resolveStops() m_gradient->setStops(st->qgradient()->stops()); m_gradientStopsSet = st->gradientStopsSet(); } + } else { + qWarning("Could not resolve property : %s", qPrintable(m_link)); } m_link = QString(); } diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index 5d58f79..e2cefeb 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -350,6 +350,26 @@ QSvgFont * QSvgTinyDocument::svgFont(const QString &family) const return m_fonts[family]; } +void QSvgTinyDocument::addNamedNode(const QString &id, QSvgNode *node) +{ + m_namedNodes.insert(id, node); +} + +QSvgNode *QSvgTinyDocument::namedNode(const QString &id) const +{ + return m_namedNodes.value(id); +} + +void QSvgTinyDocument::addNamedStyle(const QString &id, QSvgFillStyleProperty *style) +{ + m_namedStyles.insert(id, style); +} + +QSvgFillStyleProperty *QSvgTinyDocument::namedStyle(const QString &id) const +{ + return m_namedStyles.value(id); +} + void QSvgTinyDocument::restartAnimation() { m_time.restart(); diff --git a/src/svg/qsvgtinydocument_p.h b/src/svg/qsvgtinydocument_p.h index bde28c7..38a1f92 100644 --- a/src/svg/qsvgtinydocument_p.h +++ b/src/svg/qsvgtinydocument_p.h @@ -108,6 +108,10 @@ public: void addSvgFont(QSvgFont *); QSvgFont *svgFont(const QString &family) const; + void addNamedNode(const QString &id, QSvgNode *node); + QSvgNode *namedNode(const QString &id) const; + void addNamedStyle(const QString &id, QSvgFillStyleProperty *style); + QSvgFillStyleProperty *namedStyle(const QString &id) const; void restartAnimation(); int currentElapsed() const; @@ -127,6 +131,8 @@ private: mutable QRectF m_viewBox; QHash > m_fonts; + QHash m_namedNodes; + QHash > m_namedStyles; QTime m_time; bool m_animated; -- cgit v0.12