Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgParser.cpp File Reference
#include "SvgParser.h"
#include <cmath>
#include <FlakeDebug.h>
#include <QColor>
#include <QDir>
#include <QPainter>
#include <QPainterPath>
#include <QRandomGenerator>
#include <KoShape.h>
#include <KoShapeRegistry.h>
#include <KoShapeFactoryBase.h>
#include <KoShapeGroup.h>
#include <KoPathShape.h>
#include <KoDocumentResourceManager.h>
#include <KoPathShapeLoader.h>
#include <commands/KoShapeGroupCommand.h>
#include <commands/KoShapeUngroupCommand.h>
#include <KoColorBackground.h>
#include <KoGradientBackground.h>
#include <KoMeshGradientBackground.h>
#include <KoPatternBackground.h>
#include <KoFilterEffectRegistry.h>
#include <KoFilterEffect.h>
#include "KoFilterEffectStack.h"
#include "KoFilterEffectLoadingContext.h"
#include <KoClipPath.h>
#include <KoClipMask.h>
#include <KoXmlNS.h>
#include <QXmlSimpleReader>
#include "SvgMeshGradient.h"
#include "SvgMeshPatch.h"
#include "SvgUtil.h"
#include "SvgShape.h"
#include "SvgGraphicContext.h"
#include "SvgFilterHelper.h"
#include "SvgGradientHelper.h"
#include "SvgClipPathHelper.h"
#include "parsers/SvgTransformParser.h"
#include "kis_pointer_utils.h"
#include <KoVectorPatternBackground.h>
#include <KoMarker.h>
#include <text/KoSvgTextShape.h>
#include <text/KoSvgTextLoader.h>
#include "kis_dom_utils.h"
#include "kis_algebra_2d.h"
#include "kis_debug.h"
#include "kis_global.h"
#include <QXmlStreamReader>
#include <algorithm>

Go to the source code of this file.

Classes

struct  SvgParser::DeferredUseStore
 
struct  SvgParser::DeferredUseStore::El
 

Macros

#define forEachElement(elem, parent)
 

Functions

void applyDashes (const KoShapeStrokeSP srcStroke, KoShapeStrokeSP dstStroke)
 
QPointF bakeShapeOffset (const QTransform &patternTransform, const QPointF &shapeOffset)
 
QPointF extraShapeOffset (const KoShape *shape, const QTransform coordinateSystemOnLoading)
 
QGradient * prepareGradientForShape (const SvgGradientHelper *gradient, const KoShape *shape, const SvgGraphicsContext *gc, QTransform *transform)
 
SvgMeshGradientprepareMeshGradientForShape (SvgGradientHelper *gradient, const KoShape *shape, const SvgGraphicsContext *gc)
 

Macro Definition Documentation

◆ forEachElement

#define forEachElement ( elem,
parent )
Value:
for ( QDomNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) \
if ( ( elem = _node.toElement() ).isNull() ) {} else

Definition at line 537 of file SvgParser.cpp.

537#define forEachElement( elem, parent ) \
538 for ( QDomNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) \
539 if ( ( elem = _node.toElement() ).isNull() ) {} else

Function Documentation

◆ applyDashes()

void applyDashes ( const KoShapeStrokeSP srcStroke,
KoShapeStrokeSP dstStroke )

Definition at line 1222 of file SvgParser.cpp.

1223{
1224 const double lineWidth = srcStroke->lineWidth();
1225 QVector<qreal> dashes = srcStroke->lineDashes();
1226
1227 // apply line width to dashes and dash offset
1228 if (dashes.count() && lineWidth > 0.0) {
1229 const double dashOffset = srcStroke->dashOffset();
1230 QVector<qreal> dashes = srcStroke->lineDashes();
1231
1232 for (int i = 0; i < dashes.count(); ++i) {
1233 dashes[i] /= lineWidth;
1234 }
1235
1236 dstStroke->setLineStyle(Qt::CustomDashLine, dashes);
1237 dstStroke->setDashOffset(dashOffset / lineWidth);
1238 } else {
1239 dstStroke->setLineStyle(Qt::SolidLine, QVector<qreal>());
1240 }
1241}

◆ bakeShapeOffset()

QPointF bakeShapeOffset ( const QTransform & patternTransform,
const QPointF & shapeOffset )
inline

Definition at line 565 of file SvgParser.cpp.

566{
567 QTransform result =
568 patternTransform *
569 QTransform::fromTranslate(-shapeOffset.x(), -shapeOffset.y()) *
570 patternTransform.inverted();
571 KIS_ASSERT_RECOVER_NOOP(result.type() <= QTransform::TxTranslate);
572
573 return QPointF(result.dx(), result.dy());
574}
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97

