summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/imageformats/svg/qsvgiohandler.cpp2
-rw-r--r--src/svg/qsvggenerator.cpp68
-rw-r--r--src/svg/qsvghandler.cpp80
-rw-r--r--src/svg/qsvghandler_p.h3
-rw-r--r--src/svg/qsvgtinydocument.cpp14
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();
}