VectorImage: Add support for gradient/fill transforms

Handle the SVG gradientTransform and patternTransform attributes.

Fixes: QTBUG-121661
Pick-to: 6.8
Change-Id: I79d85ebfef46527e2909440aaca94c975bf21a47
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Reviewed-by: Hatem ElKharashy <hatem.elkharashy@qt.io>
This commit is contained in:
Eirik Aavitsland 2024-06-12 16:15:48 +02:00
parent ab359c11e1
commit 10637de078
7 changed files with 136 additions and 11 deletions

View File

@ -161,6 +161,8 @@ void QQuickItemGenerator::outputShapePath(const PathNodeInfo &info, const QPaint
shapePath->setFillColor(info.fillColor);
shapePath->setFillRule(fillRule);
if (!info.fillTransform.isIdentity())
shapePath->setFillTransform(info.fillTransform);
QString svgPathString = painterPath ? QQuickVectorImageGenerator::Utils::toSvgString(*painterPath) : QQuickVectorImageGenerator::Utils::toSvgString(*quadPath);

View File

@ -76,6 +76,7 @@ struct PathNodeInfo : NodeInfo
QColor fillColor;
StrokeStyle strokeStyle;
QGradient grad;
QTransform fillTransform;
};
struct TextNodeInfo : NodeInfo

View File