References KIS_ASSERT_RECOVER_NOOP.

◆ extraShapeOffset()

QPointF extraShapeOffset ( const KoShape * shape,
const QTransform coordinateSystemOnLoading )
inline

Definition at line 1720 of file SvgParser.cpp.

1721{
1722 const QTransform shapeToOriginalUserCoordinates =
1723 shape->absoluteTransformation().inverted() *
1724 coordinateSystemOnLoading;
1725
1726 KIS_SAFE_ASSERT_RECOVER_NOOP(shapeToOriginalUserCoordinates.type() <= QTransform::TxTranslate);
1727 return QPointF(shapeToOriginalUserCoordinates.dx(), shapeToOriginalUserCoordinates.dy());
1728}
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130

References KoShape::absoluteTransformation(), and KIS_SAFE_ASSERT_RECOVER_NOOP.

◆ prepareGradientForShape()

QGradient * prepareGradientForShape ( const SvgGradientHelper * gradient,
const KoShape * shape,
const SvgGraphicsContext * gc,
QTransform * transform )

Create a converted gradient that looks the same, but linked to the bounding rect of the shape, so it would be transformed with the shape

If shape outline rect is valid, convert the gradient into OBB mode by doing some magic conversions: we compensate non-uniform size of the shape by applying an additional pre-transform

Definition at line 1039 of file SvgParser.cpp.

1043{
1044 QGradient *resultGradient = 0;
1045 KIS_ASSERT(transform);
1046
1047 if (gradient->gradientUnits() == KoFlake::ObjectBoundingBox) {
1048 resultGradient = KoFlake::cloneGradient(gradient->gradient());
1049 *transform = gradient->transform();
1050 } else {
1051 if (gradient->gradient()->type() == QGradient::LinearGradient) {
1057 const QRectF boundingRect = shape->outline().boundingRect();
1058 const QTransform relativeToShape(boundingRect.width(), 0, 0, boundingRect.height(),
1059 boundingRect.x(), boundingRect.y());
1060
1061 const QTransform relativeToUser =
1062 relativeToShape * shape->transformation() * gc->matrix.inverted();
1063
1064 const QTransform userToRelative = relativeToUser.inverted();
1065
1066 const QLinearGradient *o = static_cast<const QLinearGradient*>(gradient->gradient());
1067 QLinearGradient *g = new QLinearGradient();
1068 g->setStart(userToRelative.map(o->start()));
1069 g->setFinalStop(userToRelative.map(o->finalStop()));
1070 g->setCoordinateMode(QGradient::ObjectBoundingMode);
1071 g->setStops(o->stops());
1072 g->setSpread(o->spread());
1073
1074 resultGradient = g;
1075 *transform = relativeToUser * gradient->transform() * userToRelative;
1076
1077 } else if (gradient->gradient()->type() == QGradient::RadialGradient) {
1078 // For radial and conical gradients such conversion is not possible
1079
1080 resultGradient = KoFlake::cloneGradient(gradient->gradient());
1081 *transform = gradient->transform() * gc->matrix * shape->transformation().inverted();
1082
1083 const QRectF outlineRect = shape->outlineRect();
1084 if (outlineRect.isEmpty()) return resultGradient;
1085
1092 QRadialGradient *rgradient = static_cast<QRadialGradient*>(resultGradient);
1093
1094 const qreal maxDimension = KisAlgebra2D::maxDimension(outlineRect);
1095 const QRectF uniformSize(outlineRect.topLeft(), QSizeF(maxDimension, maxDimension));
1096
1097 const QTransform uniformizeTransform =
1098 QTransform::fromTranslate(-outlineRect.x(), -outlineRect.y()) *
1099 QTransform::fromScale(maxDimension / shape->outlineRect().width(),
1100 maxDimension / shape->outlineRect().height()) *
1101 QTransform::fromTranslate(outlineRect.x(), outlineRect.y());
1102
1103 const QPointF centerLocal = transform->map(rgradient->center());
1104 const QPointF focalLocal = transform->map(rgradient->focalPoint());
1105
1106 const QPointF centerOBB = KisAlgebra2D::absoluteToRelative(centerLocal, uniformSize);
1107 const QPointF focalOBB = KisAlgebra2D::absoluteToRelative(focalLocal, uniformSize);
1108
1109 rgradient->setCenter(centerOBB);
1110 rgradient->setFocalPoint(focalOBB);
1111
1112 const qreal centerRadiusOBB = KisAlgebra2D::absoluteToRelative(rgradient->centerRadius(), uniformSize);
1113 const qreal focalRadiusOBB = KisAlgebra2D::absoluteToRelative(rgradient->focalRadius(), uniformSize);
1114
1115 rgradient->setCenterRadius(centerRadiusOBB);
1116 rgradient->setFocalRadius(focalRadiusOBB);
1117
1118 rgradient->setCoordinateMode(QGradient::ObjectBoundingMode);
1119
1120 // Warning: should it really be pre-multiplication?
1121 *transform = uniformizeTransform * gradient->transform();
1122 }
1123 }
1124
1125 // NOTE: this is an internal API in Qt. SVG specs specify that we
1126 // shouldn't interpolate in pre-multiplied space.
1127 resultGradient->setInterpolationMode(QGradient::ComponentInterpolation);
1128
1129 return resultGradient;
1130}
virtual QRectF outlineRect() const
Definition KoShape.cpp:637
virtual QPainterPath outline() const
Definition KoShape.cpp:630
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:424
QGradient * gradient() const
Returns the gradient.
KoFlake::CoordinateSystem gradientUnits() const
Returns gradient units type.
QTransform transform() const
Returns the gradient transformation.
QTransform matrix
the current transformation matrix
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
auto maxDimension(Size size) -> decltype(size.width())
QPointF absoluteToRelative(const QPointF &pt, const QRectF &rc)
KRITAFLAKE_EXPORT QGradient * cloneGradient(const QGradient *gradient)
clones the given gradient
Definition KoFlake.cpp:17

