8#include <private/qsgcurveprocessor_p.h>
9#include <private/qquickshape_p.h>
10#include <private/qquadpath_p.h>
11#include <private/qquickitem_p.h>
12#include <private/qquickimagebase_p_p.h>
14#include <QtCore/qloggingcategory.h>
15#include <QtCore/qdir.h>
21 , outputFileName(outFileName)
32 qCWarning(lcQuickVectorImage) <<
"Failed to create path" <<
dir.absolutePath();
35 QFile outFile(outputFileName);
37 outFile.write(m_result.
data());
42 if (lcQuickVectorImage().isDebugEnabled())
48 m_shapeTypeName =
name.toLatin1();
63 return m_commentString;
69 if (!
info.nodeId.isEmpty())
70 stream() <<
"objectName: \"" <<
info.nodeId <<
"\"";
71 if (!
info.isDefaultTransform) {
72 auto sx =
info.transform.m11();
73 auto sy =
info.transform.m22();
74 auto x =
info.transform.m31();
75 auto y =
info.transform.m32();
77 stream() <<
"transform: Translate { " <<
"x: " <<
x <<
"; y: " <<
y <<
" }";
79 stream() <<
"transform: Scale { xScale: " << sx <<
"; yScale: " << sy <<
" }";
81 stream() <<
"transform: Matrix4x4 { matrix: ";
82 generateTransform(
info.transform);
86 if (!
info.isDefaultOpacity) {
104 const QFileInfo outputFileInfo(outputFileName);
105 const QDir outputDir(outputFileInfo.absolutePath());
109 if (!m_retainFilePaths ||
info.externalFileReference.isEmpty()) {
110 filePath = m_assetFileDirectory;
112 filePath = outputDir.absolutePath();
117 QDir fileDir(filePath);
118 if (!fileDir.exists()) {
120 qCWarning(lcQuickVectorImage) <<
"Failed to create image resource directory:" << filePath;
128 if (!
info.image.save(filePath))
129 qCWarning(lcQuickVectorImage) <<
"Unabled to save image resource" << filePath;
130 qCDebug(lcQuickVectorImage) <<
"Saving copy of IMAGE" << filePath;
132 filePath =
info.externalFileReference;
146 stream() <<
"source: \"" << outputDir.relativeFilePath(assetFileInfo.absoluteFilePath()) <<
"\"";
159 if (!
info.isDefaultTransform)
160 qWarning() <<
"Skipped transform for node" <<
info.nodeId <<
"type" <<
info.typeName <<
"(this is not supposed to happen)";
163 m_inShapeItem =
true;
164 stream() << shapeName() <<
" {";
171 stream() <<
"preferredRendererType: Shape.CurveRenderer";
176 m_inShapeItem =
false;
184 stream() <<
"fillGradient: LinearGradient {";
187 QRectF gradRect(linGrad->start(), linGrad->finalStop());
190 stream() <<
"x1: " << logRect.left();
191 stream() <<
"y1: " << logRect.top();
192 stream() <<
"x2: " << logRect.right();
193 stream() <<
"y2: " << logRect.bottom();
194 for (
auto &stop : linGrad->stops())
195 stream() <<
"GradientStop { position: " << stop.
first <<
"; color: \"" << stop.second.
name(
QColor::HexArgb) <<
"\" }";
200 stream() <<
"fillGradient: RadialGradient {";
203 stream() <<
"centerX: " << radGrad->center().x();
204 stream() <<
"centerY: " << radGrad->center().y();
205 stream() <<
"centerRadius: " << radGrad->radius();
206 stream() <<
"focalX:" << radGrad->focalPoint().x();
207 stream() <<
"focalY:" << radGrad->focalPoint().y();
208 for (
auto &stop : radGrad->stops())
209 stream() <<
"GradientStop { position: " << stop.
first <<
"; color: \"" << stop.second.
name(
QColor::HexArgb) <<
"\" }";
215void QQuickQmlGenerator::generateTransform(
const QTransform &xf)
218 stream(SameLine) <<
"PlanarTransform.fromAffineMatrix("
219 << xf.m11() <<
", " << xf.m12() <<
", "
220 << xf.m21() <<
", " << xf.m22() <<
", "
221 << xf.dx() <<
", " << xf.dy() <<
")";
224 stream(SameLine) <<
"Qt.matrix4x4(";
226 const auto *
data =
m.data();
227 for (
int i = 0;
i < 4;
i++) {
252 stream() <<
"ShapePath {";
254 if (!
info.nodeId.isEmpty()) {
255 switch (pathSelector) {
257 stream() <<
"objectName: \"svg_fill_path:" <<
info.nodeId <<
"\"";
260 stream() <<
"objectName: \"svg_stroke_path:" <<
info.nodeId <<
"\"";
263 stream() <<
"objectName: \"svg_path:" <<
info.nodeId <<
"\"";
269 stream() <<
"strokeColor: \"transparent\"";
272 stream() <<
"strokeWidth: " <<
info.strokeStyle.width;
275 stream() <<
"miterLimit: " <<
info.strokeStyle.miterLimit;
276 if (
info.strokeStyle.dashArray.length() != 0) {
277 stream() <<
"strokeStyle: " <<
"ShapePath.DashLine";
279 stream() <<
"dashOffset: " <<
info.strokeStyle.dashOffset;
284 stream() <<
"fillColor: \"transparent\"";
291 if (!
info.fillTransform.isIdentity()) {
293 stream() <<
"fillTransform: ";
295 stream(SameLine) <<
"PlanarTransform.fromTranslate(" << xf.dx() <<
", " << xf.dy() <<
")";
297 stream(SameLine) <<
"PlanarTransform.fromScale(" << xf.m11() <<
", " << xf.m22() <<
")";
299 generateTransform(xf);
303 stream() <<
"fillRule: ShapePath.WindingFill";
305 stream() <<
"fillRule: ShapePath.OddEvenFill";
310 if (!hintStr.isEmpty())
315 stream() <<
"PathSvg { path: \"" << svgPathString <<
"\" }";
326 stream() <<
"// Missing Implementation for SVG Node: " <<
info.typeName;
327 stream() <<
"// Adding an empty Item and skipping";
343 if (!
info.isTextArea)
344 stream() <<
"Item { id: textAlignItem_" <<
counter <<
"; x: " <<
info.position.x() <<
"; y: " <<
info.position.y() <<
"}";
350 if (
info.isTextArea) {
353 if (
info.size.width() > 0)
355 if (
info.size.height() > 0)
357 stream() <<
"wrapMode: Text.Wrap";
361 stream() <<
"anchors.baseline: textAlignItem_" <<
counter <<
".top";
362 switch (
info.alignment) {
370 qCDebug(lcQuickVectorImage) <<
"Unexpected text alignment" <<
info.alignment;
375 stream() <<
"anchors." << hAlign <<
": textAlignItem_" <<
counter <<
".left";
380 stream() <<
"textFormat:" << (
info.needsRichText ?
"Text.RichText" :
"Text.StyledText");
384 stream() <<
"text: \"" <<
s <<
"\"";
385 stream() <<
"font.family: \"" <<
info.font.family() <<
"\"";
386 if (
info.font.pixelSize() > 0)
387 stream() <<
"font.pixelSize:" <<
info.font.pixelSize();
388 else if (
info.font.pointSize() > 0)
389 stream() <<
"font.pixelSize:" <<
info.font.pointSizeF();
390 if (
info.font.underline())
391 stream() <<
"font.underline: true";
393 stream() <<
"font.weight: " << int(
info.font.weight());
394 if (
info.font.italic())
395 stream() <<
"font.italic: true";
399 stream() <<
"style: Text.Outline";
432 if (!
info.forceSeparatePaths &&
info.isPathContainer) {
433 stream() << shapeName() <<
" {";
436 stream() <<
"preferredRendererType: Shape.CurveRenderer";
439 m_inShapeItem =
true;
444 if (!
info.viewBox.isEmpty()) {
446 stream() <<
"transform: [";
450 stream() <<
"Translate { x: " << -
info.viewBox.x() <<
"; y: " << -
info.viewBox.y() <<
" },";
451 stream() <<
"Scale { xScale: width / " <<
info.viewBox.width() <<
"; yScale: height / " <<
info.viewBox.height() <<
" }";
462 m_inShapeItem =
false;
474 if (comments.isEmpty()) {
475 stream() <<
"// Generated from SVG";
477 for (
const auto &comment : comments)
478 stream() <<
"// " << comment;
481 stream() <<
"import QtQuick";
486 double w =
info.size.width();
487 double h =
info.size.height();
489 stream() <<
"implicitWidth: " <<
w;
491 stream() <<
"implicitHeight: " <<
h;
500 if (comments.isEmpty())
501 stream() <<
"// Generated from SVG";
503 for (
const auto &comment : comments)
504 stream() <<
"// " << comment;
506 stream() <<
"import QtQuick";
511 double w =
info.size.width();
512 double h =
info.size.height();
514 stream() <<
"implicitWidth: " <<
w;
516 stream() <<
"implicitHeight: " <<
h;
518 if (!
info.viewBox.isEmpty()) {
519 stream() <<
"transform: [";
523 stream() <<
"Translate { x: " << -
info.viewBox.x() <<
"; y: " << -
info.viewBox.y() <<
" },";
524 stream() <<
"Scale { xScale: width / " <<
info.viewBox.width() <<
"; yScale: height / " <<
info.viewBox.height() <<
" }";
532 m_inShapeItem =
false;
541 int indentWidth = m_indentLevel * 4;
542 if (indentWidth > indentString.
size())
549 if (m_stream.device() ==
nullptr)
550 m_stream.setDevice(&m_result);
551 else if (!(
flags & StreamFlags::SameLine))
556const char *QQuickQmlGenerator::shapeName()
const
bool open(OpenMode openMode) override
\reimp
const QByteArray & data() const
Returns the data contained in the buffer.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
QByteArray left(qsizetype n) const &
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
The QColor class provides colors based on RGB, HSV or CMYK values.
QString absolutePath() const
Returns the absolute path of the file system entry this QFileInfo refers to, excluding the entry's na...
Type type() const
Returns the type of gradient.
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Qt::FillRule fillRule() const
Returns the painter path's currently set fill rule.
void optimizePaths(const PathNodeInfo &info)
QQuickVectorImageGenerator::GeneratorFlags m_flags
bool isNodeVisible(const NodeInfo &info)
bool m_generationSucceeded
void outputShapePath(const PathNodeInfo &info, const QPainterPath *path, const QQuadPath *quadPath, QQuickVectorImageGenerator::PathSelector pathSelector, const QRectF &boundingRect) override
bool generateRootNode(const StructureNodeInfo &info) override
void setCommentString(const QString commentString)
void generateNode(const NodeInfo &info) override
void generateImageNode(const ImageNodeInfo &info) override
void generateNodeBase(const NodeInfo &info) override
QString shapeTypeName() const
void setShapeTypeName(const QString &name)
QString commentString() const
bool generateStructureNode(const StructureNodeInfo &info) override
void generateUseNode(const UseNodeInfo &info) override
QQuickQmlGenerator(const QString fileName, QQuickVectorImageGenerator::GeneratorFlags flags, const QString &outFileName)
void generatePath(const PathNodeInfo &info) override
bool generateDefsNode(const NodeInfo &info) override
void generateTextNode(const TextNodeInfo &info) override
\inmodule QtCore\reentrant
constexpr QStringView first(qsizetype n) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString & fill(QChar c, qsizetype size=-1)
Sets every character in the string to character ch.
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
qsizetype size() const noexcept
Returns the number of characters in this string.
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
constexpr QColor Transparent
QString strokeJoinStyleString(Qt::PenJoinStyle strokeJoinStyle)
QString strokeCapStyleString(Qt::PenCapStyle strokeCapStyle)
QRectF mapToQtLogicalMode(const QRectF &objModeRect, const QRectF &boundingRect)
QString listString(QList< T > list)
QString pathHintString(const QQuadPath &qp)
QString toSvgString(const QPainterPath &path)
Combined button and popup list for selecting options.
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
bool qFuzzyIsNull(qfloat16 f) noexcept
#define qCWarning(category,...)
#define qCDebug(category,...)
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat GLfloat GLfloat h
static const QRectF boundingRect(const QPointF *points, int pointCount)
QLatin1StringView QLatin1String
#define QStringLiteral(str)
static bool translate(xcb_connection_t *connection, xcb_window_t child, xcb_window_t parent, int *x, int *y)
\inmodule QtCore \reentrant