@ -80,17 +80,9 @@ void QQuickQmlGenerator::generateNodeBase(const NodeInfo &info)
} else if (info.transform.type() == QTransform::TxScale && !x && !y) {
stream() << "transform: Scale { xScale: " << sx << "; yScale: " << sy << " }";
} else {
const QMatrix4x4 m(info.transform);
{
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;
}
stream() << "transform: Matrix4x4 { matrix: ";
generateTransform(info.transform);
stream(SameLine) << " }";
}
}
if (!info.isDefaultOpacity) {
@ -222,6 +214,28 @@ void QQuickQmlGenerator::generateGradient(const QGradient *grad, const QRectF &b
}
}
void QQuickQmlGenerator::generateTransform(const QTransform &xf)
{
if (xf.isAffine()) {
stream(SameLine) << "PlanarTransform.fromAffineMatrix("
<< xf.m11() << ", " << xf.m12() << ", "
<< xf.m21() << ", " << xf.m22() << ", "
<< xf.dx() << ", " << xf.dy() << ")";
} else {
QMatrix4x4 m(xf);
stream(SameLine) << "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];
if (i < 3)
stream(SameLine) << ", ";
}
stream(SameLine) << ")";
m_indentLevel -= 3;
}
}
void QQuickQmlGenerator::outputShapePath(const PathNodeInfo &info, const QPainterPath *painterPath, const QQuadPath *quadPath, QQuickVectorImageGenerator::PathSelector pathSelector, const QRectF &boundingRect)
{
Q_UNUSED(pathSelector)
@ -275,6 +289,18 @@ void QQuickQmlGenerator::outputShapePath(const PathNodeInfo &info, const QPainte
} else {
stream() << "fillColor: \"" << info.fillColor.name(QColor::HexArgb) << "\"";
}
if (!info.fillTransform.isIdentity()) {
const QTransform &xf = info.fillTransform;
stream() << "fillTransform: ";
if (info.fillTransform.type() == QTransform::TxTranslate)
stream(SameLine) << "PlanarTransform.fromTranslate(" << xf.dx() << ", " << xf.dy() << ")";
else if (info.fillTransform.type() == QTransform::TxScale && !xf.dx() && !xf.dy())
stream(SameLine) << "PlanarTransform.fromScale(" << xf.m11() << ", " << xf.m22() << ")";
else
generateTransform(xf);
}
if (fillRule == QQuickShapePath::WindingFill)
stream() << "fillRule: ShapePath.WindingFill";
else

View File

@ -78,6 +78,7 @@ protected:
private:
void generateGradient(const QGradient *grad, const QRectF &boundingRect);
void generateTransform(const QTransform &xf);
QStringView indent();
enum StreamFlags { NoFlags = 0x0, SameLine = 0x1 };

View File

@ -81,6 +81,11 @@ public:
return nullptr;
}
QTransform currentFillTransform() const
{
return m_dummyPainter.brush().transform();
}
QColor currentStrokeColor() const
{
if (m_dummyPainter.pen().brush().style() == Qt::NoBrush ||
@ -606,6 +611,8 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
if (info.grad.type() == QGradient::NoGradient && styleResolver->currentFillGradient() != nullptr)
info.grad = styleResolver->applyOpacityToGradient(*styleResolver->currentFillGradient(), styleResolver->currentFillOpacity());
info.fillTransform = styleResolver->currentFillTransform();
m_generator->generatePath(info);
};
@ -819,6 +826,7 @@ void QSvgVisitorImpl::handlePathNode(const QSvgNode *node, const QPainterPath &p
info.strokeStyle.color = styleResolver->currentStrokeColor();
if (styleResolver->currentFillGradient() != nullptr)
info.grad = styleResolver->applyOpacityToGradient(*styleResolver->currentFillGradient(), styleResolver->currentFillOpacity());
info.fillTransform = styleResolver->currentFillTransform();
m_generator->generatePath(info);

View File

@ -0,0 +1,62 @@
<svg viewBox="0 0 380 800" xmlns="http://www.w3.org/2000/svg">
<radialGradient
id="gradient1"
gradientUnits="userSpaceOnUse"
cx="100"
cy="100"
r="100"
fx="100"
fy="100"
gradientTransform="translate(100 0)">
<stop offset="0%" stop-color="darkblue" />
<stop offset="50%" stop-color="skyblue" />
<stop offset="100%" stop-color="darkblue" />
</radialGradient>
<radialGradient
id="gradient2"
gradientUnits="userSpaceOnUse"
cx="100"
cy="100"
r="100"
fx="100"
fy="100"
gradientTransform="scale(2 1)">
<stop offset="0%" stop-color="darkblue" />
<stop offset="50%" stop-color="skyblue" />
<stop offset="100%" stop-color="darkblue" />
</radialGradient>
<radialGradient
id="gradient3"
gradientUnits="userSpaceOnUse"
cx="100"
cy="100"
r="100"
fx="100"
fy="100"
gradientTransform="skewX(40)">
<stop offset="0%" stop-color="darkblue" />
<stop offset="50%" stop-color="skyblue" />
<stop offset="100%" stop-color="darkblue" />
</radialGradient>
<rect x="0" y="0" width="300" height="100" fill="url(#gradient1)" />
<text font-size="124" x="0" y="200" stroke="black" fill="url(#gradient1)">XLAT</text>
<g transform="translate(0 250)">
<rect x="0" y="0" width="300" height="100" fill="url(#gradient2)" />
<text font-size="124" x="0" y="200" stroke="black" fill="url(#gradient2)">SCAL</text>
</g>
<g transform="translate(0 500)">
<rect x="0" y="0" width="300" height="100" fill="url(#gradient3)" />
<text font-size="124" x="0" y="200" stroke="black" fill="url(#gradient3)">SKEW</text>
</g>
<!--
<g font-family="Arial" font-size="92" transform="translate(50 0)">
<text x="0" y="100" stroke="black" fill="url(#gradient1)">TEST</text>
</g>
-->
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,25 @@
import QtQuick
import QtQuick.VectorImage
Rectangle {
id: topLevelItem
width: 800
height: 800
ListModel {
id: renderers
ListElement { renderer: VectorImage.GeometryRenderer }
ListElement { renderer: VectorImage.CurveRenderer }
}
Row {
Repeater {
model: renderers
VectorImage {
source: "../shared/svg/gradientxform.svg"
preferredRendererType: renderer
}
}
}
}