From 914e25bf01e6264dd80b6f27e50b45a578a7fe89 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Mon, 13 Feb 2017 12:38:10 +0100 Subject: Add support for pattern brushes to svg generator Pattern brushes was not implemented in the svg generator. Shapes drawn with such brushes would not be included in the svg file. [ChangeLog][][QSvgGenerator] Add support for pattern brushes Task-number: QTBUG-58148 Change-Id: Ib275661c596631fea64cb250c9743a529cd7b834 Reviewed-by: Joerg Bornemann --- src/svg/qsvggenerator.cpp | 64 +++++++++++++++++++++++++- tests/auto/qsvggenerator/tst_qsvggenerator.cpp | 42 +++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp index 6af4370..de6e8d4 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("")); + QTextStream str(&d_func()->defs, QIODevice::Append); + str << "" << endl; + for (QRect r : reg.rects()) { + str << rct.arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()) << endl; + } + str << QStringLiteral("") << 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("")).arg(patternId, geo) << endl; + str << QString(QStringLiteral("")).arg(geo, color, maskId) << endl; + str << QStringLiteral("") << endl << endl; + d_func()->savedPatternBrushes.append(patternId); + } + return patternId; + } + void saveLinearGradientBrush(const QGradient *g) { QTextStream str(&d_func()->defs, QIODevice::Append); @@ -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); diff --git a/tests/auto/qsvggenerator/tst_qsvggenerator.cpp b/tests/auto/qsvggenerator/tst_qsvggenerator.cpp index 4795b55..b55b687 100644 --- a/tests/auto/qsvggenerator/tst_qsvggenerator.cpp +++ b/tests/auto/qsvggenerator/tst_qsvggenerator.cpp @@ -58,6 +58,7 @@ private slots: void fractionalFontSize(); void titleAndDescription(); void gradientInterpolation(); + void patternBrush(); }; tst_QSvgGenerator::tst_QSvgGenerator() @@ -423,5 +424,46 @@ void tst_QSvgGenerator::gradientInterpolation() QVERIFY(sqrImageDiff(image, refImage) < 2); // pixel error < 1.41 (L2-norm) } +void tst_QSvgGenerator::patternBrush() +{ + { // Pattern brush should create mask and pattern used as fill + QSvgGenerator generator; + QByteArray byteArray; + QBuffer buffer(&byteArray); + generator.setOutputDevice(&buffer); + QPainter painter(&generator); + painter.setBrush(Qt::CrossPattern); + painter.drawRect(0, 0, 100, 100); + painter.end(); + + QVERIFY(byteArray.contains("= 4); + } + +} + QTEST_MAIN(tst_QSvgGenerator) #include "tst_qsvggenerator.moc" -- cgit v1.2.1