References KisAlgebra2D::absoluteToRelative(), KoFlake::cloneGradient(), SvgGradientHelper::gradient(), SvgGradientHelper::gradientUnits(), KIS_ASSERT, SvgGraphicsContext::matrix, KisAlgebra2D::maxDimension(), KoFlake::ObjectBoundingBox, KoShape::outline(), KoShape::outlineRect(), SvgGradientHelper::transform(), and KoShape::transformation().

◆ prepareMeshGradientForShape()

SvgMeshGradient * prepareMeshGradientForShape ( SvgGradientHelper * gradient,
const KoShape * shape,
const SvgGraphicsContext * gc )

Definition at line 1132 of file SvgParser.cpp.

1134 {
1135
1136 SvgMeshGradient *resultGradient = nullptr;
1137
1138 if (gradient->gradientUnits() == KoFlake::ObjectBoundingBox) {
1139
1140 resultGradient = new SvgMeshGradient(*gradient->meshgradient());
1141
1142 const QRectF boundingRect = shape->outline().boundingRect();
1143 const QTransform relativeToShape(boundingRect.width(), 0, 0, boundingRect.height(),
1144 boundingRect.x(), boundingRect.y());
1145
1146 // NOTE: we apply translation right away, because caching hasn't been implemented for rendering, yet.
1147 // So, transform is called multiple times on the mesh and that's not nice
1148 resultGradient->setTransform(gradient->transform() * relativeToShape);
1149 } else {
1150 // NOTE: Krita's shapes use their own coordinate system. Where origin is at the top left
1151 // of the SHAPE. All the mesh patches will be rendered in the global 'user' coordinate system
1152 // where the origin is at the top left of the LAYER/DOCUMENT.
1153
1154 // Get the user coordinates of the shape
1155 const QTransform shapeglobal = shape->absoluteTransformation() * gc->matrix.inverted();
1156
1157 // Get the translation offset to shift the origin from "Shape" to "User"
1158 const QTransform translationOffset = QTransform::fromTranslate(-shapeglobal.dx(), -shapeglobal.dy());
1159
1160 resultGradient = new SvgMeshGradient(*gradient->meshgradient());
1161
1162 // NOTE: we apply translation right away, because caching hasn't been implemented for rendering, yet.
1163 // So, transform is called multiple times on the mesh and that's not nice
1164 resultGradient->setTransform(gradient->transform() * translationOffset);
1165 }
1166
1167 return resultGradient;
1168}
QScopedPointer< SvgMeshGradient > & meshgradient()
Returns the meshgradient.
void setTransform(const QTransform &matrix)

References KoShape::absoluteTransformation(), SvgGradientHelper::gradientUnits(), SvgGraphicsContext::matrix, SvgGradientHelper::meshgradient(), KoFlake::ObjectBoundingBox, KoShape::outline(), SvgMeshGradient::setTransform(), and SvgGradientHelper::transform().