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 <KoClipPath.h>
#include <KoClipMask.h>
#include <KoXmlNS.h>
#include "SvgMeshGradient.h"
#include "SvgMeshPatch.h"
#include "SvgUtil.h"
#include "SvgShape.h"
#include "SvgGraphicContext.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 551 of file SvgParser.cpp.

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

Function Documentation

◆ applyDashes()

void applyDashes ( const KoShapeStrokeSP srcStroke,
KoShapeStrokeSP dstStroke )

Definition at line 1185 of file SvgParser.cpp.

1186{
1187 const double lineWidth = srcStroke->lineWidth();
1188 QVector<qreal> dashes = srcStroke->lineDashes();
1189
1190 // apply line width to dashes and dash offset
1191 if (dashes.count() && lineWidth > 0.0) {
1192 const double dashOffset = srcStroke->dashOffset();
1193 QVector<qreal> dashes = srcStroke->lineDashes();
1194
1195 for (int i = 0; i < dashes.count(); ++i) {
1196 dashes[i] /= lineWidth;
1197 }
1198
1199 dstStroke->setLineStyle(Qt::CustomDashLine, dashes);
1200 dstStroke->setDashOffset(dashOffset / lineWidth);
1201 } else {
1202 dstStroke->setLineStyle(Qt::SolidLine, QVector<qreal>());
1203 }
1204}

◆ bakeShapeOffset()

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

Definition at line 579 of file SvgParser.cpp.

580{
581 QTransform result =
582 patternTransform *
583 QTransform::fromTranslate(-shapeOffset.x(), -shapeOffset.y()) *
584 patternTransform.inverted();
585 KIS_ASSERT_RECOVER_NOOP(result.type() <= QTransform::TxTranslate);
586
587 return QPointF(result.dx(), result.dy());
588}
#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 1555 of file SvgParser.cpp.

1556{
1557 const QTransform shapeToOriginalUserCoordinates =
1558 shape->absoluteTransformation().inverted() *
1559 coordinateSystemOnLoading;
1560
1561 KIS_SAFE_ASSERT_RECOVER_NOOP(shapeToOriginalUserCoordinates.type() <= QTransform::TxTranslate);
1562 return QPointF(shapeToOriginalUserCoordinates.dx(), shapeToOriginalUserCoordinates.dy());
1563}
QTransform absoluteTransformation() const
Definition KoShape.cpp:335
#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 1002 of file SvgParser.cpp.

