aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorHatem ElKharashy <hatem.elkharashy@qt.io>2024-01-18 13:30:56 +0200
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2024-02-03 00:13:49 +0100
commit718ed149327c03bec33e8befcefaadf2033270d6 (patch)
tree1d093a5530112cb4b7305feb20436078d95f6b8d /tools
parent2462d9d8c60be46b5a929c46a5e9f5a97220b3d7 (diff)
Refactor svgtoqml tool
Move the generation part of the tool to a separate private module, which can generate either a QML file or a QQuickItem representation of an SVG File. The generator relies mainly on QtQuickShapes for rendering, in addition to using other QQuickItems. The generator in this module can be used by 'svgtoqml' tool. The plan succeeding this commit will be to add a QML module that will expose a QML component for loading an SVG file at runtime. Task-number: QTBUG-121659 Change-Id: I4014eb696a7d39f05f8b3035bdcee50d2acaf2b6 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/svgtoqml/CMakeLists.txt6
-rw-r--r--tools/svgtoqml/main.cpp56
-rw-r--r--tools/svgtoqml/qsvgloader.cpp1119
-rw-r--r--tools/svgtoqml/qsvgloader_p.h32
4 files changed, 37 insertions, 1176 deletions
diff --git a/tools/svgtoqml/CMakeLists.txt b/tools/svgtoqml/CMakeLists.txt
index 008a1641f5..9511212627 100644
--- a/tools/svgtoqml/CMakeLists.txt
+++ b/tools/svgtoqml/CMakeLists.txt
@@ -11,16 +11,12 @@ qt_internal_add_tool(${target_name}
TOOLS_TARGET Quick
SOURCES
main.cpp
- qsvgloader.cpp qsvgloader_p.h
LIBRARIES
Qt::Core
Qt::Gui
Qt::Qml
Qt::Quick
- Qt::QuickPrivate
- Qt::Svg
- Qt::SvgPrivate
- Qt::QuickShapesPrivate
+ Qt::QuickVectorGraphicsGeneratorPrivate
)
qt_internal_return_unless_building_tools()
diff --git a/tools/svgtoqml/main.cpp b/tools/svgtoqml/main.cpp
index 816f4808c0..91d55b73eb 100644
--- a/tools/svgtoqml/main.cpp
+++ b/tools/svgtoqml/main.cpp
@@ -5,18 +5,17 @@
#include <QQmlApplicationEngine>
#include <QCommandLineParser>
#include <QFile>
-#include <private/qquickrectangle_p.h>
-#include <private/qsvgtinydocument_p.h>
#include <QQuickWindow>
-
-#include "qsvgloader_p.h"
+#include <QQuickItem>
+#include <QtQuickVectorGraphicsGenerator/private/qquickitemgenerator_p.h>
+#include <QtQuickVectorGraphicsGenerator/private/qquickqmlgenerator_p.h>
+#include <QtQuickVectorGraphicsGenerator/private/qquickvectorgraphicsglobal_p.h>
#define ENABLE_GUI
int main(int argc, char *argv[])
{
#ifdef ENABLE_GUI
- qputenv("QT_QUICKSHAPES_BACKEND", "curverenderer");
QGuiApplication app(argc, argv);
#else
QCoreApplication app(argc, argv);
@@ -41,6 +40,16 @@ int main(int argc, char *argv[])
QCoreApplication::translate("main", "typename"));
parser.addOption(typeNameOption);
+ QCommandLineOption copyrightOption("copyright-statement",
+ QCoreApplication::translate("main", "Add <string> as a comment at the start of the generated file."),
+ QCoreApplication::translate("main", "string"));
+ parser.addOption(copyrightOption);
+
+ QCommandLineOption outlineModeOption("outline-stroke-mode",
+ QCoreApplication::translate("main", "Stroke the outside of the filled shape instead of "
+ "the original path. Also sets optimize-paths."));
+ parser.addOption(outlineModeOption);
+
#ifdef ENABLE_GUI
QCommandLineOption guiOption(QStringList() << "v" << "view",
QCoreApplication::translate("main", "Display the SVG in a window."));
@@ -54,22 +63,30 @@ int main(int argc, char *argv[])
const QString inFileName = args.at(0);
- auto *doc = QSvgTinyDocument::load(inFileName);
- if (!doc) {
- fprintf(stderr, "%s is not a valid SVG\n", qPrintable(inFileName));
- return 2;
- }
-
- const QString commentString = QLatin1String("Generated from SVG file %1").arg(inFileName);
+ QString commentString = QLatin1String("Generated from SVG file %1").arg(inFileName);
const auto outFileName = args.size() > 1 ? args.at(1) : QString{};
const auto typeName = parser.value(typeNameOption);
+ auto copyrightString = parser.value(copyrightOption);
- QSvgQmlWriter::GeneratorFlags flags;
+ if (!copyrightString.isEmpty()) {
+ copyrightString = copyrightString.replace("\\n", "\n");
+ commentString = copyrightString + u"\n" + commentString;
+ }
+
+ QQuickVectorGraphics::GeneratorFlags flags;
if (parser.isSet(curveRendererOption))
- flags |= QSvgQmlWriter::CurveRenderer;
+ flags |= QQuickVectorGraphics::GeneratorFlag::CurveRenderer;
if (parser.isSet(optimizeOption))
- flags |= QSvgQmlWriter::OptimizePaths;
+ flags |= QQuickVectorGraphics::GeneratorFlag::OptimizePaths;
+ if (parser.isSet(outlineModeOption))
+ flags |= (QQuickVectorGraphics::GeneratorFlag::OutlineStrokeMode
+ | QQuickVectorGraphics::GeneratorFlag::OptimizePaths);
+
+ QQuickQmlGenerator generator(inFileName, flags, outFileName);
+ generator.setShapeTypeName(typeName);
+ generator.setCommentString(commentString);
+ generator.generate();
#ifdef ENABLE_GUI
if (parser.isSet(guiOption)) {
@@ -82,16 +99,15 @@ int main(int argc, char *argv[])
QCoreApplication::exit(-1);
if (obj) {
auto *containerItem = obj->findChild<QQuickItem*>(QStringLiteral("svg_item"));
- auto *contents = QSvgQmlWriter::loadSVG(doc, outFileName, flags, typeName, containerItem, commentString);
- contents->setWidth(containerItem->implicitWidth()); // Workaround for runtime loader viewbox size logic. TODO: fix
- contents->setHeight(containerItem->implicitHeight());
+ QQuickItemGenerator generator(inFileName, flags, containerItem);
+ generator.generate();
}
});
engine.load(url);
return app.exec();
}
+#else
+ return 0;
#endif
- QSvgQmlWriter::loadSVG(doc, outFileName, flags, typeName, nullptr, commentString);
- return 0;
}
diff --git a/tools/svgtoqml/qsvgloader.cpp b/tools/svgtoqml/qsvgloader.cpp
deleted file mode 100644
index fc72fb7454..0000000000
--- a/tools/svgtoqml/qsvgloader.cpp
+++ /dev/null
@@ -1,1119 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-
-#include "qsvgloader_p.h"
-#include <private/qsvgvisitor_p.h>
-
-#include <QString>
-#include <QPainter>
-#include <QMatrix4x4>
-#include <QQuickItem>
-
-#include <private/qquickshape_p.h>
-#include <private/qquicktext_p.h>
-#include <private/qquicktranslate_p.h>
-#include <private/qquickitem_p.h>
-
-#include <private/qquickimagebase_p_p.h>
-#include <private/qquickimage_p.h>
-#include <private/qsgcurveprocessor_p.h>
-
-#include <private/qquadpath_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class RaiiStream : public QTextStream
-{
-public:
- RaiiStream() = default;
- explicit RaiiStream(QTextStream *stream): QTextStream(&output, QIODevice::ReadWrite), m_stream(stream) {}
- ~RaiiStream() {
- flush();
- if (m_stream && !output.isEmpty())
- *m_stream << output << Qt::endl;
- }
-
- RaiiStream(RaiiStream &other) = delete;
- RaiiStream &operator=(const RaiiStream &other) = delete;
- RaiiStream(RaiiStream &&other) : m_stream(std::exchange(other.m_stream, nullptr)), output(std::move(other.output)) {}
- RaiiStream &operator=(RaiiStream &&other) {
- std::swap(m_stream, other.m_stream);
- std::swap(output, other.output);
- return *this;
- }
-
-private:
- QTextStream *m_stream = nullptr;
- QByteArray output;
-};
-
-class SvgLoaderVisitor : public QSvgVisitor
-{
-public:
- SvgLoaderVisitor();
- ~SvgLoaderVisitor();
- void setShapeTypeName(const QString &name) { m_shapeTypeName = name.toLatin1(); }
- void setFlags(QSvgQmlWriter::GeneratorFlags flags) { m_flags = flags; }
- QQuickItem *loadQML(QTextStream *stream, const QSvgTinyDocument *doc, QQuickItem *svgItem);
-
-protected:
- void visitNode(const QSvgNode *) override;
-
- bool visitStructureNodeStart(const QSvgStructureNode *node) override;
- void visitStructureNodeEnd(const QSvgStructureNode *node) override;
- bool visitDefsNodeStart(const QSvgDefs *node) override;
-
- void visitTextNode(const QSvgText *node) override;
- void visitPathNode(const QSvgPath *node) override;
- void visitRectNode(const QSvgRect *node) override;
- void visitEllipseNode(const QSvgEllipse *node) override;
-
- void visitLineNode(const QSvgLine *node) override;
- void visitPolygonNode(const QSvgPolygon *node) override;
- void visitPolylineNode(const QSvgPolyline *node) override;
-
- void visitImageNode(const QSvgImage *node) override;
-
-private:
- QString indent() { return QString().fill(' ', m_indentLevel * 4);}
- RaiiStream stream() {
- RaiiStream strm(m_stream);
- strm << indent();
- return strm;
- }
-
- const char *shapeName() const { return m_shapeTypeName.isEmpty() ? "Shape" : m_shapeTypeName.constData(); }
-
- QString currentFillColor() const;
- const QGradient *currentFillGradient() const;
- QString currentStrokeColor() const;
- float currentStrokeWidth() const;
-
- void handleBaseNodeSetup(const QSvgNode *node);
- void handleBaseNode(const QSvgNode *node);
- void handleBaseNodeEnd(const QSvgNode *node);
- void handlePathNode(const QSvgNode *node, const QPainterPath &path, Qt::PenCapStyle = Qt::SquareCap);
- void outputShapePath(const QSvgNode *node, const QPainterPath &path, Qt::PenCapStyle capStyle);
- void outputGradient(const QGradient *grad, QQuickShapePath *shapePath, const QRectF &boundingRect);
-
- enum PathSelector { FillPath = 0x1, StrokePath = 0x2, FillAndStroke = 0x3 };
- void outputShapePath(const QSvgNode *node, const QPainterPath *path, const QQuadPath *quadPath, Qt::PenCapStyle capStyle,
- PathSelector pathSelector, const QRectF &boundingRect);
-
- QQuickItem *currentItem() { return m_items.top(); }
- void addCurrentItem(QQuickItem *item, const QSvgNode *node = nullptr) {
- item->setParentItem(currentItem());
- m_items.push(item);
- if (node) {
- if (!node->nodeId().isEmpty())
- item->setObjectName(node->nodeId());
- else
- item->setObjectName(node->typeName());
- }
- }
-
- int m_indentLevel = 0;
- QTextStream *m_stream = nullptr;
- QPainter m_dummyPainter;
- QImage m_dummyImage;
- QSvgExtraStates m_svgState;
- bool m_inShapeItem = false;
- QQuickShape *m_parentShapeItem = nullptr;
- QByteArray m_shapeTypeName;
-
- QStack<QQuickItem *> m_items;
-
- QQuickItem *m_loadedItem = nullptr;
- bool m_generateQML = true;
- bool m_generateItems = false;
- QSvgQmlWriter::GeneratorFlags m_flags;
-};
-
-SvgLoaderVisitor::SvgLoaderVisitor()
-{
- m_dummyImage = QImage(1, 1, QImage::Format_RGB32);
- m_dummyPainter.begin(&m_dummyImage);
- QPen noPen(Qt::NoPen);
- noPen.setBrush(Qt::NoBrush);
- m_dummyPainter.setPen(noPen);
- m_dummyPainter.setBrush(Qt::black);
-}
-
-SvgLoaderVisitor::~SvgLoaderVisitor()
-{
- m_dummyPainter.end();
-}
-
-void SvgLoaderVisitor::handlePathNode(const QSvgNode *node, const QPainterPath &path, Qt::PenCapStyle capStyle)
-{
- handleBaseNodeSetup(node);
-
- QPainterPath pathCopy = path;
- auto fillStyle = node->style().fill;
- if (fillStyle)
- pathCopy.setFillRule(fillStyle->fillRule());
- if (m_inShapeItem) {
- if (!node->style().transform.isDefault())
- qWarning() << "Skipped transform for node" << node->nodeId() << "type" << node->typeName() << "(this is not supposed to happen)";
- outputShapePath(node, pathCopy, capStyle);
- } else {
- if (m_generateItems) {
- auto *shapeItem = new QQuickShape;
- shapeItem->setPreferredRendererType(QQuickShape::CurveRenderer);
- shapeItem->setContainsMode(QQuickShape::ContainsMode::FillContains); // TODO: configurable?
- addCurrentItem(shapeItem, node);
- m_parentShapeItem = shapeItem;
- }
- m_inShapeItem = true;
- stream() << shapeName() << " {";
- handleBaseNode(node);
- m_indentLevel++;
- if (m_flags & QSvgQmlWriter::CurveRenderer)
- stream() << "preferredRendererType: Shape.CurveRenderer";
- outputShapePath(node, pathCopy, capStyle);
- //qDebug() << *node->qpath();
- m_indentLevel--;
- stream() << "}";
- if (m_generateItems)
- m_items.pop();
- m_inShapeItem = false;
- m_parentShapeItem = nullptr;
- }
- handleBaseNodeEnd(node);
-}
-
-void SvgLoaderVisitor::visitPathNode(const QSvgPath *node)
-{
- stream() << "// PATH visit " << node->nodeId() << " count: " << node->path().elementCount();
-
- handlePathNode(node, node->path());
-}
-
-void SvgLoaderVisitor::visitLineNode(const QSvgLine *node)
-{
- // TODO: proper end caps (should be flat by default?)
- QPainterPath p;
- p.moveTo(node->line().p1());
- p.lineTo(node->line().p2());
- handlePathNode(node, p, Qt::FlatCap);
-}
-
-static QPainterPath polygonToPath(const QPolygonF &poly, bool closed)
-{
- QPainterPath path;
- if (poly.isEmpty())
- return path;
- bool first = true;
- for (const auto &p : poly) {
- if (first)
- path.moveTo(p);
- else
- path.lineTo(p);
- first = false;
- }
- if (closed)
- path.closeSubpath();
- return path;
-}
-
-void SvgLoaderVisitor::visitPolygonNode(const QSvgPolygon *node)
-{
- stream() << "// POLYGON visit " << node->nodeId() << " count: " << node->polygon().count();
- QPainterPath p = polygonToPath(node->polygon(), true);
- handlePathNode(node, p);
-}
-
-void SvgLoaderVisitor::visitPolylineNode(const QSvgPolyline *node)
-{
- stream() << "// POLYLINE visit " << node->nodeId() << " count: " << node->polygon().count();
- QPainterPath p = polygonToPath(node->polygon(), false);
- handlePathNode(node, p, Qt::FlatCap);
-}
-
-void SvgLoaderVisitor::visitImageNode(const QSvgImage *node)
-{
- // TODO: this requires proper asset management.
- stream() << "// IMAGE visit " << node->nodeId() << " type: " << node->typeName() << " " << node->type();
-
- handleBaseNodeSetup(node);
- const auto &img = node->image();
- QRectF rect = node->rect();
-
- if (m_generateItems) {
- auto *imageItem = new QQuickImage;
- addCurrentItem(imageItem, node);
- auto *imagePriv = static_cast<QQuickImageBasePrivate*>(QQuickItemPrivate::get(imageItem));
- imagePriv->pix.setImage(img);
-
- imageItem->setX(rect.x());
- imageItem->setY(rect.y());
- imageItem->setWidth(rect.width());
- imageItem->setHeight(rect.height());
- }
-
- QString fn = img.hasAlphaChannel() ? QStringLiteral("svg_asset_%1.png").arg(img.cacheKey()) : QStringLiteral("svg_asset_%1.jpg").arg(img.cacheKey());
- if (m_generateQML) {
- // For now we just create a copy of the image in the current directory
- img.save(fn);
- qDebug() << "Saving copy of IMAGE" << fn;
- }
- stream() << "Image {";
- handleBaseNode(node);
- m_indentLevel++;
- stream() << "x: " << rect.x();
- stream() << "y: " << rect.y();
- stream() << "width: " << rect.width();
- stream() << "height: " << rect.height();
- stream() << "source: \"" << fn <<"\"";
-
- m_indentLevel--;
- stream() << "}";
- handleBaseNodeEnd(node);
- if (m_generateItems)
- m_items.pop();
-}
-
-void SvgLoaderVisitor::visitTextNode(const QSvgText *node)
-{
- // TODO: font/size
- // TODO: fallback to path for gradient fill
- stream() << "// TEXT visit " << node->nodeId() << " type: " << node->typeName() << " " << node->type();
- QPointF pos = node->position();
- static int counter = 0;
-
- const bool isTextArea = node->type() == QSvgNode::Textarea;
- QQuickItem *alignItem = nullptr;
- QQuickText *textItem = nullptr;
- if (!isTextArea) {
- stream() << "Item { id: textAlignItem_" << counter << "; x: " << pos.x() << "; y: " << pos.y() << "}";
- if (m_generateItems) {
- alignItem = new QQuickItem(currentItem());
- alignItem->setX(pos.x());
- alignItem->setY(pos.y());
- }
- }
- stream() << "Text {";
-
- if (m_generateItems) {
- textItem = new QQuickText;
- addCurrentItem(textItem, node);
- }
- handleBaseNodeSetup(node);
- m_indentLevel++;
-
- if (isTextArea) {
- stream() << "x: " << pos.x();
- stream() << "y: " << pos.y();
- stream() << "width: " << node->size().width();
- stream() << "height: " << node->size().height();
- stream() << "wrapMode: Text.Wrap"; // ### WordWrap? verify with SVG standard
- stream() << "clip: true"; //### Not exactly correct: should clip on the text level, not the pixel level
- if (textItem) {
- textItem->setX(pos.x());
- textItem->setY(pos.y());
- textItem->setWidth(node->size().width());
- textItem->setHeight(node->size().height());
- textItem->setWrapMode(QQuickText::Wrap);
- textItem->setClip(true);
- }
- } else {
- auto *anchors = m_generateItems ? QQuickItemPrivate::get(textItem)->anchors() : nullptr;
- auto *alignPrivate = m_generateItems ? QQuickItemPrivate::get(alignItem) : nullptr;
- if (m_generateItems)
- anchors->setBaseline(alignPrivate->top());
- QString hAlign = QStringLiteral("left");
- stream() << "anchors.baseline: textAlignItem_" << counter << ".top";
- switch (m_svgState.textAnchor) {
- case Qt::AlignHCenter:
- hAlign = "horizontalCenter";
- if (m_generateItems)
- anchors->setHorizontalCenter(alignPrivate->left());
- break;
- case Qt::AlignRight:
- hAlign = "right";
- if (m_generateItems)
- anchors->setRight(alignPrivate->left());
- break;
- default:
- qDebug() << "Unexpected text alignment" << m_svgState.textAnchor;
- Q_FALLTHROUGH();
- case Qt::AlignLeft:
- if (m_generateItems)
- anchors->setLeft(alignPrivate->left());
- break;
- }
- stream() << "anchors." << hAlign << ": textAlignItem_" << counter << ".left";
- }
- counter++;
- QString text;
- for (const auto *tspan : node->tspans()) {
- if (!tspan) {
- text += "<br>";
- continue;
- }
-
- if (!tspan->style().font.isDefault()) // TODO: switch to rich text when we have more complex spans with fonts?
- qDebug() << "Not implemented Tspan with font:" << tspan->style().font->qfont();
- QString spanColor;
- if (!tspan->style().fill.isDefault()) {
- auto &b = tspan->style().fill->qbrush();
- qDebug() << "tspan FILL:" << b;
- if (b.style() != Qt::NoBrush)
- spanColor = b.color().name();
- }
- bool fontTag = !spanColor.isEmpty();
- if (fontTag)
- text += QStringLiteral("<font color=\"%1\">").arg(spanColor); // TODO: size="1-7" ???
- text += tspan->text().toHtmlEscaped();
- if (fontTag)
- text += QStringLiteral("</font>");
- }
- stream() << "color: \"" << currentFillColor() << "\"";
- stream() << "textFormat: Text.StyledText";
-
- QFont font = m_dummyPainter.font();
-
- stream() << "text: \"" << text << "\""; // TODO: how about adding template<T> TestVisitor::streamProperty(const QString &name, const T &value)
- stream() << "font.family: \"" << font.family() << "\"";
- if (font.pixelSize() > 0)
- stream() << "font.pixelSize:" << font.pixelSize();
- else if (font.pointSize() > 0)
- stream() << "font.pixelSize:" << font.pointSizeF();
- if (font.underline())
- stream() << "font.underline: true";
- if (font.weight() != QFont::Normal)
- stream() << "font.weight: " << int(font.weight());
-
- if (font.pixelSize() <= 0 && font.pointSize() > 0)
- font.setPixelSize(font.pointSize()); // ### TODO: this makes no sense ###
-
- if (m_generateItems) {
- textItem->setColor(QColor::fromString(currentFillColor()));
- textItem->setTextFormat(QQuickText::StyledText);
- textItem->setText(text);
- textItem->setFont(font);
- }
-
- m_indentLevel--;
- stream() << "}";
- if (m_generateItems)
- m_items.pop();
- handleBaseNodeEnd(node);
-}
-
-//#define EXTRA_DEBUG
-#ifdef EXTRA_DEBUG
-static int nodeSetupLevel = 0;
-#endif
-
-void SvgLoaderVisitor::handleBaseNodeSetup(const QSvgNode *node)
-{
-#ifdef EXTRA_DEBUG
- qDebug() << QByteArray().fill(' ', m_indentLevel * 2).constData() << "before SETUP" << node << "fill" << currentFillColor()
- << "stroke" << currentStrokeColor() << currentStrokeWidth() << node->nodeId() << " type: " << node->typeName() << " " << node->type() << "level" << nodeSetupLevel;
-#endif
- node->applyStyle(&m_dummyPainter, m_svgState);
-
-#ifdef EXTRA_DEBUG
- nodeSetupLevel++;
- qDebug() << QByteArray().fill(' ', m_indentLevel * 2).constData() << "after SETUP" << node << "fill" << currentFillColor()
- << "stroke" << currentStrokeColor() << currentStrokeWidth() << node->nodeId();
-#endif
-}
-
-void SvgLoaderVisitor::handleBaseNode(const QSvgNode *node)
-{
- m_indentLevel++;
- if (!node->nodeId().isEmpty())
- stream() << "objectName: \"" << node->nodeId() << "\""; // or maybe "objectName: \"svg_node:" << node->nodeId()
- if (!node->style().transform.isDefault()) {
- QTransform tr = node->style().transform->qtransform();
- auto sx = tr.m11();
- auto sy = tr.m22();
- auto x = tr.m31();
- auto y = tr.m32();
- if (tr.type() == QTransform::TxTranslate) {
- stream() << "// Translate " << tr.m31() << ", " << tr.m32();
- stream() << "transform: Translate { " << "x: " << x << "; y: " << y << " }";
- } else if (tr.type() == QTransform::TxScale && !x && !y) {
- stream() << "// Scale " << tr.m11() << ", " << tr.m22();
- stream() << "transform: Scale { xScale: " << sx << "; yScale: " << sy << " }";
- } else {
- stream() << "// Complex xform " << tr.type();
- const QMatrix4x4 m(tr);
- auto xform = new QQuickMatrix4x4;
- xform->setMatrix(m);
- {
- stream() << "transform: [ Matrix4x4 { matrix: Qt.matrix4x4 (";
- m_indentLevel += 3;
- const auto *data = m.data();
- for (int i = 0; i < 4; i++) {
- stream() << data[i] << ", " << data[i+4] << ", " << data[i+8] << ", " << data[i+12] << ", ";
- }
- stream() << ") } ]";
- m_indentLevel -= 3;
- }
- }
- if (m_generateItems) {
- auto xformProp = currentItem()->transform();
- if (tr.type() == QTransform::TxTranslate) {
- auto *translate = new QQuickTranslate;
- translate->setX(x);
- translate->setY(y);
- xformProp.append(&xformProp, translate);
- } else if (tr.type() == QTransform::TxScale && !x && !y) {
- auto scale = new QQuickScale;
- scale->setParent(currentItem());
- scale->setXScale(sx);
- scale->setYScale(sy);
- xformProp.append(&xformProp, scale);
- } else {
- const QMatrix4x4 m(tr);
- auto xform = new QQuickMatrix4x4;
- xform->setMatrix(m);
- xformProp.append(&xformProp, xform);
- }
- }
- }
- if (!node->style().opacity.isDefault()) {
- stream() << "opacity: " << node->style().opacity->opacity();
- if (m_generateItems)
- currentItem()->setOpacity(node->style().opacity->opacity());
- }
- m_indentLevel--;
-}
-
-void SvgLoaderVisitor::handleBaseNodeEnd(const QSvgNode *node)
-{
- node->revertStyle(&m_dummyPainter, m_svgState);
-#ifdef EXTRA_DEBUG
- nodeSetupLevel--;
- qDebug() << QByteArray().fill(' ', m_indentLevel * 2).constData() << "AFTER" << node << "fill" << currentFillColor()
- << "stroke" << currentStrokeColor() << currentStrokeWidth() << node->nodeId() << "level" << nodeSetupLevel;
-#endif
-}
-
-QString SvgLoaderVisitor::currentFillColor() const
-{
- if (m_dummyPainter.brush().style() != Qt::NoBrush) {
- QColor c(m_dummyPainter.brush().color());
- c.setAlphaF(m_svgState.fillOpacity);
- //qDebug() << "FILL" << c << m_svgState.fillOpacity << c.name();
- return c.name(QColor::HexArgb);
- } else {
- return QStringLiteral("transparent");
- }
-}
-
-const QGradient *SvgLoaderVisitor::currentFillGradient() const
-{
-
- if (m_dummyPainter.brush().style() == Qt::LinearGradientPattern || m_dummyPainter.brush().style() == Qt::RadialGradientPattern || m_dummyPainter.brush().style() == Qt::ConicalGradientPattern )
- return m_dummyPainter.brush().gradient();
- return nullptr;
-}
-
-QString SvgLoaderVisitor::currentStrokeColor() const
-{
- if (m_dummyPainter.pen().style() != Qt::NoPen)
- return m_dummyPainter.pen().color().name();
- else if (m_dummyPainter.pen().brush().style() == Qt::SolidPattern)
- return m_dummyPainter.pen().brush().color().name();
- return {};
-}
-
-float SvgLoaderVisitor::currentStrokeWidth() const
-{
- float penWidth = m_dummyPainter.pen().widthF();
- return penWidth ? penWidth : 1;
-}
-
-// Find the square that gives the same gradient in QGradient::LogicalMode as
-// objModeRect does in QGradient::ObjectMode
-
-// When the object's bounding box is not square, the stripes that are conceptually
-// perpendicular to the gradient vector within object bounding box space shall render
-// non-perpendicular relative to the gradient vector in user space due to application
-// of the non-uniform scaling transformation from bounding box space to user space.
-static QRectF mapToQtLogicalMode(const QRectF &objModeRect, const QRectF &boundingRect)
-{
-
- QRect pixelRect(objModeRect.x() * boundingRect.width() + boundingRect.left(),
- objModeRect.y() * boundingRect.height() + boundingRect.top(),
- objModeRect.width() * boundingRect.width(),
- objModeRect.height() * boundingRect.height());
-
- if (pixelRect.isEmpty()) // pure horizontal/vertical gradient
- return pixelRect;
-
- double w = boundingRect.width();
- double h = boundingRect.height();
- double objModeSlope = objModeRect.height() / objModeRect.width();
- double a = objModeSlope * w / h;
-
- // do calculation with origin == pixelRect.topLeft
- double x2 = pixelRect.width();
- double y2 = pixelRect.height();
- double x = (x2 + a * y2) / (1 + a * a);
- double y = y2 - (x - x2)/a;
-
- return QRectF(pixelRect.topLeft(), QSizeF(x,y));
-}
-
-static QString toSvgString(const QPainterPath &path)
-{
- QString svgPathString;
- QTextStream strm(&svgPathString);
-
- for (int i = 0; i < path.elementCount(); ++i) {
- QPainterPath::Element element = path.elementAt(i);
- if (element.isMoveTo()) {
- strm << "M " << element.x << " " << element.y << " ";
- } else if (element.isLineTo()) {
- strm << "L " << element.x << " " << element.y << " ";
- } else if (element.isCurveTo()) {
- QPointF c1(element.x, element.y);
- ++i;
- element = path.elementAt(i);
-
- QPointF c2(element.x, element.y);
- ++i;
- element = path.elementAt(i);
- QPointF ep(element.x, element.y);
-
- strm << "C "
- << c1.x() << " "
- << c1.y() << " "
- << c2.x() << " "
- << c2.y() << " "
- << ep.x() << " "
- << ep.y() << " ";
- }
- }
-
- return svgPathString;
-}
-
-static QString toSvgString(const QQuadPath &path)
-{
- QString svgPathString;
- QTextStream strm(&svgPathString);
- path.iterateElements([&](const QQuadPath::Element &e){
- if (e.isSubpathStart())
- strm << "M " << e.startPoint().x() << " " << e.startPoint().y() << " ";
-
- if (e.isLine()) {
- strm << "L " << e.endPoint().x() << " " << e.endPoint().y() << " ";
- } else {
- strm << "Q " << e.controlPoint().x() << " " << e.controlPoint().y() << " "
- << e.endPoint().x() << " " << e.endPoint().y() << " ";
- }
- });
-
- return svgPathString;
-}
-
-void SvgLoaderVisitor::outputGradient(const QGradient *grad, QQuickShapePath *shapePath, const QRectF &boundingRect)
-{
- auto setStops = [](QQuickShapeGradient *quickGrad, const QGradientStops &stops) {
- auto stopsProp = quickGrad->stops();
- for (auto &stop : stops) {
- auto *stopObj = new QQuickGradientStop(quickGrad);
- stopObj->setPosition(stop.first);
- stopObj->setColor(stop.second);
- stopsProp.append(&stopsProp, stopObj);
- }
- };
-
- if (grad->type() == QGradient::LinearGradient) {
- auto *linGrad = static_cast<const QLinearGradient *>(grad);
- stream() << "fillGradient: LinearGradient {";
- m_indentLevel++;
-
- QRectF gradRect(linGrad->start(), linGrad->finalStop());
- QRectF logRect = linGrad->coordinateMode() == QGradient::LogicalMode ? gradRect : mapToQtLogicalMode(gradRect, boundingRect);
-
- stream() << "x1: " << logRect.left();
- stream() << "y1: " << logRect.top();
- stream() << "x2: " << logRect.right();
- stream() << "y2: " << logRect.bottom();
- for (auto &stop : linGrad->stops()) {
- stream() << "GradientStop { position: " << stop.first << "; color: \"" << stop.second.name(QColor::HexArgb) << "\" }";
- }
- m_indentLevel--;
- stream() << "}";
-
- if (shapePath) {
- auto *quickGrad = new QQuickShapeLinearGradient(shapePath);
-
- quickGrad->setX1(logRect.left());
- quickGrad->setY1(logRect.top());
- quickGrad->setX2(logRect.right());
- quickGrad->setY2(logRect.bottom());
- setStops(quickGrad, linGrad->stops());
-
- shapePath->setFillGradient(quickGrad);
- }
- } else if (grad->type() == QGradient::RadialGradient) {
- auto *radGrad = static_cast<const QRadialGradient*>(grad);
- stream() << "fillGradient: RadialGradient {";
- m_indentLevel++;
-
- stream() << "centerX: " << radGrad->center().x();
- stream() << "centerY: " << radGrad->center().y();
- stream() << "centerRadius: " << radGrad->radius();
- stream() << "focalX: centerX; focalY: centerY";
- for (auto &stop : radGrad->stops()) {
- stream() << "GradientStop { position: " << stop.first << "; color: \"" << stop.second.name(QColor::HexArgb) << "\" }";
- }
- m_indentLevel--;
- stream() << "}";
-
- if (shapePath) {
- auto *quickGrad = new QQuickShapeRadialGradient(shapePath);
- quickGrad->setCenterX(radGrad->center().x());
- quickGrad->setCenterY(radGrad->center().y());
- quickGrad->setCenterRadius(radGrad->radius());
- quickGrad->setFocalX(radGrad->center().x());
- quickGrad->setFocalY(radGrad->center().y());
- setStops(quickGrad, radGrad->stops());
-
- shapePath->setFillGradient(quickGrad);
- }
- }
-}
-
-void SvgLoaderVisitor::outputShapePath(const QSvgNode *node, const QPainterPath &path, Qt::PenCapStyle capStyle)
-{
- const bool optimize = m_flags.testFlag(QSvgQmlWriter::OptimizePaths);
- QRectF boundingRect = path.boundingRect();
- if (optimize) {
- const bool outlineMode = m_flags.testFlag(QSvgQmlWriter::OutlineStrokeMode);
- QQuadPath strokePath = QQuadPath::fromPainterPath(path);
- bool fillPathNeededClose;
- QQuadPath fillPath = strokePath.subPathsClosed(&fillPathNeededClose);
- const bool intersectionsFound = QSGCurveProcessor::solveIntersections(fillPath, false);
- fillPath.addCurvatureData();
- QSGCurveProcessor::solveOverlaps(fillPath);
-
- const bool compatibleStrokeAndFill = !fillPathNeededClose && !intersectionsFound;
-
- if (compatibleStrokeAndFill || outlineMode) {
- outputShapePath(node, nullptr, &fillPath, capStyle, FillAndStroke, boundingRect);
- } else {
- outputShapePath(node, nullptr, &fillPath, capStyle, FillPath, boundingRect);
- outputShapePath(node, nullptr, &strokePath, capStyle, StrokePath, boundingRect);
- }
- } else {
- outputShapePath(node, &path, nullptr, capStyle, FillAndStroke, boundingRect);
- }
-}
-
-static QString pathHintString(const QQuadPath &qp)
-{
- QString res;
- QTextStream str(&res);
- auto flags = qp.pathHints();
- if (!flags)
- return res;
- str << "pathHints:";
- bool first = true;
-
-#define CHECK_PATH_HINT(flagName) \
- if (flags.testFlag(QQuadPath::flagName)) { \
- if (!first) \
- str << " |"; \
- first = false; \
- str << " ShapePath." #flagName; \
- }
-
- CHECK_PATH_HINT(PathLinear)
- CHECK_PATH_HINT(PathQuadratic)
- CHECK_PATH_HINT(PathConvex)
- CHECK_PATH_HINT(PathFillOnRight)
- CHECK_PATH_HINT(PathSolid)
- CHECK_PATH_HINT(PathNonIntersecting)
- CHECK_PATH_HINT(PathNonOverlappingControlPointTriangles)
-
- return res;
-}
-
-void SvgLoaderVisitor::outputShapePath(const QSvgNode *node, const QPainterPath *painterPath, const QQuadPath *quadPath, Qt::PenCapStyle capStyle, PathSelector pathSelector, const QRectF &boundingRect)
-{
- Q_UNUSED(pathSelector)
- Q_ASSERT(painterPath || quadPath);
-
- QString penName = currentStrokeColor();
- const bool noPen = penName.isEmpty() || penName == u"transparent";
- if (pathSelector == StrokePath && noPen)
- return;
-
- const bool noFill = !currentFillGradient() && currentFillColor() == u"transparent";
- if (pathSelector == FillPath && noFill)
- return;
-
- auto fillRule = QQuickShapePath::FillRule(painterPath ? painterPath->fillRule() : quadPath->fillRule());
- stream() << "ShapePath {";
- m_indentLevel++;
- auto *shapePath = m_generateItems ? new QQuickShapePath : nullptr;
- if (!node->nodeId().isEmpty()) {
- switch (pathSelector) {
- case FillPath:
- stream() << "objectName: \"svg_fill_path:" << node->nodeId() << "\"";
- break;
- case StrokePath:
- stream() << "objectName: \"svg_stroke_path:" << node->nodeId() << "\"";
- break;
- case FillAndStroke:
- stream() << "objectName: \"svg_path:" << node->nodeId() << "\"";
- break;
- }
- if (shapePath)
- shapePath->setObjectName(QStringLiteral("svg_path:") + node->nodeId());
- }
- stream() << "// boundingRect: " << boundingRect.x() << ", " << boundingRect.y() << " " << boundingRect.width() << "x" << boundingRect.height();
-
- if (noPen || !(pathSelector & StrokePath)) {
- stream() << "strokeColor: \"transparent\"";
- if (shapePath)
- shapePath->setStrokeColor(Qt::transparent);
- } else {
- stream() << "strokeColor: \"" << penName << "\"";
- stream() << "strokeWidth: " << currentStrokeWidth();
- if (shapePath) {
- shapePath->setStrokeColor(QColor::fromString(penName));
- shapePath->setStrokeWidth(currentStrokeWidth());
- }
- }
- if (capStyle == Qt::FlatCap)
- stream() << "capStyle: ShapePath.FlatCap"; //### TODO Add the rest of the styles, as well as join styles etc.
-
- if (shapePath)
- shapePath->setCapStyle(QQuickShapePath::CapStyle(capStyle));
-
- if (!(pathSelector & FillPath)) {
- stream() << "fillColor: \"transparent\"";
- if (shapePath)
- shapePath->setFillColor(Qt::transparent);
- } else if (auto *grad = currentFillGradient()) {
- outputGradient(grad, shapePath, boundingRect);
- } else {
- stream() << "fillColor: \"" << currentFillColor() << "\"";
- if (shapePath)
- shapePath->setFillColor(QColor::fromString(currentFillColor()));
- }
- if (fillRule == QQuickShapePath::WindingFill)
- stream() << "fillRule: ShapePath.WindingFill";
- else
- stream() << "fillRule: ShapePath.OddEvenFill";
- if (shapePath)
- shapePath->setFillRule(fillRule);
-
- if (quadPath) {
- QString hintStr = pathHintString(*quadPath);
- if (!hintStr.isEmpty())
- stream() << hintStr;
- }
-
- QString svgPathString = painterPath ? toSvgString(*painterPath) : toSvgString(*quadPath);
- stream() << "PathSvg { path: \"" << svgPathString << "\" }";
-
- if (shapePath) {
- auto *pathSvg = new QQuickPathSvg;
- pathSvg->setPath(svgPathString);
- pathSvg->setParent(shapePath);
-
- auto pathElementProp = shapePath->pathElements();
- pathElementProp.append(&pathElementProp, pathSvg);
-
- shapePath->setParent(currentItem());
- auto shapeDataProp = m_parentShapeItem->data();
- shapeDataProp.append(&shapeDataProp, shapePath);
- }
- m_indentLevel--;
- stream() << "}";
-}
-
-static bool isPathContainer(const QSvgStructureNode *node)
-{
- bool foundPath = false;
- for (const auto *child : node->renderers()) {
- switch (child->type()) {
- // nodes that shouldn't go inside Shape{}
- case QSvgNode::Switch:
- case QSvgNode::Doc:
- case QSvgNode::Group:
- case QSvgNode::Animation:
- case QSvgNode::Use:
- case QSvgNode::Video:
- //qDebug() << "NOT path container because" << node->typeName() ;
- return false;
-
- // nodes that could go inside Shape{}
- case QSvgNode::Defs:
- case QSvgNode::Image:
- case QSvgNode::Textarea:
- case QSvgNode::Text:
- case QSvgNode::Tspan:
- break;
-
- // nodes that are done as pure ShapePath{}
- case QSvgNode::Rect:
- case QSvgNode::Circle:
- case QSvgNode::Ellipse:
- case QSvgNode::Line:
- case QSvgNode::Path:
- case QSvgNode::Polygon:
- case QSvgNode::Polyline:
- if (!child->style().transform.isDefault()) {
- //qDebug() << "NOT path container because local transform";
- return false;
- }
- foundPath = true;
- break;
- default:
- qDebug() << "Unhandled type in switch" << child->type();
- break;
- }
- }
- //qDebug() << "Container" << node->nodeId() << node->typeName() << "is" << foundPath;
- return foundPath;
-}
-
-namespace {
-class ViewBoxItem : public QQuickItem
-{
-public:
- ViewBoxItem(const QRectF viewBox, QQuickItem *parent = nullptr) : QQuickItem(parent), m_viewBox(viewBox) { setXForm(); }
-
-protected:
- void geometryChange(const QRectF &/*newGeometry*/, const QRectF &/*oldGeometry*/) override
- {
- setXForm();
- }
-
-private:
- void setXForm()
- {
- auto xformProp = transform();
- xformProp.clear(&xformProp);
- bool translate = !qFuzzyIsNull(m_viewBox.x()) || !qFuzzyIsNull(m_viewBox.y());
- if (translate) {
- auto *tr = new QQuickTranslate(this);
- tr->setX(-m_viewBox.x());
- tr->setY(-m_viewBox.y());
- xformProp.append(&xformProp, tr);
- }
- if (!m_viewBox.isEmpty() && width() && height()) {
- auto *scale = new QQuickScale(this);
- qreal sx = width() / m_viewBox.width();
- qreal sy = height() / m_viewBox.height();
-
- scale->setXScale(sx);
- scale->setYScale(sy);
- xformProp.append(&xformProp, scale);
- }
- }
- QRectF m_viewBox;
-};
-}
-
-bool SvgLoaderVisitor::visitDefsNodeStart(const QSvgDefs *node)
-{
- stream() << "// skipping DEFS \"" << node->nodeId() << "\"";
- return false; // skip to end; TODO: implement defs
-}
-
-bool SvgLoaderVisitor::visitStructureNodeStart(const QSvgStructureNode *node)
-{
- constexpr bool forceSeparatePaths = false;
- handleBaseNodeSetup(node);
- stream() << "// START " << node->nodeId() << " type: " << node->typeName() << " " << node->type();
-
- bool isTopLevel = node->type() == QSvgNode::Doc;
- bool hasViewBox = false;
- QRectF viewBox;
-
- if (isTopLevel) {
- auto *doc = static_cast<const QSvgTinyDocument *>(node);
- viewBox = doc->viewBox();
- hasViewBox = !viewBox.isEmpty();
- }
-
- if (!forceSeparatePaths && !isTopLevel && isPathContainer(node)) {
- stream() << shapeName() <<" { //combined path container";
- m_indentLevel++;
- if (m_flags & QSvgQmlWriter::CurveRenderer)
- stream() << "preferredRendererType: Shape.CurveRenderer";
- m_indentLevel--;
-
- m_inShapeItem = true;
- if (m_generateItems) {
- auto *shapeItem = new QQuickShape;
- shapeItem->setPreferredRendererType(QQuickShape::CurveRenderer); // TODO: settable
- m_parentShapeItem = shapeItem;
- addCurrentItem(shapeItem, node);
- }
- } else {
- stream() << "Item { // structure node";
- if (m_generateItems) {
- auto *item = hasViewBox ? new ViewBoxItem(viewBox) : new QQuickItem;
- addCurrentItem(item, node );
- if (isTopLevel)
- m_loadedItem = item;
- }
- }
- if (hasViewBox) {
- m_indentLevel++;
- stream() << "transform: [";
- m_indentLevel++;
- bool translate = !qFuzzyIsNull(viewBox.x()) || !qFuzzyIsNull(viewBox.y());
- if (translate)
- stream() << "Translate { x: " << -viewBox.x() << "; y: " << -viewBox.y() << " },";
- stream() << "Scale { xScale: width / " << viewBox.width() << "; yScale: height / " << viewBox.height() << " }";
- m_indentLevel--;
- stream() << "]";;
- m_indentLevel--;
- }
- handleBaseNode(node);
- m_indentLevel++;
- return true;
-}
-
-void SvgLoaderVisitor::visitStructureNodeEnd(const QSvgStructureNode *node)
-{
- m_indentLevel--;
- stream() << "} // END " << node->nodeId() << " type: " << node->typeName() << " " << node->type();
- handleBaseNodeEnd(node);
-// qDebug() << "REVERT" << node->nodeId() << node->type() << (m_dummyPainter.pen().style() != Qt::NoPen) << m_dummyPainter.pen().color().name()
-// << (m_dummyPainter.pen().brush().style() != Qt::NoBrush) << m_dummyPainter.pen().brush().color().name();
- m_inShapeItem = false;
- m_parentShapeItem = nullptr;
- if (m_generateItems)
- m_items.pop();
-}
-
-void SvgLoaderVisitor::visitRectNode(const QSvgRect *node)
-{
- QRectF rect = node->rect();
- QPointF rads = node->radius();
- // This is using Qt::RelativeSize semantics: percentage of half rect size
- qreal x1 = rect.left();
- qreal x2 = rect.right();
- qreal y1 = rect.top();
- qreal y2 = rect.bottom();
-
- qreal rx = rads.x() * rect.width() / 200;
- qreal ry = rads.y() * rect.height() / 200;
- QPainterPath p;
-
- p.moveTo(x1 + rx, y1);
- p.lineTo(x2 - rx, y1);
- // qDebug() << "Line1" << x2 - rx << y1;
- p.arcTo(x2 - rx * 2, y1, rx * 2, ry * 2, 90, -90); // ARC to x2, y1 + ry
- // qDebug() << "p1" << p;
-
- p.lineTo(x2, y2 - ry);
- p.arcTo(x2 - rx * 2, y2 - ry * 2, rx * 2, ry * 2, 0, -90); // ARC to x2 - rx, y2
-
- p.lineTo(x1 + rx, y2);
- p.arcTo(x1, y2 - ry * 2, rx * 2, ry * 2, 270, -90); // ARC to x1, y2 - ry
-
- p.lineTo(x1, y1 + ry);
- p.arcTo(x1, y1, rx * 2, ry * 2, 180, -90); // ARC to x1 + rx, y1
-
-
- stream() << "// Path from rect " << node->nodeId() << " r " << rect.x() << ", " << rect.y()
- << " " << rect.width() << "x" << rect.height() << " R: " << rads.x() << ", " << rads.y();
-
- handlePathNode(node, p);
-
- return;
-
-}
-
-void SvgLoaderVisitor::visitEllipseNode(const QSvgEllipse *node)
-{
- QRectF rect = node->rect();
- stream() << "// Ellipse" << node->nodeId() << " rect: " << rect.x() << ", " << rect.y()
- << " " << rect.width() << "x" << rect.height();
- QPainterPath p;
- p.addEllipse(rect);
-
- handlePathNode(node, p);
-}
-
-QQuickItem *SvgLoaderVisitor::loadQML(QTextStream *outStream, const QSvgTinyDocument *doc, QQuickItem *parentItem)
-{
- Q_ASSERT(outStream);
- m_stream = outStream;
- m_indentLevel = 0;
-
- stream() << "import QtQuick";
- stream() << "import QtQuick.Shapes" << Qt::endl;
-
- QRectF viewBox = doc->viewBox();
-
- m_generateItems = parentItem != nullptr;
- m_items.push(parentItem);
-
- stream() << "Item {";
- m_indentLevel++;
- stream() << "// viewBox " << viewBox.x() << ", " << viewBox.y()
- << " " << viewBox.width() << "x" << viewBox.height();
- stream() << "// size " << doc->width() << "x" << doc->height();
- double w = doc->width();
- double h = doc->height();
- if (w > 0)
- stream() << "implicitWidth: " << w;
- if (h > 0)
- stream() << "implicitHeight: " << h;
-
- if (parentItem) {
- m_generateItems = true;
- parentItem->setImplicitWidth(w);
- parentItem->setImplicitHeight(h);
- }
- traverse(doc);
- m_indentLevel--;
- stream() << "}";
- return m_loadedItem;
-}
-
-void SvgLoaderVisitor::visitNode(const QSvgNode *node)
-{
- handleBaseNodeSetup(node);
- stream() << "//### SVG NODE NOT IMPLEMENTED: " << node->nodeId() << " type: " << node->typeName() << " " << node->type();
- stream() << "Item {";
- handleBaseNode(node);
- stream() << "}";
- handleBaseNodeEnd(node);
-}
-
-QQuickItem *QSvgQmlWriter::loadSVG(const QSvgTinyDocument *doc, const QString &outFileName, GeneratorFlags flags, const QString &typeName, QQuickItem *parentItem, const QString &commentString)
-{
- SvgLoaderVisitor visitor;
- if (!typeName.isEmpty())
- visitor.setShapeTypeName(typeName);
- visitor.setFlags(flags);
- QByteArray result;
- QTextStream str(&result);
- if (commentString.isEmpty())
- str << "// Generated from SVG" << Qt::endl;
- else
- str << "// " << commentString << Qt::endl;
- auto *loadedItem = visitor.loadQML(&str, doc, parentItem);
- if (!outFileName.isEmpty()) {
- QFile outFile(outFileName);
- outFile.open(QIODevice::WriteOnly);
- outFile.write(result);
- outFile.close();
- }
-#if 0
- result.truncate(300);
- qDebug().noquote() << result;
-#endif
- return loadedItem;
-}
-
-QT_END_NAMESPACE
diff --git a/tools/svgtoqml/qsvgloader_p.h b/tools/svgtoqml/qsvgloader_p.h
deleted file mode 100644
index 1804a7d358..0000000000
--- a/tools/svgtoqml/qsvgloader_p.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-
-#ifndef QSVGQMLWRITER_P_H
-#define QSVGQMLWRITER_P_H
-
-#include <QtCore/qtconfigmacros.h>
-#include <QtCore/qflags.h>
-
-QT_BEGIN_NAMESPACE
-
-class QTextStream;
-class QSvgTinyDocument;
-class QString;
-class QQuickItem;
-
-class QSvgQmlWriter
-{
-public:
- enum GeneratorFlag {
- OptimizePaths = 0x01,
- CurveRenderer = 0x02,
- OutlineStrokeMode = 0x04
- };
- Q_DECLARE_FLAGS(GeneratorFlags, GeneratorFlag);
- static QQuickItem *loadSVG(const QSvgTinyDocument *doc, const QString &outFileName, GeneratorFlags flags, const QString &typeName, QQuickItem *parentItem, const QString &commentString);
-};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSvgQmlWriter::GeneratorFlags);
-
-QT_END_NAMESPACE
-
-#endif // QSVGQMLWRITER_P_H