aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/svgtoqml/main.cpp44
-rw-r--r--tools/svgtoqml/qsvgloader.cpp374
-rw-r--r--tools/svgtoqml/qsvgloader_p.h10
3 files changed, 295 insertions, 133 deletions
diff --git a/tools/svgtoqml/main.cpp b/tools/svgtoqml/main.cpp
index bedf703373..816f4808c0 100644
--- a/tools/svgtoqml/main.cpp
+++ b/tools/svgtoqml/main.cpp
@@ -28,24 +28,22 @@ int main(int argc, char *argv[])
parser.addPositionalArgument("input", QCoreApplication::translate("main", "SVG file to read."));
parser.addPositionalArgument("output", QCoreApplication::translate("main", "QML file to write."));
-#if 0
- QCommandLineOption separateOption(QStringList() << "s" << "separate-items",
- QCoreApplication::translate("main", "Generate separate items for all sub-shapes."));
- parser.addOption(separateOption);
-
- QCommandLineOption combineOption(QStringList() << "c" << "combine-shapes",
- QCoreApplication::translate("main", "Combine all sub-shapes into one item."));
- parser.addOption(combineOption);
-#endif
+ QCommandLineOption optimizeOption("optimize-paths",
+ QCoreApplication::translate("main", "Optimize paths for the curve renderer."));
+ parser.addOption(optimizeOption);
+
+ QCommandLineOption curveRendererOption("curve-renderer",
+ QCoreApplication::translate("main", "Use the curve renderer in generated QML."));
+ parser.addOption(curveRendererOption);
+
QCommandLineOption typeNameOption(QStringList() << "t" << "type-name",
QCoreApplication::translate("main", "Use <typename> for Shape."),
QCoreApplication::translate("main", "typename"));
parser.addOption(typeNameOption);
-
#ifdef ENABLE_GUI
QCommandLineOption guiOption(QStringList() << "v" << "view",
- QCoreApplication::translate("main", "Display the SVG in a window."));
+ QCoreApplication::translate("main", "Display the SVG in a window."));
parser.addOption(guiOption);
#endif
parser.process(app);
@@ -54,14 +52,24 @@ int main(int argc, char *argv[])
parser.showHelp(1);
}
- auto *doc = QSvgTinyDocument::load(args.at(0));
+ const QString inFileName = args.at(0);
+
+ auto *doc = QSvgTinyDocument::load(inFileName);
if (!doc) {
- fprintf(stderr, "%s is not a valid SVG\n", qPrintable(args.at(0)));
+ fprintf(stderr, "%s is not a valid SVG\n", qPrintable(inFileName));
return 2;
}
- auto outFileName = args.size() > 1 ? args.at(1) : QString{};
- auto typeName = parser.value(typeNameOption);
+ const 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);
+
+ QSvgQmlWriter::GeneratorFlags flags;
+ if (parser.isSet(curveRendererOption))
+ flags |= QSvgQmlWriter::CurveRenderer;
+ if (parser.isSet(optimizeOption))
+ flags |= QSvgQmlWriter::OptimizePaths;
#ifdef ENABLE_GUI
if (parser.isSet(guiOption)) {
@@ -69,12 +77,12 @@ int main(int argc, char *argv[])
const QUrl url(QStringLiteral("qrc:/main.qml"));
QQmlApplicationEngine engine;
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
- &app, [url, outFileName, doc, typeName](QObject *obj, const QUrl &objUrl){
+ &app, [&](QObject *obj, const QUrl &objUrl){
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
if (obj) {
auto *containerItem = obj->findChild<QQuickItem*>(QStringLiteral("svg_item"));
- auto *contents = QSvgQmlWriter::loadSVG(doc, outFileName, typeName, containerItem);
+ 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());
}
@@ -84,6 +92,6 @@ int main(int argc, char *argv[])
}
#endif
- QSvgQmlWriter::loadSVG(doc, outFileName, typeName, nullptr);
+ QSvgQmlWriter::loadSVG(doc, outFileName, flags, typeName, nullptr, commentString);
return 0;
}
diff --git a/tools/svgtoqml/qsvgloader.cpp b/tools/svgtoqml/qsvgloader.cpp
index 3d924bbdeb..fc72fb7454 100644
--- a/tools/svgtoqml/qsvgloader.cpp
+++ b/tools/svgtoqml/qsvgloader.cpp
@@ -16,6 +16,7 @@
#include <private/qquickimagebase_p_p.h>
#include <private/qquickimage_p.h>
+#include <private/qsgcurveprocessor_p.h>
#include <private/qquadpath_p.h>
@@ -52,6 +53,7 @@ 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:
@@ -92,6 +94,11 @@ private:
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) {
@@ -119,6 +126,7 @@ private:
QQuickItem *m_loadedItem = nullptr;
bool m_generateQML = true;
bool m_generateItems = false;
+ QSvgQmlWriter::GeneratorFlags m_flags;
};
SvgLoaderVisitor::SvgLoaderVisitor()
@@ -140,10 +148,14 @@ void SvgLoaderVisitor::handlePathNode(const QSvgNode *node, const QPainterPath &
{
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, path, capStyle);
+ outputShapePath(node, pathCopy, capStyle);
} else {
if (m_generateItems) {
auto *shapeItem = new QQuickShape;
@@ -156,7 +168,9 @@ void SvgLoaderVisitor::handlePathNode(const QSvgNode *node, const QPainterPath &
stream() << shapeName() << " {";
handleBaseNode(node);
m_indentLevel++;
- outputShapePath(node, path, capStyle);
+ if (m_flags & QSvgQmlWriter::CurveRenderer)
+ stream() << "preferredRendererType: Shape.CurveRenderer";
+ outputShapePath(node, pathCopy, capStyle);
//qDebug() << *node->qpath();
m_indentLevel--;
stream() << "}";
@@ -171,6 +185,7 @@ void SvgLoaderVisitor::handlePathNode(const QSvgNode *node, const QPainterPath &
void SvgLoaderVisitor::visitPathNode(const QSvgPath *node)
{
stream() << "// PATH visit " << node->nodeId() << " count: " << node->path().elementCount();
+
handlePathNode(node, node->path());
}
@@ -545,145 +560,265 @@ static QRectF mapToQtLogicalMode(const QRectF &objModeRect, const QRectF &boundi
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)
{
- QPointF offset; // ??? do we need this?
+ 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()) {
- stream() << "objectName: \"svg_path:" << node->nodeId() << "\"";
- if (m_generateItems)
+ 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: " << path.boundingRect().x() << ", " << path.boundingRect().y() << " " << path.boundingRect().width() << "x" << path.boundingRect().height();
- QString penName = currentStrokeColor();
- if (penName.isEmpty()) {
+ stream() << "// boundingRect: " << boundingRect.x() << ", " << boundingRect.y() << " " << boundingRect.width() << "x" << boundingRect.height();
+
+ if (noPen || !(pathSelector & StrokePath)) {
stream() << "strokeColor: \"transparent\"";
- if (m_generateItems)
+ if (shapePath)
shapePath->setStrokeColor(Qt::transparent);
} else {
stream() << "strokeColor: \"" << penName << "\"";
stream() << "strokeWidth: " << currentStrokeWidth();
- if (m_generateItems) {
+ if (shapePath) {
shapePath->setStrokeColor(QColor::fromString(penName));
shapePath->setStrokeWidth(currentStrokeWidth());
}
}
if (capStyle == Qt::FlatCap)
- stream() << "capStyle: ShapePath.FlatCap"; //### TODO
+ stream() << "capStyle: ShapePath.FlatCap"; //### TODO Add the rest of the styles, as well as join styles etc.
- if (m_generateItems)
+ if (shapePath)
shapePath->setCapStyle(QQuickShapePath::CapStyle(capStyle));
- if (auto *grad = currentFillGradient()) {
-
- 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);
-// qDebug() << "grad" << linGrad->start() << linGrad->finalStop() << "mode" << linGrad->coordinateMode();
-// qDebug() << "path BR" << path.boundingRect();
- QRectF br = path.boundingRect();
- stream() << "fillGradient: LinearGradient {";
- m_indentLevel++;
-
- QRectF gradRect(linGrad->start(), linGrad->finalStop());
- QRectF logRect = linGrad->coordinateMode() == QGradient::LogicalMode ? gradRect : mapToQtLogicalMode(gradRect, br);
-
- 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 (m_generateItems) {
- 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 (m_generateItems) {
- 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);
- }
- }
+ 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 (m_generateItems)
+ if (shapePath)
shapePath->setFillColor(QColor::fromString(currentFillColor()));
}
- stream() << "fillRule: ShapePath.WindingFill";
-
- 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 - offset.x()) << " " << (element.y - offset.y()) << " ";
- } else if (element.isLineTo()) {
- strm << "L " << (element.x - offset.x()) << " " << (element.y - offset.y()) << " ";
- } else if (element.isCurveTo()) {
- QPointF c1((element.x - offset.x()), (element.y - offset.y()));
- ++i;
- element = path.elementAt(i);
-
- QPointF c2((element.x - offset.x()), (element.y - offset.y()));
- ++i;
- element = path.elementAt(i);
-
- strm<< "C "
- << (c1.x() - offset.x()) << " "
- << (c1.y() - offset.y()) << " "
- << (c2.x() - offset.x()) << " "
- << (c2.y() - offset.y()) << " "
- << (element.x - offset.x()) << " "
- << (element.y - offset.y()) << " ";
- }
+ 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 (m_generateItems) {
+ if (shapePath) {
auto *pathSvg = new QQuickPathSvg;
pathSvg->setPath(svgPathString);
pathSvg->setParent(shapePath);
@@ -807,10 +942,15 @@ bool SvgLoaderVisitor::visitStructureNodeStart(const QSvgStructureNode *node)
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_inShapeItem = true;
m_parentShapeItem = shapeItem;
addCurrentItem(shapeItem, node);
}
@@ -908,6 +1048,7 @@ QQuickItem *SvgLoaderVisitor::loadQML(QTextStream *outStream, const QSvgTinyDocu
Q_ASSERT(outStream);
m_stream = outStream;
m_indentLevel = 0;
+
stream() << "import QtQuick";
stream() << "import QtQuick.Shapes" << Qt::endl;
@@ -949,13 +1090,18 @@ void SvgLoaderVisitor::visitNode(const QSvgNode *node)
handleBaseNodeEnd(node);
}
-QQuickItem *QSvgQmlWriter::loadSVG(const QSvgTinyDocument *doc, const QString &outFileName, const QString &typeName, QQuickItem *parentItem)
+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);
diff --git a/tools/svgtoqml/qsvgloader_p.h b/tools/svgtoqml/qsvgloader_p.h
index c5cee6747d..1804a7d358 100644
--- a/tools/svgtoqml/qsvgloader_p.h
+++ b/tools/svgtoqml/qsvgloader_p.h
@@ -5,6 +5,7 @@
#define QSVGQMLWRITER_P_H
#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qflags.h>
QT_BEGIN_NAMESPACE
@@ -16,8 +17,15 @@ class QQuickItem;
class QSvgQmlWriter
{
public:
- static QQuickItem *loadSVG(const QSvgTinyDocument *doc, const QString &outFileName, const QString &typeName, QQuickItem *parentItem = nullptr);
+ 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