diff options
author | Ariya Hidayat <ariya.hidayat@nokia.com> | 2009-08-28 15:26:32 (GMT) |
---|---|---|
committer | Ariya Hidayat <ariya.hidayat@nokia.com> | 2009-08-31 09:18:11 (GMT) |
commit | 7f1d1eaeb1dbe7b0951e4b3c47b27c7dc95eb7c1 (patch) | |
tree | eb056bb24a38b7f533d7dfe51a39650a8920edbc | |
parent | 3216fe93a400980ec9d1a4eeafa1c700db56ded2 (diff) | |
download | Qt-7f1d1eaeb1dbe7b0951e4b3c47b27c7dc95eb7c1.zip Qt-7f1d1eaeb1dbe7b0951e4b3c47b27c7dc95eb7c1.tar.gz Qt-7f1d1eaeb1dbe7b0951e4b3c47b27c7dc95eb7c1.tar.bz2 |
Preemptively parse the necessary attributes in QSvgAttributes.
Previously, retrieving an attribute value requires a two-stage lookup,
first in the XML attributes and (if it is found there) in the CSS
attributes. Both look-ups requires a number of iterations and
comparisons, which have to be carried out for every value look-up.
This patch changes it so that iterations and comparisons need to be done
only once, namely at the beginning. This requires us to store several
SVG attributes needed by the parsing routine, but since they are just
QStringRefs, the increase in the heap usage is really minimal and even
not reported by Valgrind's Massif.
Also, now we don't need to hold the XML attributes anymore.
The loading of tiger.svg (tests/benchmarks/qsvgrenderer) is reduced from
101.2 millions instructions to 96.5. The biggest gain is however obvious
from the time spent in QSvgAttributes::parseStyle(QSvgNode*,
QSvgAttributes, QSvgHandler*) which goes down from 16.7 millions
instructions to 6.9 millions, i.e. 2.4x faster.
Even with the new extra overhead in the QSvgAttributes constructor,
QSvgAttributes::parseStyle(QSvgNode*, QXmlStreamAttributes,
QSvgHandler*) goes down from 23.5 millions instructions to 18.4 millions,
i.e. 1.3x faster.
Reviewed-by: Kim
-rw-r--r-- | src/svg/qsvghandler.cpp | 252 |
1 files changed, 195 insertions, 57 deletions
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index 44f5b6d..2076fff 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -77,49 +77,187 @@ double qstrtod(const char *s00, char const **se, bool *ok); static bool parsePathDataFast(const QStringRef &data, QPainterPath &path); +static inline QString someId(const QXmlStreamAttributes &attributes) +{ + QString id = attributes.value(QLatin1String("id")).toString(); + if (id.isEmpty()) + id = attributes.value(QLatin1String("xml:id")).toString(); + return id; +} + struct QSvgAttributes { QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHandler *handler); - QStringRef value(const QLatin1String &name) const; + QString id; + + QStringRef color; + QStringRef colorOpacity; + QStringRef fill; + QStringRef fillRule; + QStringRef fillOpacity; + QStringRef stroke; + QStringRef strokeDashArray; + QStringRef strokeDashOffset; + QStringRef strokeLineCap; + QStringRef strokeLineJoin; + QStringRef strokeMiterLimit; + QStringRef strokeOpacity; + QStringRef strokeWidth; + QStringRef vectorEffect; + QStringRef fontFamily; + QStringRef fontSize; + QStringRef fontStyle; + QStringRef fontWeight; + QStringRef fontVariant; + QStringRef textAnchor; + QStringRef transform; + QStringRef visibility; + QStringRef opacity; + QStringRef compOp; + QStringRef display; + QStringRef offset; + QStringRef stopColor; + QStringRef stopOpacity; - QXmlStreamAttributes m_xmlAttributes; QVector<QSvgCssAttribute> m_cssAttributes; }; QSvgAttributes::QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHandler *handler) - : m_xmlAttributes(xmlAttributes) { + id = someId(xmlAttributes); QStringRef style = xmlAttributes.value(QLatin1String("style")); - if (!style.isEmpty()) + if (!style.isEmpty()) { handler->parseCSStoXMLAttrs(style.toString(), &m_cssAttributes); -} - -QStringRef QSvgAttributes::value(const QLatin1String &name) const -{ - QStringRef v = m_xmlAttributes.value(name); - if (v.isEmpty()) { - for (int i = 0; i < m_cssAttributes.count(); ++i) { - if (m_cssAttributes.at(i).name == name) { - v = m_cssAttributes.at(i).value; - break; - } + for (int j = 0; j < m_cssAttributes.count(); ++j) { + const QSvgCssAttribute &attribute = m_cssAttributes.at(j ); + QStringRef name = attribute.name; + QStringRef value = attribute.value; + if (name == QLatin1String("color")) + color = value; + if (name == QLatin1String("color-opacity")) + colorOpacity = value; + if (name == QLatin1String("fill")) + fill = value; + if (name == QLatin1String("fill-rule")) + fillRule = value; + if (name == QLatin1String("fill-opacity")) + fillOpacity = value; + if (name == QLatin1String("stroke")) + stroke = value; + if (name == QLatin1String("stroke-dasharray")) + strokeDashArray = value; + if (name == QLatin1String("stroke-dashoffset")) + strokeDashOffset = value; + if (name == QLatin1String("stroke-linecap")) + strokeLineCap = value; + if (name == QLatin1String("stroke-linejoin")) + strokeLineJoin = value; + if (name == QLatin1String("stroke-miterlimit")) + strokeMiterLimit = value; + if (name == QLatin1String("stroke-opacity")) + strokeOpacity = value; + if (name == QLatin1String("stroke-width")) + strokeWidth = value; + if (name == QLatin1String("vector-effect")) + vectorEffect = value; + if (name == QLatin1String("font-family")) + fontFamily = value; + if (name == QLatin1String("font-size")) + fontSize = value; + if (name == QLatin1String("font-style")) + fontStyle = value; + if (name == QLatin1String("font-weight")) + fontWeight = value; + if (name == QLatin1String("font-variant")) + fontVariant = value; + if (name == QLatin1String("text-anchor")) + textAnchor = value; + if (name == QLatin1String("transform")) + transform = value; + if (name == QLatin1String("visibility")) + visibility = value; + if (name == QLatin1String("opacity")) + opacity = value; + if (name == QLatin1String("comp-op")) + compOp = value; + if (name == QLatin1String("display")) + display = value; + if (name == QLatin1String("offset")) + offset = value; + if (name == QLatin1String("stop-color")) + stopColor = value; + if (name == QLatin1String("stop-opacity")) + stopOpacity = value; } } - return v; -} -static inline QString someId(const QXmlStreamAttributes &attributes) -{ - QString id = attributes.value(QLatin1String("id")).toString(); - if (id.isEmpty()) - id = attributes.value(QLatin1String("xml:id")).toString(); - return id; -} -static inline QString someId(const QSvgAttributes &attributes) -{ return someId(attributes.m_xmlAttributes); } + for (int i = 0; i < xmlAttributes.count(); ++i) { + const QXmlStreamAttribute &attribute = xmlAttributes.at(i); + QStringRef name = attribute.qualifiedName(); + QStringRef value = attribute.value(); + if (name == QLatin1String("color")) + color = value; + if (name == QLatin1String("color-opacity")) + colorOpacity = value; + if (name == QLatin1String("fill")) + fill = value; + if (name == QLatin1String("fill-rule")) + fillRule = value; + if (name == QLatin1String("fill-opacity")) + fillOpacity = value; + if (name == QLatin1String("stroke")) + stroke = value; + if (name == QLatin1String("stroke-dasharray")) + strokeDashArray = value; + if (name == QLatin1String("stroke-dashoffset")) + strokeDashOffset = value; + if (name == QLatin1String("stroke-linecap")) + strokeLineCap = value; + if (name == QLatin1String("stroke-linejoin")) + strokeLineJoin = value; + if (name == QLatin1String("stroke-miterlimit")) + strokeMiterLimit = value; + if (name == QLatin1String("stroke-opacity")) + strokeOpacity = value; + if (name == QLatin1String("stroke-width")) + strokeWidth = value; + if (name == QLatin1String("vector-effect")) + vectorEffect = value; + if (name == QLatin1String("font-family")) + fontFamily = value; + if (name == QLatin1String("font-size")) + fontSize = value; + if (name == QLatin1String("font-style")) + fontStyle = value; + if (name == QLatin1String("font-weight")) + fontWeight = value; + if (name == QLatin1String("font-variant")) + fontVariant = value; + if (name == QLatin1String("text-anchor")) + textAnchor = value; + if (name == QLatin1String("transform")) + transform = value; + if (name == QLatin1String("visibility")) + visibility = value; + if (name == QLatin1String("opacity")) + opacity = value; + if (name == QLatin1String("comp-op")) + compOp = value; + if (name == QLatin1String("display")) + display = value; + if (name == QLatin1String("offset")) + offset = value; + if (name == QLatin1String("stop-color")) + stopColor = value; + if (name == QLatin1String("stop-opacity")) + stopOpacity = value; + } +} +static inline QString someId(const QSvgAttributes &attributes) +{ return attributes.id; } static const char * QSvgStyleSelector_nodeString[] = { "svg", @@ -602,8 +740,8 @@ static void parseColor(QSvgNode *, const QSvgAttributes &attributes, QSvgHandler *handler) { - QString colorStr = attributes.value(QLatin1String("color")).toString(); - QString opacity = attributes.value(QLatin1String("color-opacity")).toString(); + QString colorStr = attributes.color.toString(); + QString opacity = attributes.colorOpacity.toString(); QColor color; if (constructColor(colorStr, opacity, color, handler)) { handler->pushColor(color); @@ -627,9 +765,9 @@ static void parseBrush(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *handler) { - QString value = attributes.value(QLatin1String("fill")).toString(); - QString fillRule = attributes.value(QLatin1String("fill-rule")).toString(); - QString opacity = attributes.value(QLatin1String("fill-opacity")).toString(); + QString value = attributes.fill.toString(); + QString fillRule = attributes.fillRule.toString(); + QString opacity = attributes.fillOpacity.toString(); QString myId = someId(attributes); if (!value.isEmpty() || !fillRule.isEmpty() || !opacity.isEmpty()) { @@ -806,15 +944,15 @@ static void parsePen(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *handler) { - QString value = attributes.value(QLatin1String("stroke")).toString(); - QString dashArray = attributes.value(QLatin1String("stroke-dasharray")).toString(); - QString dashOffset = attributes.value(QLatin1String("stroke-dashoffset")).toString(); - QString linecap = attributes.value(QLatin1String("stroke-linecap")).toString(); - QString linejoin = attributes.value(QLatin1String("stroke-linejoin")).toString(); - QString miterlimit = attributes.value(QLatin1String("stroke-miterlimit")).toString(); - QString opacity = attributes.value(QLatin1String("stroke-opacity")).toString(); - QString width = attributes.value(QLatin1String("stroke-width")).toString(); - QString vectorEffect = attributes.value(QLatin1String("vector-effect")).toString(); + QString value = attributes.stroke.toString(); + QString dashArray = attributes.strokeDashArray.toString(); + QString dashOffset = attributes.strokeDashOffset.toString(); + QString linecap = attributes.strokeLineCap.toString(); + QString linejoin = attributes.strokeLineJoin.toString(); + QString miterlimit = attributes.strokeMiterLimit.toString(); + QString opacity = attributes.strokeOpacity.toString(); + QString width = attributes.strokeWidth.toString(); + QString vectorEffect = attributes.vectorEffect.toString(); QString myId = someId(attributes); //qDebug()<<"Node "<<node->type()<<", attrs are "<<value<<width; @@ -916,12 +1054,12 @@ static void parseFont(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *handler) { - QString family = attributes.value(QLatin1String("font-family")).toString(); - QString size = attributes.value(QLatin1String("font-size")).toString(); - QString style = attributes.value(QLatin1String("font-style")).toString(); - QString weight = attributes.value(QLatin1String("font-weight")).toString(); - QString variant = attributes.value(QLatin1String("font-variant")).toString(); - QString anchor = attributes.value(QLatin1String("text-anchor")).toString(); + QString family = attributes.fontFamily.toString(); + QString size = attributes.fontSize.toString(); + QString style = attributes.fontStyle.toString(); + QString weight = attributes.fontWeight.toString(); + QString variant = attributes.fontVariant.toString(); + QString anchor = attributes.textAnchor.toString(); if (family.isEmpty() && size.isEmpty() && style.isEmpty() && weight.isEmpty() && variant.isEmpty() && anchor.isEmpty()) return; @@ -996,7 +1134,7 @@ static void parseTransform(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *) { - QString value = attributes.value(QLatin1String("transform")).toString(); + QString value = attributes.transform.toString(); QString myId = someId(attributes); value = value.trimmed(); if (value.isEmpty()) @@ -1013,7 +1151,7 @@ static void parseVisibility(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *) { - QString value = attributes.value(QLatin1String("visibility")).toString(); + QString value = attributes.visibility.toString(); QSvgNode *parent = node->parent(); if (parent && (value.isEmpty() || value == QT_INHERIT)) @@ -1666,7 +1804,7 @@ static void parseOpacity(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *) { - const QString value = attributes.value(QLatin1String("opacity")).toString().trimmed(); + const QString value = attributes.opacity.toString().trimmed(); bool ok = false; qreal op = value.toDouble(&ok); @@ -1739,7 +1877,7 @@ static void parseCompOp(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *) { - QString value = attributes.value(QLatin1String("comp-op")).toString(); + QString value = attributes.compOp.toString(); value = value.trimmed(); if (!value.isEmpty()) { @@ -1794,7 +1932,7 @@ static void parseOthers(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *) { - QString displayStr = attributes.value(QLatin1String("display")).toString(); + QString displayStr = attributes.display.toString(); displayStr = displayStr.trimmed(); if (!displayStr.isEmpty()) { @@ -2663,8 +2801,7 @@ static bool parseStopNode(QSvgStyleProperty *parent, cssNode.ptr = &anim; QVector<QCss::Declaration> decls = handler->selector()->declarationsForNode(cssNode); - QSvgAttributes attrs(attributes, handler); - + QXmlStreamAttributes xmlAttr = attributes; for (int i = 0; i < decls.count(); ++i) { const QCss::Declaration &decl = decls.at(i); @@ -2678,14 +2815,15 @@ static bool parseStopNode(QSvgStyleProperty *parent, valueStr.prepend(QLatin1String("url(")); valueStr.append(QLatin1Char(')')); } - attrs.m_xmlAttributes.append(QString(), decl.d->property, valueStr); + xmlAttr.append(QString(), decl.d->property, valueStr); } + QSvgAttributes attrs(xmlAttr, handler); QSvgGradientStyle *style = static_cast<QSvgGradientStyle*>(parent); - QString offsetStr = attrs.value(QLatin1String("offset")).toString(); - QString colorStr = attrs.value(QLatin1String("stop-color")).toString(); - QString opacityStr = attrs.value(QLatin1String("stop-opacity")).toString(); + QString offsetStr = attrs.offset.toString(); + QString colorStr = attrs.stopColor.toString(); + QString opacityStr = attrs.stopOpacity.toString(); QColor color; bool ok = true; |