diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/imageformats/svg/qsvgiohandler.cpp | 2 | ||||
-rw-r--r-- | src/svg/qsvggenerator.cpp | 68 | ||||
-rw-r--r-- | src/svg/qsvghandler.cpp | 80 | ||||
-rw-r--r-- | src/svg/qsvghandler_p.h | 3 | ||||
-rw-r--r-- | src/svg/qsvgtinydocument.cpp | 14 |
5 files changed, 135 insertions, 32 deletions
diff --git a/src/plugins/imageformats/svg/qsvgiohandler.cpp b/src/plugins/imageformats/svg/qsvgiohandler.cpp index 88d37bc..0c26cb5 100644 --- a/src/plugins/imageformats/svg/qsvgiohandler.cpp +++ b/src/plugins/imageformats/svg/qsvgiohandler.cpp @@ -98,7 +98,7 @@ bool QSvgIOHandlerPrivate::load(QIODevice *device) } if (res) { - defaultSize = QSize(r.viewBox().width(), r.viewBox().height()); + defaultSize = r.defaultSize(); loaded = true; } diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp index 5829a1a..3f4e545 100644 --- a/src/svg/qsvggenerator.cpp +++ b/src/svg/qsvggenerator.cpp @@ -52,6 +52,7 @@ #include "qtextstream.h" #include "qbuffer.h" #include "qmath.h" +#include "qbitmap.h" #include "qdebug.h" @@ -128,6 +129,9 @@ public: QString currentGradientName; int numGradients; + QStringList savedPatternBrushes; + QStringList savedPatternMasks; + struct _attributes { QString document_title; QString document_description; @@ -145,12 +149,13 @@ static inline QPaintEngine::PaintEngineFeatures svgEngineFeatures() { return QPaintEngine::PaintEngineFeatures( QPaintEngine::AllFeatures - & ~QPaintEngine::PatternBrush & ~QPaintEngine::PerspectiveTransform & ~QPaintEngine::ConicalGradientFill & ~QPaintEngine::PorterDuff); } +Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); + class QSvgPaintEngine : public QPaintEngine { Q_DECLARE_PRIVATE(QSvgPaintEngine) @@ -212,6 +217,41 @@ public: Q_ASSERT(!isActive()); d_func()->resolution = resolution; } + + QString savePatternMask(Qt::BrushStyle style) + { + QString maskId = QString(QStringLiteral("patternmask%1")).arg(style); + if (!d_func()->savedPatternMasks.contains(maskId)) { + QImage img = qt_imageForBrush(style, true); + QRegion reg(QBitmap::fromData(img.size(), img.constBits())); + QString rct(QStringLiteral("<rect x=\"%1\" y=\"%2\" width=\"%3\" height=\"%4\" />")); + QTextStream str(&d_func()->defs, QIODevice::Append); + str << "<mask id=\"" << maskId << "\" x=\"0\" y=\"0\" width=\"8\" height=\"8\" " + << "stroke=\"none\" fill=\"#ffffff\" patternUnits=\"userSpaceOnUse\" >" << endl; + for (QRect r : reg.rects()) { + str << rct.arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()) << endl; + } + str << QStringLiteral("</mask>") << endl << endl; + d_func()->savedPatternMasks.append(maskId); + } + return maskId; + } + + QString savePatternBrush(const QString &color, const QBrush &brush) + { + QString patternId = QString(QStringLiteral("fillpattern%1_")).arg(brush.style()) + color.midRef(1); + if (!d_func()->savedPatternBrushes.contains(patternId)) { + QString maskId = savePatternMask(brush.style()); + QString geo(QStringLiteral("x=\"0\" y=\"0\" width=\"8\" height=\"8\"")); + QTextStream str(&d_func()->defs, QIODevice::Append); + str << QString(QStringLiteral("<pattern id=\"%1\" %2 patternUnits=\"userSpaceOnUse\" >")).arg(patternId, geo) << endl; + str << QString(QStringLiteral("<rect %1 stroke=\"none\" fill=\"%2\" mask=\"url(#%3);\" />")).arg(geo, color, maskId) << endl; + str << QStringLiteral("</pattern>") << endl << endl; + d_func()->savedPatternBrushes.append(patternId); + } + return patternId; + } + void saveLinearGradientBrush(const QGradient *g) { QTextStream str(&d_func()->defs, QIODevice::Append); @@ -242,7 +282,7 @@ public: << QLatin1String("fx=\"") <<grad->focalPoint().x() << QLatin1String("\" ") << QLatin1String("fy=\"") <<grad->focalPoint().y() << QLatin1String("\" "); } - str << QLatin1String("xml:id=\"") <<d_func()->generateGradientName()<< QLatin1String("\">\n"); + str << QLatin1String("id=\"") <<d_func()->generateGradientName()<< QLatin1String("\">\n"); saveGradientStops(str, g); str << QLatin1String("</radialGradient>") << endl; } @@ -421,6 +461,28 @@ public: d_func()->attributes.fillOpacity = colorOpacity; } break; + case Qt::Dense1Pattern: + case Qt::Dense2Pattern: + case Qt::Dense3Pattern: + case Qt::Dense4Pattern: + case Qt::Dense5Pattern: + case Qt::Dense6Pattern: + case Qt::Dense7Pattern: + case Qt::HorPattern: + case Qt::VerPattern: + case Qt::CrossPattern: + case Qt::BDiagPattern: + case Qt::FDiagPattern: + case Qt::DiagCrossPattern: { + QString color, colorOpacity; + translate_color(sbrush.color(), &color, &colorOpacity); + QString patternId = savePatternBrush(color, sbrush); + QString patternRef = QString(QStringLiteral("url(#%1)")).arg(patternId); + stream() << "fill=\"" << patternRef << "\" fill-opacity=\"" << colorOpacity << "\" "; + d_func()->attributes.fill = patternRef; + d_func()->attributes.fillOpacity = colorOpacity; + break; + } case Qt::LinearGradientPattern: saveLinearGradientBrush(sbrush.gradient()); d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName); @@ -1062,7 +1124,7 @@ void QSvgPaintEngine::drawRects(const QRectF *rects, int rectCount) Q_D(QSvgPaintEngine); for (int i=0; i < rectCount; ++i) { - const QRectF &rect = rects[i]; + const QRectF &rect = rects[i].normalized(); *d->stream << "<rect"; if (state->pen().isCosmetic()) *d->stream << " vector-effect=\"non-scaling-stroke\""; diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index 3b1cbb8..c40091f 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -55,6 +55,7 @@ #include "qvector.h" #include "qfileinfo.h" #include "qfile.h" +#include "qdir.h" #include "qdebug.h" #include "qmath.h" #include "qnumeric.h" @@ -65,9 +66,41 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcSvgHandler, "qt.svg") + static const char *qt_inherit_text = "inherit"; #define QT_INHERIT QLatin1String(qt_inherit_text) +static QByteArray prefixMessage(const QByteArray &msg, const QXmlStreamReader *r) +{ + QByteArray result; + if (r) { + if (const QFile *file = qobject_cast<const QFile *>(r->device())) + result.append(QFile::encodeName(QDir::toNativeSeparators(file->fileName()))); + else + result.append(QByteArrayLiteral("<input>")); + result.append(':'); + result.append(QByteArray::number(r->lineNumber())); + if (const qint64 column = r->columnNumber()) { + result.append(':'); + result.append(QByteArray::number(column)); + } + result.append(QByteArrayLiteral(": ")); + } + result.append(msg); + return result; +} + +static inline QByteArray msgProblemParsing(const QString &localName, const QXmlStreamReader *r) +{ + return prefixMessage(QByteArrayLiteral("Problem parsing ") + localName.toLocal8Bit(), r); +} + +static inline QByteArray msgCouldNotResolveProperty(const QString &id, const QXmlStreamReader *r) +{ + return prefixMessage(QByteArrayLiteral("Could not resolve property: ") + id.toLocal8Bit(), r); +} + // ======== duplicated from qcolor_p static inline int qsvg_h2i(char hex) @@ -289,6 +322,8 @@ QSvgAttributes::QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHa } } } +#else + Q_UNUSED(handler); #endif // QT_NO_CSSPARSER for (int i = 0; i < xmlAttributes.count(); ++i) { @@ -397,6 +432,8 @@ QSvgAttributes::QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHa } +#ifndef QT_NO_CSSPARSER + static const char * QSvgStyleSelector_nodeString[] = { "svg", "g", @@ -419,8 +456,6 @@ static const char * QSvgStyleSelector_nodeString[] = { "video" }; -#ifndef QT_NO_CSSPARSER - class QSvgStyleSelector : public QCss::StyleSelector { public: @@ -2692,11 +2727,11 @@ static QSvgNode *createImageNode(QSvgNode *parent, filename = filename.trimmed(); if (filename.isEmpty()) { - qWarning() << "QSvgHandler: Image filename is empty"; + qCWarning(lcSvgHandler) << "QSvgHandler: Image filename is empty"; return 0; } if (nwidth <= 0 || nheight <= 0) { - qWarning() << "QSvgHandler: Width or height for" << filename << "image was not greater than 0"; + qCWarning(lcSvgHandler) << "QSvgHandler: Width or height for" << filename << "image was not greater than 0"; return 0; } @@ -2709,7 +2744,7 @@ static QSvgNode *createImageNode(QSvgNode *parent, QByteArray data = QByteArray::fromBase64(dataStr.toLatin1()); image = QImage::fromData(data); } else { - qDebug()<<"QSvgHandler::createImageNode: Unrecognized inline image format!"; + qCDebug(lcSvgHandler) << "QSvgHandler::createImageNode: Unrecognized inline image format!"; } } else image = QImage(filename); @@ -3166,7 +3201,7 @@ static QSvgNode *createSvgNode(QSvgNode *parent, QString baseProfile = attributes.value(QLatin1String("baseProfile")).toString(); #if 0 if (baseProfile.isEmpty() && baseProfile != QLatin1String("tiny")) { - qWarning("Profile is %s while we only support tiny!", + qCWarning(lcSvgHandler, "Profile is %s while we only support tiny!", qPrintable(baseProfile)); } #endif @@ -3332,7 +3367,7 @@ static QSvgNode *createUseNode(QSvgNode *parent, } } - qWarning("link %s hasn't been detected!", qPrintable(linkId)); + qCWarning(lcSvgHandler, "link %s hasn't been detected!", qPrintable(linkId)); return 0; } @@ -3619,8 +3654,10 @@ bool QSvgHandler::startElement(const QString &localName, } else if (xmlSpace == QLatin1String("default")) { m_whitespaceMode.push(QSvgText::Default); } else { - qWarning() << QString::fromLatin1("\"%1\" is an invalid value for attribute xml:space. " - "Valid values are \"preserve\" and \"default\".").arg(xmlSpace.toString()); + const QByteArray msg = '"' + xmlSpace.toString().toLocal8Bit() + + "\" is an invalid value for attribute xml:space. " + "Valid values are \"preserve\" and \"default\"."; + qCWarning(lcSvgHandler, "%s", prefixMessage(msg, xml).constData()); m_whitespaceMode.push(QSvgText::Default); } @@ -3676,13 +3713,15 @@ bool QSvgHandler::startElement(const QString &localName, if (node->type() == QSvgNode::TSPAN) { static_cast<QSvgText *>(m_nodes.top())->addTspan(static_cast<QSvgTspan *>(node)); } else { - qWarning("\'text\' or \'textArea\' element contains invalid element type."); + const QByteArray msg = QByteArrayLiteral("\'text\' or \'textArea\' element contains invalid element type."); + qCWarning(lcSvgHandler, "%s", prefixMessage(msg, xml).constData()); delete node; node = 0; } break; default: - qWarning("Could not add child element to parent element because the types are incorrect."); + const QByteArray msg = QByteArrayLiteral("Could not add child element to parent element because the types are incorrect."); + qCWarning(lcSvgHandler, "%s", prefixMessage(msg, xml).constData()); delete node; node = 0; break; @@ -3703,25 +3742,24 @@ bool QSvgHandler::startElement(const QString &localName, } } else if (ParseMethod method = findUtilFactory(localName)) { Q_ASSERT(!m_nodes.isEmpty()); - if (!method(m_nodes.top(), attributes, this)) { - qWarning("Problem parsing %s", qPrintable(localName)); - } + if (!method(m_nodes.top(), attributes, this)) + qCWarning(lcSvgHandler, "%s", msgProblemParsing(localName, xml).constData()); } else if (StyleFactoryMethod method = findStyleFactoryMethod(localName)) { QSvgStyleProperty *prop = method(m_nodes.top(), attributes, this); if (prop) { m_style = prop; m_nodes.top()->appendStyleProperty(prop, someId(attributes)); } else { - qWarning("Could not parse node: %s", qPrintable(localName)); + const QByteArray msg = QByteArrayLiteral("Could not parse node: ") + localName.toLocal8Bit(); + qCWarning(lcSvgHandler, "%s", prefixMessage(msg, xml).constData()); } } else if (StyleParseMethod method = findStyleUtilFactoryMethod(localName)) { if (m_style) { - if (!method(m_style, attributes, this)) { - qWarning("Problem parsing %s", qPrintable(localName)); - } + if (!method(m_style, attributes, this)) + qCWarning(lcSvgHandler, "%s", msgProblemParsing(localName, xml).constData()); } } else { - //qWarning()<<"Skipping unknown element!"<<namespaceURI<<"::"<<localName; + //qCWarning(lcSvgHandler) <<"Skipping unknown element!"<<namespaceURI<<"::"<<localName; m_skipNodes.push(Unknown); return true; } @@ -3780,7 +3818,7 @@ void QSvgHandler::resolveGradients(QSvgNode *node) if (style) { fill->setFillStyle(style); } else { - qWarning("Could not resolve property : %s", qPrintable(id)); + qCWarning(lcSvgHandler, "%s", msgCouldNotResolveProperty(id, xml).constData()); fill->setBrush(Qt::NoBrush); } } @@ -3792,7 +3830,7 @@ void QSvgHandler::resolveGradients(QSvgNode *node) if (style) { stroke->setStyle(style); } else { - qWarning("Could not resolve property : %s", qPrintable(id)); + qCWarning(lcSvgHandler, "%s", msgCouldNotResolveProperty(id, xml).constData()); stroke->setStroke(Qt::NoBrush); } } diff --git a/src/svg/qsvghandler_p.h b/src/svg/qsvghandler_p.h index 32dd059..2c06cb4 100644 --- a/src/svg/qsvghandler_p.h +++ b/src/svg/qsvghandler_p.h @@ -54,6 +54,7 @@ #include "QtCore/qxmlstream.h" #include "QtCore/qhash.h" #include "QtCore/qstack.h" +#include <QtCore/QLoggingCategory> #include "qsvgstyle_p.h" #include "private/qcssparser_p.h" #include "qsvggraphics_p.h" @@ -186,6 +187,8 @@ private: const bool m_ownsReader; }; +Q_DECLARE_LOGGING_CATEGORY(lcSvgHandler) + QT_END_NAMESPACE #endif // QSVGHANDLER_P_H diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index 7bb1f75..15351bd 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -104,7 +104,7 @@ QByteArray qt_inflateGZipDataFrom(QIODevice *device) // Adding 16 to the window size gives us gzip decoding if (inflateInit2(&zlibStream, MAX_WBITS + 16) != Z_OK) { - qWarning("Cannot initialize zlib, because: %s", + qCWarning(lcSvgHandler, "Cannot initialize zlib, because: %s", (zlibStream.msg != NULL ? zlibStream.msg : "Unknown error")); return QByteArray(); } @@ -137,7 +137,7 @@ QByteArray qt_inflateGZipDataFrom(QIODevice *device) case Z_STREAM_ERROR: case Z_MEM_ERROR: { inflateEnd(&zlibStream); - qWarning("Error while inflating gzip file: %s", + qCWarning(lcSvgHandler, "Error while inflating gzip file: %s", (zlibStream.msg != NULL ? zlibStream.msg : "Unknown error")); destination.chop(zlibStream.avail_out); return destination; @@ -167,8 +167,8 @@ QSvgTinyDocument * QSvgTinyDocument::load(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly)) { - qWarning("Cannot open file '%s', because: %s", - qPrintable(fileName), qPrintable(file.errorString())); + qCWarning(lcSvgHandler, "Cannot open file '%s', because: %s", + qPrintable(fileName), qPrintable(file.errorString())); return 0; } @@ -185,7 +185,7 @@ QSvgTinyDocument * QSvgTinyDocument::load(const QString &fileName) doc = handler.document(); doc->m_animationDuration = handler.animationDuration(); } else { - qWarning("Cannot read file '%s', because: %s (line %d)", + qCWarning(lcSvgHandler, "Cannot read file '%s', because: %s (line %d)", qPrintable(fileName), qPrintable(handler.errorString()), handler.lineNumber()); } return doc; @@ -261,7 +261,7 @@ void QSvgTinyDocument::draw(QPainter *p, const QString &id, QSvgNode *node = scopeNode(id); if (!node) { - qDebug("Couldn't find node %s. Skipping rendering.", qPrintable(id)); + qCDebug(lcSvgHandler, "Couldn't find node %s. Skipping rendering.", qPrintable(id)); return; } if (m_time.isNull()) { @@ -443,7 +443,7 @@ QMatrix QSvgTinyDocument::matrixForElement(const QString &id) const QSvgNode *node = scopeNode(id); if (!node) { - qDebug("Couldn't find node %s. Skipping rendering.", qPrintable(id)); + qCDebug(lcSvgHandler, "Couldn't find node %s. Skipping rendering.", qPrintable(id)); return QMatrix(); } |