1006{
1007 QGradient *resultGradient = 0;
1008 KIS_ASSERT(transform);
1009
1010 if (gradient->gradientUnits() == KoFlake::ObjectBoundingBox) {
1011 resultGradient = KoFlake::cloneGradient(gradient->gradient());
1012 *transform = gradient->transform();
1013 } else {
1014 if (gradient->gradient()->type() == QGradient::LinearGradient) {
1020 const QRectF boundingRect = shape->outline().boundingRect();
1021 const QTransform relativeToShape(boundingRect.width(), 0, 0, boundingRect.height(),
1022 boundingRect.x(), boundingRect.y());
1023
1024 const QTransform relativeToUser =
1025 relativeToShape * shape->transformation() * gc->matrix.inverted();
1026
1027 const QTransform userToRelative = relativeToUser.inverted();
1028
1029 const QLinearGradient *o = static_cast<const QLinearGradient*>(gradient->gradient());
1030 QLinearGradient *g = new QLinearGradient();
1031 g->setStart(userToRelative.map(o->start()));
1032 g->setFinalStop(userToRelative.map(o->finalStop()));
1033 g->setCoordinateMode(QGradient::ObjectBoundingMode);
1034 g->setStops(o->stops());
1035 g->setSpread(o->spread());
1036
1037 resultGradient = g;
1038 *transform = relativeToUser * gradient->transform() * userToRelative;
1039
1040 } else if (gradient->gradient()->type() == QGradient::RadialGradient) {
1041 // For radial and conical gradients such conversion is not possible
1042
1043 resultGradient = KoFlake::cloneGradient(gradient->gradient());
1044 *transform = gradient->transform() * gc->matrix * shape->transformation().inverted();
1045
1046 const QRectF outlineRect = shape->outlineRect();
1047 if (outlineRect.isEmpty()) return resultGradient;
1048
1055 QRadialGradient *rgradient = static_cast<QRadialGradient*>(resultGradient);
1056
1057 const qreal maxDimension = KisAlgebra2D::maxDimension(outlineRect);
1058 const QRectF uniformSize(outlineRect.topLeft(), QSizeF(maxDimension, maxDimension));
1059
1060 const QTransform uniformizeTransform =
1061 QTransform::fromTranslate(-outlineRect.x(), -outlineRect.y()) *
1062 QTransform::fromScale(maxDimension / shape->outlineRect().width(),
1063 maxDimension / shape->outlineRect().height()) *
1064 QTransform::fromTranslate(outlineRect.x(), outlineRect.y());
1065
1066 const QPointF centerLocal = transform->map(rgradient->center());
1067 const QPointF focalLocal = transform->map(rgradient->focalPoint());
1068
1069 const QPointF centerOBB = KisAlgebra2D::absoluteToRelative(centerLocal, uniformSize);
1070 const QPointF focalOBB = KisAlgebra2D::absoluteToRelative(focalLocal, uniformSize);
1071
1072 rgradient->setCenter(centerOBB);
1073 rgradient->setFocalPoint(focalOBB);
1074
1075 const qreal centerRadiusOBB = KisAlgebra2D::absoluteToRelative(rgradient->centerRadius(), uniformSize);
1076 const qreal focalRadiusOBB = KisAlgebra2D::absoluteToRelative(rgradient->focalRadius(), uniformSize);
1077
1078 rgradient->setCenterRadius(centerRadiusOBB);
1079 rgradient->setFocalRadius(focalRadiusOBB);
1080
1081 rgradient->setCoordinateMode(QGradient::ObjectBoundingMode);
1082
1083 // Warning: should it really be pre-multiplication?
1084 *transform = uniformizeTransform * gradient->transform();
1085 }
1086 }
1087
1088 // NOTE: this is an internal API in Qt. SVG specs specify that we
1089 // shouldn't interpolate in pre-multiplied space.
1090 resultGradient->setInterpolationMode(QGradient::ComponentInterpolation);
1091
1092 return resultGradient;
1093}
virtual QRectF outlineRect() const
Definition KoShape.cpp:566
virtual QPainterPath outline() const
Definition KoShape.cpp:559
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:383
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 1095 of file SvgParser.cpp.

1097 {
1098
1099 SvgMeshGradient *resultGradient = nullptr;
1100
1101 if (gradient->gradientUnits() == KoFlake::ObjectBoundingBox) {
1102
1103 resultGradient = new SvgMeshGradient(*gradient->meshgradient());
1104
1105 const QRectF boundingRect = shape->outline().boundingRect();
1106 const QTransform relativeToShape(boundingRect.width(), 0, 0, boundingRect.height(),
1107 boundingRect.x(), boundingRect.y());
1108
1109 // NOTE: we apply translation right away, because caching hasn't been implemented for rendering, yet.
1110 // So, transform is called multiple times on the mesh and that's not nice
1111 resultGradient->setTransform(gradient->transform() * relativeToShape);
1112 } else {
1113 // NOTE: Krita's shapes use their own coordinate system. Where origin is at the top left
1114 // of the SHAPE. All the mesh patches will be rendered in the global 'user' coordinate system
1115 // where the origin is at the top left of the LAYER/DOCUMENT.
1116
1117 // Get the user coordinates of the shape
1118 const QTransform shapeglobal = shape->absoluteTransformation() * gc->matrix.inverted();
1119
1120 // Get the translation offset to shift the origin from "Shape" to "User"
1121 const QTransform translationOffset = QTransform::fromTranslate(-shapeglobal.dx(), -shapeglobal.dy());
1122
1123 resultGradient = new SvgMeshGradient(*gradient->meshgradient());
1124
1125 // NOTE: we apply translation right away, because caching hasn't been implemented for rendering, yet.
1126 // So, transform is called multiple times on the mesh and that's not nice
1127 resultGradient->setTransform(gradient->transform() * translationOffset);
1128 }
1129
1130 return resultGradient;
1131}
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().