Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgParser Class Reference

#include <SvgParser.h>

Classes

struct  DeferredUseStore
 

Public Types

typedef std::function< QByteArray(const QString &) FileFetcherFunc)
 

Public Member Functions

QString documentDescription () const
 
QString documentTitle () const
 
QList< QExplicitlySharedDataPointer< KoMarker > > knownMarkers () const
 
void parseDefsElement (const QDomElement &e)
 
QList< KoShape * > parseSvg (const QDomElement &e, QSizeF *fragmentSize=0)
 Parses a svg fragment, returning the list of top level child shapes.
 
KoShapeparseTextElement (const QDomElement &e, KoSvgTextShape *mergeIntoShape=0)
 
void setDefaultKraTextVersion (int version)
 
void setFileFetcher (FileFetcherFunc func)
 
void setFillStrokeInheritByDefault (const bool enable)
 
void setResolution (const QRectF boundsInPixels, qreal pixelsPerInch)
 
void setResolveTextPropertiesForTopLevel (const bool enable)
 
void setXmlBaseDir (const QString &baseDir)
 Sets the initial xml base directory (the directory form where the file is read)
 
QList< KoShape * > shapes () const
 Returns the list of all shapes of the svg document.
 
 SvgParser (KoDocumentResourceManager *documentResourceManager)
 
QVector< KoSvgSymbol * > takeSymbols ()
 
QStringList warnings () const
 
virtual ~SvgParser ()
 

Static Public Member Functions

static QDomDocument createDocumentFromSvg (const QByteArray &data, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0)
 
static QDomDocument createDocumentFromSvg (const QString &data, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0)
 
static QDomDocument createDocumentFromSvg (QIODevice *device, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0)
 
static QDomDocument createDocumentFromSvg (QXmlStreamReader reader, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0)
 

Protected Member Functions

void addToGroup (QList< KoShape * > shapes, KoShapeContainer *group)
 Adds list of shapes to the given group shape.
 
void applyClipping (KoShape *shape, const QPointF &shapeToOriginalUserCoordinates)
 Applies the current clip path to the object.
 
void applyCurrentBasicStyle (KoShape *shape)
 
void applyCurrentStyle (KoShape *shape, const QPointF &shapeToOriginalUserCoordinates)
 
void applyFillStyle (KoShape *shape)
 Applies the current fill style to the object.
 
void applyId (const QString &id, KoShape *shape)
 Applies id to specified shape.
 
void applyMarkers (KoPathShape *shape)
 
void applyMaskClipping (KoShape *shape, const QPointF &shapeToOriginalUserCoordinates)
 
void applyPaintOrder (KoShape *shape)
 
void applyStrokeStyle (KoShape *shape)
 Applies the current stroke style to the object.
 
void applyStyle (KoShape *, const QDomElement &, const QPointF &shapeToOriginalUserCoordinates)
 Applies styles to the given shape.
 
void applyStyle (KoShape *, const SvgStyles &, const QPointF &shapeToOriginalUserCoordinates)
 Applies styles to the given shape.
 
void applyViewBoxTransform (const QDomElement &element)
 
void buildDocument (QList< KoShape * > shapes)
 Builds the document from the given shapes list.
 
QList< KoShape * > createListOfShapesFromCSS (const QDomElement e, const QString value, SvgLoadingContext &context, bool hideShapesFromDefs=true)
 Create a list of shapes from a CSS shapes definition with potentially multiple shapes.
 
KoShapecreateObject (const QDomElement &, const SvgStyles &style=SvgStyles())
 Creates an object from the given xml element.
 
KoShapecreateObjectDirect (const QDomElement &b)
 
KoShapecreatePath (const QDomElement &)
 Create path object from the given xml element.
 
KoShapecreateShape (const QString &shapeID)
 creates a shape from the given shape id
 
KoShapecreateShapeFromCSS (const QDomElement e, const QString value, SvgLoadingContext &context, bool hideShapesFromDefs=true)
 Creates a shape from a CSS shapes definition.
 
KoShapecreateShapeFromElement (const QDomElement &element, SvgLoadingContext &context)
 Creates shape from specified svg element.
 
SvgClipPathHelperfindClipPath (const QString &id)
 find clip path with given id in clip path map
 
SvgGradientHelperfindGradient (const QString &id)
 find gradient with given id in gradient map
 
QSharedPointer< KoVectorPatternBackgroundfindPattern (const QString &id, const KoShape *shape)
 find pattern with given id in pattern map
 
KoShapegetTextPath (const QDomElement &e, bool hideShapesFromDefs=true)
 Get the path for the gives textPath element.
 
QDomText getTheOnlyTextChild (const QDomElement &e)
 
qreal parseAngular (const QString &unit)
 parses a angular attribute values, result in radians
 
bool parseClipMask (const QDomElement &e)
 
bool parseClipPath (const QDomElement &)
 Parses a clip path element.
 
QList< KoShape * > parseContainer (const QDomElement &)
 Parses a container element, returning a list of child shapes.
 
bool parseFilter (const QDomElement &, const QDomElement &referencedBy=QDomElement())
 Parses a filter element.
 
SvgGradientHelperparseGradient (const QDomElement &)
 Parses a gradient element.
 
KoShapeparseGroup (const QDomElement &e, const QDomElement &overrideChildrenFrom=QDomElement(), bool createContext=true)
 Parses a group-like element element, saving all its topmost properties.
 
bool parseMarker (const QDomElement &e)
 
SvgGradientHelperparseMeshGradient (const QDomElement &)
 Parses mesh gradient element.
 
QList< QPair< QString, QColor > > parseMeshPatch (const QDomNode &meshpatch)
 Parses a single meshpatch and returns the pointer.
 
void parseMetadataApplyToShape (const QDomElement &e, KoShape *shape)
 This parses the SVG native title and desc elements and adds them into additional attributes.
 
QSharedPointer< KoVectorPatternBackgroundparsePattern (const QDomElement &e, const KoShape *__shape)
 Parses a pattern element.
 
QList< KoShape * > parseSingleElement (const QDomElement &b, DeferredUseStore *deferredUseStore=0)
 XXX.
 
bool parseSymbol (const QDomElement &e)
 
void parseTextChildren (const QDomElement &e, KoSvgTextLoader &textLoader, bool hideShapesFromDefs=true)
 parse children of a <text > element into the root shape.
 
qreal parseUnit (const QString &, bool horiz=false, bool vert=false, const QRectF &bbox=QRectF())
 parses a length attribute
 
qreal parseUnitX (const QString &unit)
 parses a length attribute in x-direction
 
qreal parseUnitXY (const QString &unit)
 parses a length attribute in xy-direction
 
qreal parseUnitY (const QString &unit)
 parses a length attribute in y-direction
 
KoShapeparseUse (const QDomElement &, DeferredUseStore *deferredUseStore)
 Parses a use element, returning a list of child shapes.
 
KoShaperesolveUse (const QDomElement &e, const QString &key)
 
bool shapeInDefs (const KoShape *shape)
 Check whether the shapes are in the defs of the SVG document.
 
void uploadStyleToContext (const QDomElement &e)
 

Private Attributes

QMap< QString, QSharedPointer< KoClipMask > > m_clipMasks
 
QMap< QString, SvgClipPathHelperm_clipPaths
 
SvgLoadingContext m_context
 
QList< KoShape * > m_defsShapes
 
QString m_documentDescription
 
KoDocumentResourceManagerm_documentResourceManager
 
QString m_documentTitle
 
QMap< QString, SvgGradientHelperm_gradients
 
bool m_inheritStrokeFillByDefault = false
 
bool m_isInsideTextSubtree = false
 
QMap< QString, QExplicitlySharedDataPointer< KoMarker > > m_markers
 
bool m_resolveTextPropertiesForTopLevel = true
 
QMap< KoShape *, QTransform > m_shapeParentTransform
 
QList< KoShape * > m_shapes
 
QMap< QString, KoSvgSymbol * > m_symbols
 
QVector< KoIDm_warnings
 

Detailed Description

Definition at line 38 of file SvgParser.h.

Member Typedef Documentation

◆ FileFetcherFunc

typedef std::function<QByteArray(const QString&) SvgParser::FileFetcherFunc)

Definition at line 81 of file SvgParser.h.

Constructor & Destructor Documentation

◆ SvgParser()

SvgParser::SvgParser ( KoDocumentResourceManager * documentResourceManager)
explicit

Definition at line 126 of file SvgParser.cpp.

127 : m_context(documentResourceManager)
128 , m_documentResourceManager(documentResourceManager)
129{
130}
KoDocumentResourceManager * m_documentResourceManager
Definition SvgParser.h:230
SvgLoadingContext m_context
Definition SvgParser.h:225

◆ ~SvgParser()

SvgParser::~SvgParser ( )
virtual

Definition at line 132 of file SvgParser.cpp.

133{
134 for (auto it = m_symbols.begin(); it != m_symbols.end(); ++it) {
135 delete it.value();
136 }
137 qDeleteAll(m_defsShapes);
138}
QList< KoShape * > m_defsShapes
Definition SvgParser.h:233
QMap< QString, KoSvgSymbol * > m_symbols
Definition SvgParser.h:232

References m_defsShapes, and m_symbols.

Member Function Documentation

◆ addToGroup()

void SvgParser::addToGroup ( QList< KoShape * > shapes,
KoShapeContainer * group )
protected

Adds list of shapes to the given group shape.

Definition at line 1399 of file SvgParser.cpp.

1400{
1401 m_shapes += shapes;
1402
1403 if (!group || shapes.isEmpty())
1404 return;
1405
1406 // not normalized
1407 KoShapeGroupCommand cmd(group, shapes, false);
1408 cmd.redo();
1409}
The undo / redo command for grouping shapes.
QList< KoShape * > shapes() const
Returns the list of all shapes of the svg document.
QList< KoShape * > m_shapes
Definition SvgParser.h:231

References m_shapes, KoShapeGroupCommand::redo(), and shapes().

◆ applyClipping()

void SvgParser::applyClipping ( KoShape * shape,
const QPointF & shapeToOriginalUserCoordinates )
protected

Applies the current clip path to the object.

Definition at line 1306 of file SvgParser.cpp.

1307{
1309 if (! gc)
1310 return;
1311
1312 if (gc->clipPathId.isEmpty())
1313 return;
1314
1315 SvgClipPathHelper *clipPath = findClipPath(gc->clipPathId);
1316 if (!clipPath || clipPath->isEmpty())
1317 return;
1318
1320
1321 Q_FOREACH (KoShape *item, clipPath->shapes()) {
1322 KoShape *clonedShape = item->cloneShape();
1323 KIS_ASSERT_RECOVER(clonedShape) { continue; }
1324
1325 shapes.append(clonedShape);
1326 }
1327
1328 if (!shapeToOriginalUserCoordinates.isNull()) {
1329 const QTransform t =
1330 QTransform::fromTranslate(shapeToOriginalUserCoordinates.x(),
1331 shapeToOriginalUserCoordinates.y());
1332
1333 Q_FOREACH(KoShape *s, shapes) {
1335 }
1336 }
1337
1338 KoClipPath *clipPathObject = new KoClipPath(shapes,
1341 shape->setClipPath(clipPathObject);
1342}
Clip path used to clip shapes.
void applyAbsoluteTransformation(const QTransform &matrix)
Definition KoShape.cpp:348
void setClipPath(KoClipPath *clipPath)
Sets a new clip path, removing the old one.
Definition KoShape.cpp:921
virtual KoShape * cloneShape() const
creates a deep copy of the shape or shape's subtree
Definition KoShape.cpp:173
KoFlake::CoordinateSystem clipPathUnits() const
Returns the clip path units type.
QList< KoShape * > shapes() const
QString clipPathId
the current clip path id
SvgGraphicsContext * currentGC() const
Returns the current graphics context.
SvgClipPathHelper * findClipPath(const QString &id)
find clip path with given id in clip path map
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55

References KoShape::applyAbsoluteTransformation(), SvgGraphicsContext::clipPathId, SvgClipPathHelper::clipPathUnits(), KoShape::cloneShape(), SvgLoadingContext::currentGC(), findClipPath(), SvgClipPathHelper::isEmpty(), KIS_ASSERT_RECOVER, m_context, KoFlake::ObjectBoundingBox, KoShape::setClipPath(), SvgClipPathHelper::shapes(), shapes(), and KoFlake::UserSpaceOnUse.

◆ applyCurrentBasicStyle()

void SvgParser::applyCurrentBasicStyle ( KoShape * shape)
protected

WARNING: here is a small inconsistency with the standard: in the standard, 'display' is not inherited, but in flake it is!

NOTE: though the standard says: "A value of 'display:none' indicates that the given element and <em><strong>its children</strong></em> shall not be rendered directly". Therefore, using setVisible(false) is fully legitimate here (DK 29.11.16).

Definition at line 935 of file SvgParser.cpp.

936{
937 if (!shape) return;
938
940 KIS_ASSERT(gc);
941
942 if (!dynamic_cast<KoShapeGroup*>(shape)) {
943 applyFillStyle(shape);
944 applyStrokeStyle(shape);
945 }
946
947 if (!gc->display || !gc->visible) {
958 shape->setVisible(false);
959 }
960 shape->setTransparency(1.0 - gc->opacity);
961
962 applyPaintOrder(shape);
963}
void setTransparency(qreal transparency)
Definition KoShape.cpp:637
void setVisible(bool on)
Definition KoShape.cpp:790
bool visible
controls visibility of the shape (inherited)
bool display
controls display of shape
qreal opacity
the shapes opacity
void applyFillStyle(KoShape *shape)
Applies the current fill style to the object.
void applyStrokeStyle(KoShape *shape)
Applies the current stroke style to the object.
void applyPaintOrder(KoShape *shape)
#define KIS_ASSERT(cond)
Definition kis_assert.h:33

References applyFillStyle(), applyPaintOrder(), applyStrokeStyle(), SvgLoadingContext::currentGC(), SvgGraphicsContext::display, KIS_ASSERT, m_context, SvgGraphicsContext::opacity, KoShape::setTransparency(), KoShape::setVisible(), and SvgGraphicsContext::visible.

◆ applyCurrentStyle()

void SvgParser::applyCurrentStyle ( KoShape * shape,
const QPointF & shapeToOriginalUserCoordinates )
protected

Definition at line 920 of file SvgParser.cpp.

921{
922 if (!shape) return;
923
925
926 if (KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape)) {
927 applyMarkers(pathShape);
928 }
929
930 applyClipping(shape, shapeToOriginalUserCoordinates);
931 applyMaskClipping(shape, shapeToOriginalUserCoordinates);
932
933}
The position of a path point within a path shape.
Definition KoPathShape.h:63
void applyCurrentBasicStyle(KoShape *shape)
void applyMarkers(KoPathShape *shape)
void applyClipping(KoShape *shape, const QPointF &shapeToOriginalUserCoordinates)
Applies the current clip path to the object.
void applyMaskClipping(KoShape *shape, const QPointF &shapeToOriginalUserCoordinates)

References applyClipping(), applyCurrentBasicStyle(), applyMarkers(), and applyMaskClipping().

◆ applyFillStyle()

void SvgParser::applyFillStyle ( KoShape * shape)
protected

Applies the current fill style to the object.

Definition at line 1134 of file SvgParser.cpp.

1135{
1137 if (! gc)
1138 return;
1139
1142 } else if (gc->fillType == SvgGraphicsContext::Solid) {
1144 } else if (gc->fillType == SvgGraphicsContext::Complex) {
1145 // try to find referenced gradient
1146 SvgGradientHelper *gradient = findGradient(gc->fillId);
1147 if (gradient) {
1148 QTransform transform;
1149
1150 if (gradient->isMeshGradient()) {
1152
1153 QScopedPointer<SvgMeshGradient> result(prepareMeshGradientForShape(gradient, shape, gc));
1154
1155 bg = toQShared(new KoMeshGradientBackground(result.data(), transform));
1156 shape->setBackground(bg);
1157 } else if (gradient->gradient()) {
1158 QGradient *result = prepareGradientForShape(gradient, shape, gc, &transform);
1159 if (result) {
1161 bg = toQShared(new KoGradientBackground(result));
1162 bg->setTransform(transform);
1163 shape->setBackground(bg);
1164 }
1165 }
1166 } else {
1168 findPattern(gc->fillId, shape);
1169
1170 if (pattern) {
1171 shape->setBackground(pattern);
1172 } else {
1173 // no referenced fill found, use fallback color
1175 }
1176 }
1177 } else if (gc->fillType == SvgGraphicsContext::Inherit) {
1178 shape->setInheritBackground(true);
1179 }
1180
1181 KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
1182 if (path)
1183 path->setFillRule(gc->fillRule);
1184}
QGradient * prepareGradientForShape(const SvgGradientHelper *gradient, const KoShape *shape, const SvgGraphicsContext *gc, QTransform *transform)
SvgMeshGradient * prepareMeshGradientForShape(SvgGradientHelper *gradient, const KoShape *shape, const SvgGraphicsContext *gc)
A simple solid color shape background.
A gradient shape background.
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule to be used for painting the background.
void setInheritBackground(bool value)
setInheritBackground marks a shape as inheriting the background from the parent shape....
Definition KoShape.cpp:768
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
Definition KoShape.cpp:746
QGradient * gradient() const
Returns the gradient.
bool isMeshGradient() const
Qt::FillRule fillRule
the current fill rule
QString fillId
the current fill id (used for gradient/pattern fills)
StyleType fillType
the current fill type
@ Complex
gradient or pattern style
QColor fillColor
the current fill color. Default is black fill as per svg spec
QSharedPointer< KoVectorPatternBackground > findPattern(const QString &id, const KoShape *shape)
find pattern with given id in pattern map
SvgGradientHelper * findGradient(const QString &id)
find gradient with given id in gradient map
QSharedPointer< T > toQShared(T *ptr)

References SvgGraphicsContext::Complex, SvgLoadingContext::currentGC(), SvgGraphicsContext::fillColor, SvgGraphicsContext::fillId, SvgGraphicsContext::fillRule, SvgGraphicsContext::fillType, findGradient(), findPattern(), SvgGradientHelper::gradient(), SvgGraphicsContext::Inherit, SvgGradientHelper::isMeshGradient(), m_context, SvgGraphicsContext::None, prepareGradientForShape(), prepareMeshGradientForShape(), KoShape::setBackground(), KoPathShape::setFillRule(), KoShape::setInheritBackground(), SvgGraphicsContext::Solid, and toQShared().

◆ applyId()

void SvgParser::applyId ( const QString & id,
KoShape * shape )
protected

Applies id to specified shape.

Definition at line 2238 of file SvgParser.cpp.

2239{
2240 if (id.isEmpty())
2241 return;
2242
2243 KoShape *existingShape = m_context.shapeById(id);
2244 if (existingShape) {
2245 debugFlake << "SVG contains nodes with duplicated id:" << id;
2246 // Generate a random name and just don't register the shape.
2247 // We don't use the name as a unique identifier so we don't need to
2248 // worry about the extremely rare case of name collision.
2249 const QString suffix = QString::number(QRandomGenerator::system()->bounded(0x10000000, 0x7FFFFFFF), 16);
2250 const QString newName = id + '_' + suffix;
2251 shape->setName(newName);
2252 } else {
2253 shape->setName(id);
2254 m_context.registerShape(id, shape);
2255 }
2256}
#define debugFlake
Definition FlakeDebug.h:15
void setName(const QString &name)
Definition KoShape.cpp:955
void registerShape(const QString &id, KoShape *shape)
Registers a shape so it can be referenced later.
KoShape * shapeById(const QString &id)
Returns shape with specified id.

References debugFlake, m_context, SvgLoadingContext::registerShape(), KoShape::setName(), and SvgLoadingContext::shapeById().

◆ applyMarkers()

void SvgParser::applyMarkers ( KoPathShape * shape)
protected

Definition at line 1250 of file SvgParser.cpp.

1251{
1253 if (!gc)
1254 return;
1255
1256 if (!gc->markerStartId.isEmpty() && m_markers.contains(gc->markerStartId)) {
1258 }
1259
1260 if (!gc->markerMidId.isEmpty() && m_markers.contains(gc->markerMidId)) {
1262 }
1263
1264 if (!gc->markerEndId.isEmpty() && m_markers.contains(gc->markerEndId)) {
1266 }
1267
1269}
void setAutoFillMarkers(bool value)
void setMarker(KoMarker *marker, KoFlake::MarkerPosition pos)
QMap< QString, QExplicitlySharedDataPointer< KoMarker > > m_markers
Definition SvgParser.h:229
@ EndMarker
Definition KoFlake.h:44
@ StartMarker
Definition KoFlake.h:42
@ MidMarker
Definition KoFlake.h:43

References SvgGraphicsContext::autoFillMarkers, SvgLoadingContext::currentGC(), KoFlake::EndMarker, m_context, m_markers, SvgGraphicsContext::markerEndId, SvgGraphicsContext::markerMidId, SvgGraphicsContext::markerStartId, KoFlake::MidMarker, KoPathShape::setAutoFillMarkers(), KoPathShape::setMarker(), and KoFlake::StartMarker.

◆ applyMaskClipping()

void SvgParser::applyMaskClipping ( KoShape * shape,
const QPointF & shapeToOriginalUserCoordinates )
protected

Definition at line 1344 of file SvgParser.cpp.

1345{
1347 if (!gc)
1348 return;
1349
1350 if (gc->clipMaskId.isEmpty())
1351 return;
1352
1353
1354 QSharedPointer<KoClipMask> originalClipMask = m_clipMasks.value(gc->clipMaskId);
1355 if (!originalClipMask || originalClipMask->isEmpty()) return;
1356
1357 KoClipMask *clipMask = originalClipMask->clone();
1358
1359 clipMask->setExtraShapeOffset(shapeToOriginalUserCoordinates);
1360
1361 shape->setClipMask(clipMask);
1362}
void setClipMask(KoClipMask *clipMask)
Sets a new clip mask, removing the old one. The mask is owned by the shape.
Definition KoShape.cpp:933
QString clipMaskId
the current clip mask id
QMap< QString, QSharedPointer< KoClipMask > > m_clipMasks
Definition SvgParser.h:228
void setExtraShapeOffset(const QPointF &value)

References SvgGraphicsContext::clipMaskId, SvgLoadingContext::currentGC(), m_clipMasks, m_context, KoShape::setClipMask(), and KoClipMask::setExtraShapeOffset().

◆ applyPaintOrder()

void SvgParser::applyPaintOrder ( KoShape * shape)
protected

Definition at line 1271 of file SvgParser.cpp.

1272{
1274 if (!gc)
1275 return;
1276
1277 if (!gc->paintOrder.isEmpty() && gc->paintOrder != "inherit") {
1278 QStringList paintOrder = gc->paintOrder.split(" ");
1280 Q_FOREACH(const QString p, paintOrder) {
1281 if (p == "fill") {
1282 order.append(KoShape::Fill);
1283 } else if (p == "stroke") {
1284 order.append(KoShape::Stroke);
1285 } else if (p == "markers") {
1286 order.append(KoShape::Markers);
1287 }
1288 }
1289 if (paintOrder.size() == 1 && order.isEmpty()) { // Normal
1291 }
1292 if (order.size() == 1) {
1293 if (order.first() == KoShape::Fill) {
1295 } else if (order.first() == KoShape::Stroke) {
1297 } else if (order.first() == KoShape::Markers) {
1299 }
1300 } else if (order.size() > 1) {
1301 shape->setPaintOrder(order.at(0), order.at(1));
1302 }
1303 }
1304}
const Params2D p
virtual void setPaintOrder(PaintOrder first, PaintOrder second)
setPaintOrder set the paint order. As there's only three entries in any given paintorder,...
Definition KoShape.cpp:664
static QVector< PaintOrder > defaultPaintOrder()
default paint order as per SVG specification
Definition KoShape.cpp:699
@ Stroke
Definition KoShape.h:117
@ Markers
Definition KoShape.h:118
QString paintOrder
String list indicating paint order;.

References SvgLoadingContext::currentGC(), KoShape::defaultPaintOrder(), KoShape::Fill, m_context, KoShape::Markers, p, SvgGraphicsContext::paintOrder, KoShape::setPaintOrder(), and KoShape::Stroke.

◆ applyStrokeStyle()

void SvgParser::applyStrokeStyle ( KoShape * shape)
protected

Applies the current stroke style to the object.

Definition at line 1207 of file SvgParser.cpp.

1208{
1210 if (! gc)
1211 return;
1212
1214 KoShapeStrokeSP stroke(new KoShapeStroke());
1215 stroke->setLineWidth(0.0);
1216 const QColor color = Qt::transparent;
1217 stroke->setColor(color);
1218 shape->setStroke(stroke);
1219 } else if (gc->strokeType == SvgGraphicsContext::Solid) {
1220 KoShapeStrokeSP stroke(new KoShapeStroke(*gc->stroke));
1221 applyDashes(gc->stroke, stroke);
1222 shape->setStroke(stroke);
1223 } else if (gc->strokeType == SvgGraphicsContext::Complex) {
1224 // try to find referenced gradient
1225 SvgGradientHelper *gradient = findGradient(gc->strokeId);
1226 if (gradient) {
1227 QTransform transform;
1228 QGradient *result = prepareGradientForShape(gradient, shape, gc, &transform);
1229 if (result) {
1230 QBrush brush = *result;
1231 delete result;
1232 brush.setTransform(transform);
1233
1234 KoShapeStrokeSP stroke(new KoShapeStroke(*gc->stroke));
1235 stroke->setLineBrush(brush);
1236 applyDashes(gc->stroke, stroke);
1237 shape->setStroke(stroke);
1238 }
1239 } else {
1240 // no referenced stroke found, use fallback color
1241 KoShapeStrokeSP stroke(new KoShapeStroke(*gc->stroke));
1242 applyDashes(gc->stroke, stroke);
1243 shape->setStroke(stroke);
1244 }
1245 } else if (gc->strokeType == SvgGraphicsContext::Inherit) {
1246 shape->setInheritStroke(true);
1247 }
1248}
void applyDashes(const KoShapeStrokeSP srcStroke, KoShapeStrokeSP dstStroke)
virtual void setStroke(KoShapeStrokeModelSP stroke)
Definition KoShape.cpp:899
void setInheritStroke(bool value)
setInheritStroke marks a shape as inheriting the stroke from the parent shape. NOTE: The currently se...
Definition KoShape.cpp:908
QString strokeId
the current stroke id (used for gradient strokes)
StyleType strokeType
the current stroke type
KoShapeStrokeSP stroke
the current stroke

References applyDashes(), SvgGraphicsContext::Complex, SvgLoadingContext::currentGC(), findGradient(), SvgGraphicsContext::Inherit, m_context, SvgGraphicsContext::None, prepareGradientForShape(), KoShape::setInheritStroke(), KoShape::setStroke(), SvgGraphicsContext::Solid, SvgGraphicsContext::stroke, SvgGraphicsContext::strokeId, and SvgGraphicsContext::strokeType.

◆ applyStyle() [1/2]

void SvgParser::applyStyle ( KoShape * obj,
const QDomElement & e,
const QPointF & shapeToOriginalUserCoordinates )
protected

Applies styles to the given shape.

Definition at line 966 of file SvgParser.cpp.

967{
968 applyStyle(obj, m_context.styleParser().collectStyles(e), shapeToOriginalUserCoordinates);
969}
SvgStyleParser * styleParser
void applyStyle(KoShape *, const QDomElement &, const QPointF &shapeToOriginalUserCoordinates)
Applies styles to the given shape.
SvgStyles collectStyles(const QDomElement &)
Creates style map from given xml element.

References applyStyle(), SvgStyleParser::collectStyles(), m_context, and SvgLoadingContext::styleParser.

◆ applyStyle() [2/2]

void SvgParser::applyStyle ( KoShape * obj,
const SvgStyles & styles,
const QPointF & shapeToOriginalUserCoordinates )
protected

Applies styles to the given shape.

Definition at line 971 of file SvgParser.cpp.

972{
974 if (!gc)
975 return;
976
978
979 if (!obj)
980 return;
981
982 if (!dynamic_cast<KoShapeGroup*>(obj)) {
983 applyFillStyle(obj);
984 applyStrokeStyle(obj);
985 }
986
987 if (KoPathShape *pathShape = dynamic_cast<KoPathShape*>(obj)) {
988 applyMarkers(pathShape);
989 }
990
991 applyClipping(obj, shapeToOriginalUserCoordinates);
992 applyMaskClipping(obj, shapeToOriginalUserCoordinates);
993
994 if (!gc->display || !gc->visible) {
995 obj->setVisible(false);
996 }
997 obj->setTransparency(1.0 - gc->opacity);
998 applyPaintOrder(obj);
999}
bool m_inheritStrokeFillByDefault
Definition SvgParser.h:239
void parseStyle(const SvgStyles &styles, const bool inheritByDefault=false)
Parses specified style attributes.

References applyClipping(), applyFillStyle(), applyMarkers(), applyMaskClipping(), applyPaintOrder(), applyStrokeStyle(), SvgLoadingContext::currentGC(), SvgGraphicsContext::display, m_context, m_inheritStrokeFillByDefault, SvgGraphicsContext::opacity, SvgStyleParser::parseStyle(), KoShape::setTransparency(), KoShape::setVisible(), SvgLoadingContext::styleParser, and SvgGraphicsContext::visible.

◆ applyViewBoxTransform()

void SvgParser::applyViewBoxTransform ( const QDomElement & element)
protected

Applies viewBox transformation to the current graphical context NOTE: after applying the function currentBoundingBox can become null!

Definition at line 1510 of file SvgParser.cpp.

1511{
1513
1514 QRectF viewRect = gc->currentBoundingBox;
1515 QTransform viewTransform;
1516
1518 &viewRect, &viewTransform)) {
1519
1520 gc->matrix = viewTransform * gc->matrix;
1521 gc->currentBoundingBox = viewRect;
1522 }
1523}
QRectF currentBoundingBox
the current bound box used for bounding box units
QTransform matrix
the current transformation matrix
static bool parseViewBox(const QDomElement &e, const QRectF &elementBounds, QRectF *_viewRect, QTransform *_viewTransform)
Parses a viewbox attribute into an rectangle.
Definition SvgUtil.cpp:133

References SvgGraphicsContext::currentBoundingBox, SvgLoadingContext::currentGC(), m_context, SvgGraphicsContext::matrix, and SvgUtil::parseViewBox().

◆ buildDocument()

void SvgParser::buildDocument ( QList< KoShape * > shapes)
protected

Builds the document from the given shapes list.

◆ createDocumentFromSvg() [1/4]

QDomDocument SvgParser::createDocumentFromSvg ( const QByteArray & data,
QString * errorMsg = 0,
int * errorLine = 0,
int * errorColumn = 0 )
static

Definition at line 172 of file SvgParser.cpp.

173{
174#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
175 QXmlInputSource source;
176 source.setData(data);
177 return createDocumentFromXmlInputSource(&source, errorMsg, errorLine, errorColumn);
178#else
179 return createDocumentFromSvg(QXmlStreamReader(data), errorMsg, errorLine, errorColumn);
180#endif
181}
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
static QDomDocument createDocumentFromSvg(QIODevice *device, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0)

References createDocumentFromSvg(), and source().

◆ createDocumentFromSvg() [2/4]

QDomDocument SvgParser::createDocumentFromSvg ( const QString & data,
QString * errorMsg = 0,
int * errorLine = 0,
int * errorColumn = 0 )
static

Definition at line 183 of file SvgParser.cpp.

184{
185#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
186 QXmlInputSource source;
187 source.setData(data);
188 return createDocumentFromXmlInputSource(&source, errorMsg, errorLine, errorColumn);
189#else
190 return createDocumentFromSvg(QXmlStreamReader(data), errorMsg, errorLine, errorColumn);
191#endif
192}

References createDocumentFromSvg(), and source().

◆ createDocumentFromSvg() [3/4]

QDomDocument SvgParser::createDocumentFromSvg ( QIODevice * device,
QString * errorMsg = 0,
int * errorLine = 0,
int * errorColumn = 0 )
static

Definition at line 162 of file SvgParser.cpp.

163{
164#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
165 QXmlInputSource source(device);
166 return createDocumentFromXmlInputSource(&source, errorMsg, errorLine, errorColumn);
167#else
168 return createDocumentFromSvg(QXmlStreamReader(device), errorMsg, errorLine, errorColumn);
169#endif
170}

References createDocumentFromSvg(), and source().

◆ createDocumentFromSvg() [4/4]

QDomDocument SvgParser::createDocumentFromSvg ( QXmlStreamReader reader,
QString * errorMsg = 0,
int * errorLine = 0,
int * errorColumn = 0 )
static

Definition at line 194 of file SvgParser.cpp.

195{
196 QDomDocument doc;
197
198
199 reader.setNamespaceProcessing(false);
200#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
201 if (!doc.setContent(&reader, false, errorMsg, errorLine, errorColumn)) {
202 return {};
203 }
204#else
205 QDomDocument::ParseResult result = doc.setContent(&reader, QDomDocument::ParseOption::PreserveSpacingOnlyNodes);
206 if (!result) {
207 if (errorMsg && errorLine && errorColumn) {
208 *errorMsg = result.errorMessage;
209 *errorLine = result.errorLine;
210 *errorColumn = result.errorColumn;
211 }
212 return {};
213 }
214#endif
215 return doc;
216}

◆ createListOfShapesFromCSS()

QList< KoShape * > SvgParser::createListOfShapesFromCSS ( const QDomElement e,
const QString value,
SvgLoadingContext & context,
bool hideShapesFromDefs = true )
protected

Create a list of shapes from a CSS shapes definition with potentially multiple shapes.

Definition at line 2192 of file SvgParser.cpp.

2193{
2194 QList<KoShape*> shapeList;
2195 if (value == "auto" || value == "none") {
2196 return shapeList;
2197 }
2198 QStringList params = value.split(")");
2199 Q_FOREACH(const QString param, params) {
2200 KoShape *s = createShapeFromCSS(e, param.trimmed()+")", context, hideShapesFromDefs);
2201 if (s) {
2202 shapeList.append(s);
2203 }
2204 }
2205 return shapeList;
2206}
float value(const T *src, size_t ch)
KoShape * createShapeFromCSS(const QDomElement e, const QString value, SvgLoadingContext &context, bool hideShapesFromDefs=true)
Creates a shape from a CSS shapes definition.

References createShapeFromCSS(), and value().

◆ createObject()

KoShape * SvgParser::createObject ( const QDomElement & b,
const SvgStyles & style = SvgStyles() )
protected

Creates an object from the given xml element.

Definition at line 2039 of file SvgParser.cpp.

2040{
2042
2044 if (obj) {
2046 const QPointF extraOffset = extraShapeOffset(obj, m_context.currentGC()->matrix);
2047
2048 SvgStyles objStyle = style.isEmpty() ? m_context.styleParser().collectStyles(b) : style;
2049 m_context.styleParser().parseFont(objStyle);
2050 applyStyle(obj, objStyle, extraOffset);
2051
2052 // handle id
2053 applyId(b.attribute("id"), obj);
2056 }
2057
2059
2060 if (obj) {
2062 }
2063
2064 return obj;
2065}
QPointF extraShapeOffset(const KoShape *shape, const QTransform coordinateSystemOnLoading)
QMap< QString, QString > SvgStyles
void setZIndex(qint16 zIndex)
Definition KoShape.cpp:782
SvgGraphicsContext * pushGraphicsContext(const QDomElement &element=QDomElement(), bool inherit=true)
Pushes a new graphics context to the stack.
void popGraphicsContext()
Pops the current graphics context from the stack.
int nextZIndex()
Returns the next z-index.
void parseMetadataApplyToShape(const QDomElement &e, KoShape *shape)
This parses the SVG native title and desc elements and adds them into additional attributes.
KoShape * createShapeFromElement(const QDomElement &element, SvgLoadingContext &context)
Creates shape from specified svg element.
void applyId(const QString &id, KoShape *shape)
Applies id to specified shape.
QMap< KoShape *, QTransform > m_shapeParentTransform
Definition SvgParser.h:238
void parseFont(const SvgStyles &styles)
Parses font attributes.

References KoShape::applyAbsoluteTransformation(), applyId(), applyStyle(), SvgStyleParser::collectStyles(), createShapeFromElement(), SvgLoadingContext::currentGC(), extraShapeOffset(), m_context, m_shapeParentTransform, SvgGraphicsContext::matrix, SvgLoadingContext::nextZIndex(), SvgStyleParser::parseFont(), parseMetadataApplyToShape(), SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), KoShape::setZIndex(), and SvgLoadingContext::styleParser.

◆ createObjectDirect()

KoShape * SvgParser::createObjectDirect ( const QDomElement & b)
protected

Definition at line 2013 of file SvgParser.cpp.

2014{
2017
2019 if (obj) {
2021 const QPointF extraOffset = extraShapeOffset(obj, m_context.currentGC()->matrix);
2022
2023 applyCurrentStyle(obj, extraOffset);
2024
2025 // handle id
2026 applyId(b.attribute("id"), obj);
2029 }
2030
2032
2033 if (obj) {
2035 }
2036 return obj;
2037}
void uploadStyleToContext(const QDomElement &e)
void applyCurrentStyle(KoShape *shape, const QPointF &shapeToOriginalUserCoordinates)

References KoShape::applyAbsoluteTransformation(), applyCurrentStyle(), applyId(), createShapeFromElement(), SvgLoadingContext::currentGC(), extraShapeOffset(), m_context, m_shapeParentTransform, SvgGraphicsContext::matrix, SvgLoadingContext::nextZIndex(), parseMetadataApplyToShape(), SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), KoShape::setZIndex(), and uploadStyleToContext().

◆ createPath()

KoShape * SvgParser::createPath ( const QDomElement & element)
protected

Create path object from the given xml element.

Definition at line 1943 of file SvgParser.cpp.

1944{
1945 KoShape *obj = 0;
1946 if (element.tagName() == "line") {
1947 KoPathShape *path = static_cast<KoPathShape*>(createShape(KoPathShapeId));
1948 if (path) {
1949 double x1 = element.attribute("x1").isEmpty() ? 0.0 : parseUnitX(element.attribute("x1"));
1950 double y1 = element.attribute("y1").isEmpty() ? 0.0 : parseUnitY(element.attribute("y1"));
1951 double x2 = element.attribute("x2").isEmpty() ? 0.0 : parseUnitX(element.attribute("x2"));
1952 double y2 = element.attribute("y2").isEmpty() ? 0.0 : parseUnitY(element.attribute("y2"));
1953 path->clear();
1954 path->moveTo(QPointF(x1, y1));
1955 path->lineTo(QPointF(x2, y2));
1956 path->normalize();
1957 obj = path;
1958 }
1959 } else if (element.tagName() == "polyline" || element.tagName() == "polygon") {
1960 KoPathShape *path = static_cast<KoPathShape*>(createShape(KoPathShapeId));
1961 if (path) {
1962 path->clear();
1963
1964 bool bFirst = true;
1965 QStringList pointList = SvgUtil::simplifyList(element.attribute("points"));
1966 for (QStringList::Iterator it = pointList.begin(); it != pointList.end(); ++it) {
1967 QPointF point;
1969 ++it;
1970 if (it == pointList.end())
1971 break;
1973 if (bFirst) {
1974 path->moveTo(point);
1975 bFirst = false;
1976 } else
1977 path->lineTo(point);
1978 }
1979 if (element.tagName() == "polygon")
1980 path->close();
1981
1982 path->setPosition(path->normalize());
1983
1984 obj = path;
1985 }
1986 } else if (element.tagName() == "path") {
1987 KoPathShape *path = static_cast<KoPathShape*>(createShape(KoPathShapeId));
1988 if (path) {
1989 path->clear();
1990
1991 KoPathShapeLoader loader(path);
1992 loader.parseSvg(element.attribute("d"), true);
1993 path->setPosition(path->normalize());
1994
1995 QPointF newPosition = QPointF(SvgUtil::fromUserSpace(path->position().x()),
1996 SvgUtil::fromUserSpace(path->position().y()));
1997 QSizeF newSize = QSizeF(SvgUtil::fromUserSpace(path->size().width()),
1998 SvgUtil::fromUserSpace(path->size().height()));
1999
2000 path->setSize(newSize);
2001 path->setPosition(newPosition);
2002
2003 if (element.hasAttribute("sodipodi:nodetypes")) {
2004 path->loadNodeTypes(element.attribute("sodipodi:nodetypes"));
2005 }
2006 obj = path;
2007 }
2008 }
2009
2010 return obj;
2011}
#define KoPathShapeId
Definition KoPathShape.h:20
void clear()
Removes all subpaths and their points from the path.
qreal parseUnitX(const QString &unit)
parses a length attribute in x-direction
qreal parseUnitY(const QString &unit)
parses a length attribute in y-direction
KoShape * createShape(const QString &shapeID)
creates a shape from the given shape id
static QStringList simplifyList(const QString &str)
Definition SvgUtil.cpp:450
static double fromUserSpace(double value)
Definition SvgUtil.cpp:29
double toDouble(const QString &str, bool *ok=nullptr)

References KoPathShape::clear(), createShape(), SvgUtil::fromUserSpace(), KoPathShapeId, KoPathShapeLoader::parseSvg(), parseUnitX(), parseUnitY(), SvgUtil::simplifyList(), and KisDomUtils::toDouble().

◆ createShape()

KoShape * SvgParser::createShape ( const QString & shapeID)
protected

creates a shape from the given shape id

Definition at line 2208 of file SvgParser.cpp.

2209{
2210 KoShapeFactoryBase *factory = KoShapeRegistry::instance()->get(shapeID);
2211 if (!factory) {
2212 debugFlake << "Could not find factory for shape id" << shapeID;
2213 return 0;
2214 }
2215
2217 if (!shape) {
2218 debugFlake << "Could not create Default shape for shape id" << shapeID;
2219 return 0;
2220 }
2221 if (shape->shapeId().isEmpty()) {
2222 shape->setShapeId(factory->id());
2223 }
2224
2225 // reset transformation that might come from the default shape
2226 shape->setTransformation(QTransform());
2227
2228 // reset border
2229 // ??? KoShapeStrokeModelSP oldStroke = shape->stroke();
2231
2232 // reset fill
2234
2235 return shape;
2236}
QSharedPointer< KoShapeStrokeModel > KoShapeStrokeModelSP
T get(const QString &id) const
virtual KoShape * createDefaultShape(KoDocumentResourceManager *documentResources=0) const
static KoShapeRegistry * instance()
QString shapeId() const
Definition KoShape.cpp:875
void setTransformation(const QTransform &matrix)
Definition KoShape.cpp:369
void setShapeId(const QString &id)
Definition KoShape.cpp:880

References KoShapeFactoryBase::createDefaultShape(), debugFlake, KoGenericRegistry< T >::get(), KoShapeFactoryBase::id, KoShapeRegistry::instance(), m_documentResourceManager, KoShape::setBackground(), KoShape::setShapeId(), KoShape::setStroke(), KoShape::setTransformation(), and KoShape::shapeId().

◆ createShapeFromCSS()

KoShape * SvgParser::createShapeFromCSS ( const QDomElement e,
const QString value,
SvgLoadingContext & context,
bool hideShapesFromDefs = true )
protected

Creates a shape from a CSS shapes definition.

Definition at line 2112 of file SvgParser.cpp.

2113{
2114 if (value.isEmpty()) {
2115 return 0;
2116 }
2117 unsigned int start = value.indexOf('(') + 1;
2118 unsigned int end = value.indexOf(')', start);
2119
2120 QString val = value.mid(start, end - start);
2121 QString fillRule;
2122 if (val.startsWith("evenodd,")) {
2123 start += QString("evenodd,").size();
2124 fillRule = "evenodd";
2125 } else if (val.startsWith("nonzero,")) {
2126 start += QString("nonzero,").size();
2127 fillRule = "nonzero";
2128 }
2129 val = value.mid(start, end - start);
2130
2131 QDomElement el;
2132 if (value.startsWith("url(")) {
2133 start = value.indexOf('#') + 1;
2134 KoShape *s = m_context.shapeById(value.mid(start, end - start));
2135 if (s) {
2136 const QTransform absTf = s->absoluteTransformation();
2137 KoShape *cloned = s->cloneShape();
2138 cloned->setTransformation(absTf * m_shapeParentTransform.value(s).inverted());
2139 // When we have a parent, the shape is inside the defs, but when not,
2140 // it's in the group we're in the currently parsing.
2141
2142 if (cloned && shapeInDefs(s) && hideShapesFromDefs) {
2143 cloned->setTransparency(1.0);
2144 }
2145 return cloned;
2146 }
2147 } else if (value.startsWith("circle(")) {
2148 el = e.ownerDocument().createElement("circle");
2149 QStringList params = val.split(" ");
2150 el.setAttribute("r", SvgUtil::parseUnitXY(context.currentGC(), context.resolvedProperties(), params.first()));
2151 if (params.contains("at")) {
2152 // 1 == "at"
2153 el.setAttribute("cx", SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), params.at(2)));
2154 el.setAttribute("cy", SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), params.at(3)));
2155 }
2156 } else if (value.startsWith("ellipse(")) {
2157 el = e.ownerDocument().createElement("ellipse");
2158 QStringList params = val.split(" ");
2159 el.setAttribute("rx", SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), params.at(0)));
2160 el.setAttribute("ry", SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), params.at(1)));
2161 if (params.contains("at")) {
2162 // 2 == "at"
2163 el.setAttribute("cx", SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), params.at(3)));
2164 el.setAttribute("cy", SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), params.at(4)));
2165 }
2166 } else if (value.startsWith("polygon(")) {
2167 el = e.ownerDocument().createElement("polygon");
2168 QStringList points;
2169 Q_FOREACH(QString point, SvgUtil::simplifyList(val)) {
2170 bool xVal = points.size() % 2;
2171 if (xVal) {
2172 points.append(QString::number(SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), point)));
2173 } else {
2174 points.append(QString::number(SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), point)));
2175 }
2176 }
2177 el.setAttribute("points", points.join(" "));
2178 } else if (value.startsWith("path(")) {
2179 el = e.ownerDocument().createElement("path");
2180 // SVG path data is inside a string.
2181 start += 1;
2182 end -= 1;
2183 el.setAttribute("d", value.mid(start, end - start));
2184 }
2185
2186 el.setAttribute("fill-rule", fillRule);
2187 KoShape *shape = createShapeFromElement(el, context);
2188 if (shape) shape->setTransparency(1.0);
2189 return shape;
2190}
QTransform absoluteTransformation() const
Definition KoShape.cpp:330
KoSvgTextProperties resolvedProperties(bool onlyFontAndLineHeight=false) const
bool shapeInDefs(const KoShape *shape)
Check whether the shapes are in the defs of the SVG document.
static qreal parseUnitX(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, const QString &unit)
parses a length attribute in x-direction
Definition SvgUtil.cpp:304
static qreal parseUnitXY(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, const QString &unit)
parses a length attribute in xy-direction
Definition SvgUtil.cpp:322
static qreal parseUnitY(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, const QString &unit)
parses a length attribute in y-direction
Definition SvgUtil.cpp:313

References KoShape::absoluteTransformation(), KoShape::cloneShape(), createShapeFromElement(), SvgLoadingContext::currentGC(), m_context, m_shapeParentTransform, SvgUtil::parseUnitX(), SvgUtil::parseUnitXY(), SvgUtil::parseUnitY(), SvgLoadingContext::resolvedProperties(), KoShape::setTransformation(), KoShape::setTransparency(), SvgLoadingContext::shapeById(), shapeInDefs(), SvgUtil::simplifyList(), KoShape::size(), and value().

◆ createShapeFromElement()

KoShape * SvgParser::createShapeFromElement ( const QDomElement & element,
SvgLoadingContext & context )
protected

Creates shape from specified svg element.

Definition at line 2067 of file SvgParser.cpp.

2068{
2069 KoShape *object = 0;
2070
2071
2072 const QString tagName = SvgUtil::mapExtendedShapeTag(element.tagName(), element);
2074
2075 foreach (KoShapeFactoryBase *f, factories) {
2076 KoShape *shape = f->createDefaultShape(m_documentResourceManager);
2077 if (!shape)
2078 continue;
2079
2080 SvgShape *svgShape = dynamic_cast<SvgShape*>(shape);
2081 if (!svgShape) {
2082 delete shape;
2083 continue;
2084 }
2085
2086 // reset transformation that might come from the default shape
2087 shape->setTransformation(QTransform());
2088
2089 // reset border
2090 KoShapeStrokeModelSP oldStroke = shape->stroke();
2092
2093 // reset fill
2095
2096 if (!svgShape->loadSvg(element, context)) {
2097 delete shape;
2098 continue;
2099 }
2100
2101 object = shape;
2102 break;
2103 }
2104
2105 if (!object) {
2106 object = createPath(element);
2107 }
2108
2109 return object;
2110}
QList< KoShapeFactoryBase * > factoriesForElement(const QString &nameSpace, const QString &elementName)
virtual KoShapeStrokeModelSP stroke() const
Definition KoShape.cpp:885
static const QString svg
Definition KoXmlNS.h:39
KoShape * createPath(const QDomElement &)
Create path object from the given xml element.
An interface providing svg loading and saving routines.
Definition SvgShape.h:18
virtual bool loadSvg(const QDomElement &element, SvgLoadingContext &context)
Loads data from specified svg element.
Definition SvgShape.cpp:19
static QString mapExtendedShapeTag(const QString &tagName, const QDomElement &element)
Definition SvgUtil.cpp:432

References createPath(), KoShapeRegistry::factoriesForElement(), KoShapeRegistry::instance(), SvgShape::loadSvg(), m_documentResourceManager, SvgUtil::mapExtendedShapeTag(), KoShape::setBackground(), KoShape::setStroke(), KoShape::setTransformation(), KoShape::stroke(), and KoXmlNS::svg.

◆ documentDescription()

QString SvgParser::documentDescription ( ) const

Definition at line 1546 of file SvgParser.cpp.

1547{
1548 return m_documentDescription;
1549}
QString m_documentDescription
Definition SvgParser.h:236

References m_documentDescription.

◆ documentTitle()

QString SvgParser::documentTitle ( ) const

Definition at line 1541 of file SvgParser.cpp.

1542{
1543 return m_documentTitle;
1544}
QString m_documentTitle
Definition SvgParser.h:235

References m_documentTitle.

◆ findClipPath()

SvgClipPathHelper * SvgParser::findClipPath ( const QString & id)
protected

find clip path with given id in clip path map

Definition at line 318 of file SvgParser.cpp.

319{
320 return m_clipPaths.contains(id) ? &m_clipPaths[id] : 0;
321}
QMap< QString, SvgClipPathHelper > m_clipPaths
Definition SvgParser.h:227

References m_clipPaths.

◆ findGradient()

SvgGradientHelper * SvgParser::findGradient ( const QString & id)
protected

find gradient with given id in gradient map

Definition at line 281 of file SvgParser.cpp.

282{
283 SvgGradientHelper *result = 0;
284
285 // check if gradient was already parsed, and return it
286 if (m_gradients.contains(id)) {
287 result = &m_gradients[ id ];
288 }
289
290 // check if gradient was stored for later parsing
291 if (!result && m_context.hasDefinition(id)) {
292 const QDomElement &e = m_context.definition(id);
293 if (e.tagName().contains("Gradient")) {
294 result = parseGradient(m_context.definition(id));
295 } else if (e.tagName() == "meshgradient") {
297 }
298 }
299
300 return result;
301}
QDomElement definition(const QString &id) const
Returns the definition with the specified id.
bool hasDefinition(const QString &id) const
Checks if a definition with the specified id exists.
SvgGradientHelper * parseGradient(const QDomElement &)
Parses a gradient element.
SvgGradientHelper * parseMeshGradient(const QDomElement &)
Parses mesh gradient element.
QMap< QString, SvgGradientHelper > m_gradients
Definition SvgParser.h:226

References SvgLoadingContext::definition(), SvgLoadingContext::hasDefinition(), m_context, m_gradients, parseGradient(), and parseMeshGradient().

◆ findPattern()

QSharedPointer< KoVectorPatternBackground > SvgParser::findPattern ( const QString & id,
const KoShape * shape )
protected

find pattern with given id in pattern map

Definition at line 303 of file SvgParser.cpp.

304{
306
307 // check if gradient was stored for later parsing
308 if (m_context.hasDefinition(id)) {
309 const QDomElement &e = m_context.definition(id);
310 if (e.tagName() == "pattern") {
311 result = parsePattern(m_context.definition(id), shape);
312 }
313 }
314
315 return result;
316}
QSharedPointer< KoVectorPatternBackground > parsePattern(const QDomElement &e, const KoShape *__shape)
Parses a pattern element.

References SvgLoadingContext::definition(), SvgLoadingContext::hasDefinition(), m_context, and parsePattern().

◆ getTextPath()

KoShape * SvgParser::getTextPath ( const QDomElement & e,
bool hideShapesFromDefs = true )
protected

Get the path for the gives textPath element.

Definition at line 1640 of file SvgParser.cpp.

1640 {
1641 if (e.hasAttribute("path")) {
1642 QDomElement p = e.ownerDocument().createElement("path");
1643 p.setAttribute("d", e.attribute("path"));
1644 KoShape *s = createPath(p);
1645 if (hideShapesFromDefs) {
1646 s->setTransparency(1.0);
1647 }
1648 return s;
1649 } else {
1650 QString pathId;
1651 if (e.hasAttribute("href")) {
1652 pathId = e.attribute("href").remove(0, 1);
1653 } else if (e.hasAttribute("xlink:href")) {
1654 pathId = e.attribute("xlink:href").remove(0, 1);
1655 }
1656 if (!pathId.isNull()) {
1657 KoShape *s = m_context.shapeById(pathId);
1658 if (s) {
1659 KoShape *cloned = s->cloneShape();
1660 const QTransform absTf = s->absoluteTransformation();
1661 cloned->setTransformation(absTf * m_shapeParentTransform.value(s).inverted());
1662 if(cloned && shapeInDefs(s) && hideShapesFromDefs) {
1663 cloned->setTransparency(1.0);
1664 }
1665 return cloned;
1666 }
1667 }
1668 }
1669 return nullptr;
1670}

References KoShape::absoluteTransformation(), KoShape::cloneShape(), createPath(), m_context, m_shapeParentTransform, p, KoShape::setTransformation(), KoShape::setTransparency(), SvgLoadingContext::shapeById(), and shapeInDefs().

◆ getTheOnlyTextChild()

QDomText SvgParser::getTheOnlyTextChild ( const QDomElement & e)
protected

Definition at line 1623 of file SvgParser.cpp.

1624{
1625 QDomNode firstChild = e.firstChild();
1626 return !firstChild.isNull() && firstChild == e.lastChild() && firstChild.isText() ?
1627 firstChild.toText() : QDomText();
1628}

◆ knownMarkers()

QList< QExplicitlySharedDataPointer< KoMarker > > SvgParser::knownMarkers ( ) const

Definition at line 1536 of file SvgParser.cpp.

1537{
1538 return m_markers.values();
1539}

References m_markers.

◆ parseAngular()

qreal SvgParser::parseAngular ( const QString & unit)
protected

parses a angular attribute values, result in radians

Definition at line 346 of file SvgParser.cpp.

347{
349}
static qreal parseUnitAngular(SvgGraphicsContext *gc, const QString &unit)
parses angle, result in radians!
Definition SvgUtil.cpp:332

References SvgLoadingContext::currentGC(), m_context, and SvgUtil::parseUnitAngular().

◆ parseClipMask()

bool SvgParser::parseClipMask ( const QDomElement & e)
protected

Definition at line 868 of file SvgParser.cpp.

869{
871
872 const QString id = e.attribute("id");
873 if (id.isEmpty()) return false;
874
875 clipMask->setCoordinates(KoFlake::coordinatesFromString(e.attribute("maskUnits"), KoFlake::ObjectBoundingBox));
876 clipMask->setContentCoordinates(KoFlake::coordinatesFromString(e.attribute("maskContentUnits"), KoFlake::UserSpaceOnUse));
877
878 QRectF maskRect;
879
880 if (clipMask->coordinates() == KoFlake::ObjectBoundingBox) {
881 maskRect.setRect(
882 SvgUtil::fromPercentage(e.attribute("x", "-10%")),
883 SvgUtil::fromPercentage(e.attribute("y", "-10%")),
884 SvgUtil::fromPercentage(e.attribute("width", "120%")),
885 SvgUtil::fromPercentage(e.attribute("height", "120%")));
886 } else {
887 maskRect.setRect(
888 parseUnitX(e.attribute("x", "-10%")), // yes, percents are insane in this case,
889 parseUnitY(e.attribute("y", "-10%")), // but this is what SVG 1.1 tells us...
890 parseUnitX(e.attribute("width", "120%")),
891 parseUnitY(e.attribute("height", "120%")));
892 }
893
894 clipMask->setMaskRect(maskRect);
895
896
897 // ensure that the clip mask is loaded in local coordinates system
899 m_context.currentGC()->matrix = QTransform();
901
902 KoShape *clipShape = parseGroup(e);
903
905
906 if (!clipShape) return false;
907 clipMask->setShapes({clipShape});
908
909 m_clipMasks.insert(id, clipMask);
910 return true;
911}
void workaroundClearInheritedFillProperties()
KoShape * parseGroup(const QDomElement &e, const QDomElement &overrideChildrenFrom=QDomElement(), bool createContext=true)
Parses a group-like element element, saving all its topmost properties.
static double fromPercentage(QString s, bool *ok=nullptr)
Definition SvgUtil.cpp:64
CoordinateSystem coordinatesFromString(const QString &value, CoordinateSystem defaultValue)

References KoFlake::coordinatesFromString(), SvgLoadingContext::currentGC(), SvgUtil::fromPercentage(), m_clipMasks, m_context, SvgGraphicsContext::matrix, KoFlake::ObjectBoundingBox, parseGroup(), parseUnitX(), parseUnitY(), SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), KoFlake::UserSpaceOnUse, and SvgGraphicsContext::workaroundClearInheritedFillProperties().

◆ parseClipPath()

bool SvgParser::parseClipPath ( const QDomElement & e)
protected

Parses a clip path element.

Definition at line 841 of file SvgParser.cpp.

842{
843 SvgClipPathHelper clipPath;
844
845 const QString id = e.attribute("id");
846 if (id.isEmpty()) return false;
847
848 clipPath.setClipPathUnits(
849 KoFlake::coordinatesFromString(e.attribute("clipPathUnits"), KoFlake::UserSpaceOnUse));
850
851 // ensure that the clip path is loaded in local coordinates system
853 m_context.currentGC()->matrix = QTransform();
855
856 KoShape *clipShape = parseGroup(e);
857
859
860 if (!clipShape) return false;
861
862 clipPath.setShapes({clipShape});
863 m_clipPaths.insert(id, clipPath);
864
865 return true;
866}
void setClipPathUnits(KoFlake::CoordinateSystem clipPathUnits)
Set the clip path units type.
void setShapes(const QList< KoShape * > &shapes)

References KoFlake::coordinatesFromString(), SvgLoadingContext::currentGC(), m_clipPaths, m_context, SvgGraphicsContext::matrix, parseGroup(), SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), SvgClipPathHelper::setClipPathUnits(), SvgClipPathHelper::setShapes(), KoFlake::UserSpaceOnUse, and SvgGraphicsContext::workaroundClearInheritedFillProperties().

◆ parseContainer()

QList< KoShape * > SvgParser::parseContainer ( const QDomElement & e)
protected

Parses a container element, returning a list of child shapes.

Definition at line 1807 of file SvgParser.cpp.

1808{
1810
1811 // are we parsing a switch container
1812 bool isSwitch = e.tagName() == "switch";
1813
1814 DeferredUseStore deferredUseStore(this);
1815
1816 for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
1817 QDomElement b = n.toElement();
1818 if (b.isNull()) {
1819 continue;
1820 }
1821
1822 if (isSwitch) {
1823 // if we are parsing a switch check the requiredFeatures, requiredExtensions
1824 // and systemLanguage attributes
1825 // TODO: evaluate feature list
1826 if (b.hasAttribute("requiredFeatures")) {
1827 continue;
1828 }
1829 if (b.hasAttribute("requiredExtensions")) {
1830 // we do not support any extensions
1831 continue;
1832 }
1833 if (b.hasAttribute("systemLanguage")) {
1834 // not implemented yet
1835 }
1836 }
1837
1838 QList<KoShape*> currentShapes = parseSingleElement(b, &deferredUseStore);
1839 shapes.append(currentShapes);
1840
1841 // if we are parsing a switch, stop after the first supported element
1842 if (isSwitch && !currentShapes.isEmpty())
1843 break;
1844 }
1845 return shapes;
1846}
QList< KoShape * > parseSingleElement(const QDomElement &b, DeferredUseStore *deferredUseStore=0)
XXX.

References parseSingleElement(), and shapes().

◆ parseDefsElement()

void SvgParser::parseDefsElement ( const QDomElement & e)

Definition at line 1848 of file SvgParser.cpp.

1849{
1850 KIS_SAFE_ASSERT_RECOVER_RETURN(e.tagName() == "defs");
1852}
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References KIS_SAFE_ASSERT_RECOVER_RETURN, and parseSingleElement().

◆ parseFilter()

bool SvgParser::parseFilter ( const QDomElement & ,
const QDomElement & referencedBy = QDomElement() )
protected

Parses a filter element.

◆ parseGradient()

SvgGradientHelper * SvgParser::parseGradient ( const QDomElement & e)
protected

Parses a gradient element.

Definition at line 352 of file SvgParser.cpp.

353{
354 // IMPROVEMENTS:
355 // - Store the parsed colorstops in some sort of a cache so they don't need to be parsed again.
356 // - A gradient inherits attributes it does not have from the referencing gradient.
357 // - Gradients with no color stops have no fill or stroke.
358 // - Gradients with one color stop have a solid color.
359
361 if (!gc) return 0;
362
363 SvgGradientHelper gradHelper;
364
365 QString gradientId = e.attribute("id");
366 if (gradientId.isEmpty()) return 0;
367
368 // check if we have this gradient already parsed
369 // copy existing gradient if it exists
370 if (m_gradients.contains(gradientId)) {
371 return &m_gradients[gradientId];
372 }
373
374 if (e.hasAttribute("xlink:href")) {
375 // strip the '#' symbol
376 QString href = e.attribute("xlink:href").mid(1);
377
378 if (!href.isEmpty()) {
379 // copy the referenced gradient if found
380 SvgGradientHelper *pGrad = findGradient(href);
381 if (pGrad) {
382 gradHelper = *pGrad;
383 }
384 }
385 }
386
387 const QGradientStops defaultStops = gradHelper.gradient()->stops();
388
389 if (e.attribute("gradientUnits") == "userSpaceOnUse") {
391 }
392
395
396 if (e.tagName() == "linearGradient") {
397 QLinearGradient *g = new QLinearGradient();
398 if (gradHelper.gradientUnits() == KoFlake::ObjectBoundingBox) {
399 g->setCoordinateMode(QGradient::ObjectBoundingMode);
400 g->setStart(QPointF(SvgUtil::fromPercentage(e.attribute("x1", "0%")),
401 SvgUtil::fromPercentage(e.attribute("y1", "0%"))));
402 g->setFinalStop(QPointF(SvgUtil::fromPercentage(e.attribute("x2", "100%")),
403 SvgUtil::fromPercentage(e.attribute("y2", "0%"))));
404 } else {
405 g->setStart(QPointF(parseUnitX(e.attribute("x1")),
406 parseUnitY(e.attribute("y1"))));
407 g->setFinalStop(QPointF(parseUnitX(e.attribute("x2")),
408 parseUnitY(e.attribute("y2"))));
409 }
410 gradHelper.setGradient(g);
411
412 } else if (e.tagName() == "radialGradient") {
413 QRadialGradient *g = new QRadialGradient();
414 if (gradHelper.gradientUnits() == KoFlake::ObjectBoundingBox) {
415 g->setCoordinateMode(QGradient::ObjectBoundingMode);
416 g->setCenter(QPointF(SvgUtil::fromPercentage(e.attribute("cx", "50%")),
417 SvgUtil::fromPercentage(e.attribute("cy", "50%"))));
418 g->setRadius(SvgUtil::fromPercentage(e.attribute("r", "50%")));
419 g->setFocalPoint(QPointF(SvgUtil::fromPercentage(e.attribute("fx", "50%")),
420 SvgUtil::fromPercentage(e.attribute("fy", "50%"))));
421 } else {
422 g->setCenter(QPointF(parseUnitX(e.attribute("cx")),
423 parseUnitY(e.attribute("cy"))));
424 g->setFocalPoint(QPointF(parseUnitX(e.attribute("fx")),
425 parseUnitY(e.attribute("fy"))));
426 g->setRadius(parseUnitXY(e.attribute("r")));
427 }
428 gradHelper.setGradient(g);
429 } else {
430 debugFlake << "WARNING: Failed to parse gradient with tag" << e.tagName();
431 }
432
433 // handle spread method
434 QGradient::Spread spreadMethod = QGradient::PadSpread;
435 QString spreadMethodStr = e.attribute("spreadMethod");
436 if (!spreadMethodStr.isEmpty()) {
437 if (spreadMethodStr == "reflect") {
438 spreadMethod = QGradient::ReflectSpread;
439 } else if (spreadMethodStr == "repeat") {
440 spreadMethod = QGradient::RepeatSpread;
441 }
442 }
443
444 gradHelper.setSpreadMode(spreadMethod);
445
446 // Parse the color stops.
447 m_context.styleParser().parseColorStops(gradHelper.gradient(), e, gc, defaultStops);
448
449 if (e.hasAttribute("gradientTransform")) {
450 SvgTransformParser p(e.attribute("gradientTransform"));
451 if (p.isValid()) {
452 gradHelper.setTransform(p.transform());
453 }
454 }
455
457
458 m_gradients.insert(gradientId, gradHelper);
459
460 return &m_gradients[gradientId];
461}
KoFlake::CoordinateSystem gradientUnits() const
Returns gradient units type.
void setSpreadMode(const QGradient::Spread &spreadMode)
void setGradient(QGradient *g)
Sets the gradient.
void setGradientUnits(KoFlake::CoordinateSystem units)
Sets the gradient units type.
void setTransform(const QTransform &transform)
Sets the gradient transformation.
qreal parseUnitXY(const QString &unit)
parses a length attribute in xy-direction
void parseColorStops(QGradient *, const QDomElement &, SvgGraphicsContext *context, const QGradientStops &defaultStops)
Parses gradient color stops.

References SvgLoadingContext::currentGC(), debugFlake, findGradient(), SvgUtil::fromPercentage(), SvgGradientHelper::gradient(), SvgGradientHelper::gradientUnits(), m_context, m_gradients, KoFlake::ObjectBoundingBox, p, SvgStyleParser::parseColorStops(), parseUnitX(), parseUnitXY(), parseUnitY(), SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), SvgGradientHelper::setGradient(), SvgGradientHelper::setGradientUnits(), SvgGradientHelper::setSpreadMode(), SvgGradientHelper::setTransform(), SvgLoadingContext::styleParser, uploadStyleToContext(), and KoFlake::UserSpaceOnUse.

◆ parseGroup()

KoShape * SvgParser::parseGroup ( const QDomElement & e,
const QDomElement & overrideChildrenFrom = QDomElement(),
bool createContext = true )
protected

Parses a group-like element element, saving all its topmost properties.

Definition at line 1566 of file SvgParser.cpp.

1567{
1568 if (createContext) {
1570 }
1571
1572 KoShapeGroup *group = new KoShapeGroup();
1573 group->setZIndex(m_context.nextZIndex());
1574
1575 // groups should also have their own coordinate system!
1577 const QPointF extraOffset = extraShapeOffset(group, m_context.currentGC()->matrix);
1578
1580
1581 QList<KoShape*> childShapes;
1582
1583 if (!overrideChildrenFrom.isNull()) {
1584 // we upload styles from both: <use> and <defs>
1585 uploadStyleToContext(overrideChildrenFrom);
1586 if (overrideChildrenFrom.tagName() == "symbol") {
1587 childShapes = {parseGroup(overrideChildrenFrom)};
1588 } else {
1589 childShapes = parseSingleElement(overrideChildrenFrom, 0);
1590 }
1591 } else {
1592 childShapes = parseContainer(b);
1593 }
1594
1595 // handle id
1596 applyId(b.attribute("id"), group);
1597
1598 if (b.hasAttribute(KoSvgTextShape_TEXTCONTOURGROUP)) {
1599 Q_FOREACH(KoShape *shape, childShapes) {
1600 if (shape->shapeId() == KoSvgTextShape_SHAPEID) {
1601 shape->setTransformation(group->transformation());
1602
1603 if (createContext) {
1605 }
1606 return shape;
1607 }
1608 }
1609 }
1610 addToGroup(childShapes, group);
1611
1612 applyCurrentStyle(group, extraOffset); // apply style to this group after size is set
1613
1614 parseMetadataApplyToShape(b, group);
1615
1616 if (createContext) {
1618 }
1619
1620 return group;
1621}
#define KoSvgTextShape_SHAPEID
#define KoSvgTextShape_TEXTCONTOURGROUP
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:378
void addToGroup(QList< KoShape * > shapes, KoShapeContainer *group)
Adds list of shapes to the given group shape.
QList< KoShape * > parseContainer(const QDomElement &)
Parses a container element, returning a list of child shapes.

References addToGroup(), KoShape::applyAbsoluteTransformation(), applyCurrentStyle(), applyId(), SvgLoadingContext::currentGC(), extraShapeOffset(), KoSvgTextShape_SHAPEID, KoSvgTextShape_TEXTCONTOURGROUP, m_context, SvgGraphicsContext::matrix, SvgLoadingContext::nextZIndex(), parseContainer(), parseGroup(), parseMetadataApplyToShape(), parseSingleElement(), SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), KoShape::setTransformation(), KoShape::setZIndex(), KoShape::shapeId(), KoShape::transformation(), and uploadStyleToContext().

◆ parseMarker()

bool SvgParser::parseMarker ( const QDomElement & e)
protected

Definition at line 737 of file SvgParser.cpp.

738{
739 const QString id = e.attribute("id");
740 if (id.isEmpty()) return false;
741
742 std::unique_ptr<KoMarker> marker(new KoMarker());
743 marker->setCoordinateSystem(
744 KoMarker::coordinateSystemFromString(e.attribute("markerUnits", "strokeWidth")));
745
746 marker->setReferencePoint(QPointF(parseUnitX(e.attribute("refX")),
747 parseUnitY(e.attribute("refY"))));
748
749 marker->setReferenceSize(QSizeF(parseUnitX(e.attribute("markerWidth", "3")),
750 parseUnitY(e.attribute("markerHeight", "3"))));
751
752 const QString orientation = e.attribute("orient", "0");
753
754 if (orientation == "auto") {
755 marker->setAutoOrientation(true);
756 } else {
757 marker->setExplicitOrientation(parseAngular(orientation));
758 }
759
760 // ensure that the clip path is loaded in local coordinates system
762 m_context.currentGC()->matrix = QTransform();
763 m_context.currentGC()->currentBoundingBox = QRectF(QPointF(0, 0), marker->referenceSize());
764
765 KoShape *markerShape = parseGroup(e);
766
768
769 if (!markerShape) return false;
770
771 marker->setShapes({markerShape});
772
773 m_markers.insert(id, QExplicitlySharedDataPointer<KoMarker>(marker.release()));
774
775 return true;
776}
static MarkerCoordinateSystem coordinateSystemFromString(const QString &value)
Definition KoMarker.cpp:155
qreal parseAngular(const QString &unit)
parses a angular attribute values, result in radians

References KoMarker::coordinateSystemFromString(), SvgGraphicsContext::currentBoundingBox, SvgLoadingContext::currentGC(), m_context, m_markers, SvgGraphicsContext::matrix, parseAngular(), parseGroup(), parseUnitX(), parseUnitY(), SvgLoadingContext::popGraphicsContext(), and SvgLoadingContext::pushGraphicsContext().

◆ parseMeshGradient()

SvgGradientHelper * SvgParser::parseMeshGradient ( const QDomElement & e)
protected

Parses mesh gradient element.

Definition at line 463 of file SvgParser.cpp.

464{
465 SvgGradientHelper gradHelper;
466 QString gradientId = e.attribute("id");
467 QScopedPointer<SvgMeshGradient> g(new SvgMeshGradient);
468
469 // check if we have this gradient already parsed
470 // copy existing gradient if it exists
471 if (m_gradients.contains(gradientId)) {
472 return &m_gradients[gradientId];
473 }
474
475 if (e.hasAttribute("xlink:href")) {
476 // strip the '#' symbol
477 QString href = e.attribute("xlink:href").mid(1);
478
479 if (!href.isEmpty()) {
480 // copy the referenced gradient if found
481 SvgGradientHelper *pGrad = findGradient(href);
482 if (pGrad) {
483 gradHelper = *pGrad;
484 }
485 }
486 }
487
488 if (e.attribute("gradientUnits") == "userSpaceOnUse") {
490 }
491
492 if (e.hasAttribute("transform")) {
493 SvgTransformParser p(e.attribute("transform"));
494 if (p.isValid()) {
495 gradHelper.setTransform(p.transform());
496 }
497 }
498
499 QString type = e.attribute("type");
500 g->setType(SvgMeshGradient::BILINEAR);
501 if (!type.isEmpty() && type == "bicubic") {
502 g->setType(SvgMeshGradient::BICUBIC);
503 }
504
505 int irow = 0, icols;
506 for (int i = 0; i < e.childNodes().size(); ++i) {
507 QDomNode node = e.childNodes().at(i);
508
509 if (node.nodeName() == "meshrow") {
510
511 SvgMeshStop startingNode;
512 if (irow == 0) {
513 startingNode.point = QPointF(
514 parseUnitX(e.attribute("x")),
515 parseUnitY(e.attribute(("y"))));
516 startingNode.color = QColor();
517 }
518
519 icols = 0;
520 g->getMeshArray()->newRow();
521 for (int j = 0; j < node.childNodes().size() ; ++j) {
522 QDomNode meshpatchNode = node.childNodes().at(j);
523
524 if (meshpatchNode.nodeName() == "meshpatch") {
525 if (irow > 0) {
526 // Starting point for this would be the bottom (right) corner of the above patch
527 startingNode = g->getMeshArray()->getStop(SvgMeshPatch::Bottom, irow - 1, icols);
528 } else if (icols != 0) {
529 // Starting point for this would be the right (top) corner of the previous patch
530 startingNode = g->getMeshArray()->getStop(SvgMeshPatch::Right, irow, icols - 1);
531 }
532
533 QList<QPair<QString, QColor>> rawStops = parseMeshPatch(meshpatchNode);
534 // TODO handle the false result
535 if (!g->getMeshArray()->addPatch(rawStops, startingNode.point)) {
536 debugFlake << "WARNING: Failed to create meshpatch";
537 }
538 icols++;
539 }
540 }
541 irow++;
542 }
543 }
544 gradHelper.setMeshGradient(g.data());
545 m_gradients.insert(gradientId, gradHelper);
546
547 return &m_gradients[gradientId];
548}
void setMeshGradient(SvgMeshGradient *g)
Sets the meshgradient.
QList< QPair< QString, QColor > > parseMeshPatch(const QDomNode &meshpatch)
Parses a single meshpatch and returns the pointer.
int size(const Forest< T > &forest)
Definition KisForest.h:1232
QPointF point

References SvgMeshGradient::BICUBIC, SvgMeshGradient::BILINEAR, SvgMeshPatch::Bottom, SvgMeshStop::color, debugFlake, findGradient(), m_gradients, p, parseMeshPatch(), parseUnitX(), parseUnitY(), SvgMeshStop::point, SvgMeshPatch::Right, SvgGradientHelper::setGradientUnits(), SvgGradientHelper::setMeshGradient(), SvgGradientHelper::setTransform(), and KoFlake::UserSpaceOnUse.

◆ parseMeshPatch()

QList< QPair< QString, QColor > > SvgParser::parseMeshPatch ( const QDomNode & meshpatch)
protected

Parses a single meshpatch and returns the pointer.

Definition at line 554 of file SvgParser.cpp.

555{
556 // path and its associated color
558
560 if (!gc) return rawstops;
561
562 QDomElement e = meshpatchNode.toElement();
563
564 QDomElement stop;
565
566 forEachElement(stop, e) {
567 qreal X = 0; // dummy value, don't care, just to ensure the function won't blow up (also to avoid a Coverity issue)
568 QColor color = m_context.styleParser().parseColorStop(stop, gc, X).second;
569
570 QString pathStr = stop.attribute("path");
571
572 rawstops.append({pathStr, color});
573 }
574
575 return rawstops;
576}
#define forEachElement(elem, parent)
QPair< qreal, QColor > parseColorStop(const QDomElement &, SvgGraphicsContext *context, qreal &previousOffset)
const QString X

References SvgLoadingContext::currentGC(), forEachElement, m_context, SvgStyleParser::parseColorStop(), and SvgLoadingContext::styleParser.

◆ parseMetadataApplyToShape()

void SvgParser::parseMetadataApplyToShape ( const QDomElement & e,
KoShape * shape )
protected

This parses the SVG native title and desc elements and adds them into additional attributes.

Definition at line 821 of file SvgParser.cpp.

822{
823 const QString titleTag = "title";
824 const QString descriptionTag = "desc";
825 QDomElement title = e.firstChildElement(titleTag);
826 if (!title.isNull()) {
827 QDomText text = getTheOnlyTextChild(title);
828 if (!text.data().isEmpty()) {
829 shape->setAdditionalAttribute(titleTag, text.data());
830 }
831 }
832 QDomElement description = e.firstChildElement(descriptionTag);
833 if (!description.isNull()) {
834 QDomText text = getTheOnlyTextChild(description);
835 if (!text.data().isEmpty()) {
836 shape->setAdditionalAttribute(descriptionTag, text.data());
837 }
838 }
839}
void setAdditionalAttribute(const QString &name, const QString &value)
Definition KoShape.cpp:1072
QDomText getTheOnlyTextChild(const QDomElement &e)

References getTheOnlyTextChild(), and KoShape::setAdditionalAttribute().

◆ parsePattern()

QSharedPointer< KoVectorPatternBackground > SvgParser::parsePattern ( const QDomElement & e,
const KoShape * __shape )
protected

Parses a pattern element.

Unlike the gradient parsing function, this method is called every time we reference the pattern, not when we define it. Therefore we can already use the coordinate system of the destination.

In Krita shapes X,Y coordinates are baked into the shape global transform, but the pattern should be painted in "user" coordinates. Therefore, we should handle this offset separately.

TODO: Please also note that this offset is different from extraShapeOffset(), because A.inverted() * B != A * B.inverted(). I'm not sure which variant is correct (DK)

Definition at line 589 of file SvgParser.cpp.

590{
598
600 if (!gc) return pattHelper;
601
602 const QString patternId = e.attribute("id");
603 if (patternId.isEmpty()) return pattHelper;
604
605 pattHelper = toQShared(new KoVectorPatternBackground);
606
607 if (e.hasAttribute("xlink:href")) {
608 // strip the '#' symbol
609 QString href = e.attribute("xlink:href").mid(1);
610
611 if (!href.isEmpty() &&href != patternId) {
612 // copy the referenced pattern if found
614 if (pPatt) {
615 pattHelper = pPatt;
616 }
617 }
618 }
619
620 pattHelper->setReferenceCoordinates(
621 KoFlake::coordinatesFromString(e.attribute("patternUnits"),
622 pattHelper->referenceCoordinates()));
623
624 pattHelper->setContentCoordinates(
625 KoFlake::coordinatesFromString(e.attribute("patternContentUnits"),
626 pattHelper->contentCoordinates()));
627
628 if (e.hasAttribute("patternTransform")) {
629 SvgTransformParser p(e.attribute("patternTransform"));
630 if (p.isValid()) {
631 pattHelper->setPatternTransform(p.transform());
632 }
633 }
634
635 if (pattHelper->referenceCoordinates() == KoFlake::ObjectBoundingBox) {
636 QRectF referenceRect(
637 SvgUtil::fromPercentage(e.attribute("x", "0%")),
638 SvgUtil::fromPercentage(e.attribute("y", "0%")),
639 SvgUtil::fromPercentage(e.attribute("width", "0%")), // 0% is according to SVG 1.1, don't ask me why!
640 SvgUtil::fromPercentage(e.attribute("height", "0%"))); // 0% is according to SVG 1.1, don't ask me why!
641
642 pattHelper->setReferenceRect(referenceRect);
643 } else {
644 QRectF referenceRect(
645 parseUnitX(e.attribute("x", "0")),
646 parseUnitY(e.attribute("y", "0")),
647 parseUnitX(e.attribute("width", "0")), // 0 is according to SVG 1.1, don't ask me why!
648 parseUnitY(e.attribute("height", "0"))); // 0 is according to SVG 1.1, don't ask me why!
649
650 pattHelper->setReferenceRect(referenceRect);
651 }
652
663 const QTransform dstShapeTransform = shape->absoluteTransformation();
664 const QTransform shapeOffsetTransform = dstShapeTransform * gc->matrix.inverted();
665 KIS_SAFE_ASSERT_RECOVER_NOOP(shapeOffsetTransform.type() <= QTransform::TxTranslate);
666 const QPointF extraShapeOffset(shapeOffsetTransform.dx(), shapeOffsetTransform.dy());
667
669 gc = m_context.currentGC();
671
672 // start building shape tree from scratch
673 gc->matrix = QTransform();
674
675 const QRectF boundingRect = shape->outline().boundingRect()/*.translated(extraShapeOffset)*/;
676 const QTransform relativeToShape(boundingRect.width(), 0, 0, boundingRect.height(),
677 boundingRect.x(), boundingRect.y());
678
679
680
681 // WARNING1: OBB and ViewBox transformations are *baked* into the pattern shapes!
682 // although we expect the pattern be reusable, but it is not so!
683 // WARNING2: the pattern shapes are stored in *User* coordinate system, although
684 // the "official" content system might be either OBB or User. It means that
685 // this baked transform should be stripped before writing the shapes back
686 // into SVG
687 if (e.hasAttribute("viewBox")) {
689 pattHelper->referenceCoordinates() == KoFlake::ObjectBoundingBox ?
690 relativeToShape.mapRect(pattHelper->referenceRect()) :
691 pattHelper->referenceRect();
692
694 pattHelper->setContentCoordinates(pattHelper->referenceCoordinates());
695
696 } else if (pattHelper->contentCoordinates() == KoFlake::ObjectBoundingBox) {
697 gc->matrix = relativeToShape * gc->matrix;
698 }
699
700 // We do *not* apply patternTransform here! Here we only bake the untransformed
701 // version of the shape. The transformed one will be done in the very end while rendering.
702
703 QList<KoShape*> patternShapes = parseContainer(e);
704
705 if (pattHelper->contentCoordinates() == KoFlake::UserSpaceOnUse) {
706 // In Krita we normalize the shapes, bake this transform into the pattern shapes
707
708 const QPointF offset = bakeShapeOffset(pattHelper->patternTransform(), extraShapeOffset);
709
710 Q_FOREACH (KoShape *shape, patternShapes) {
711 shape->applyAbsoluteTransformation(QTransform::fromTranslate(offset.x(), offset.y()));
712 }
713 }
714
715 if (pattHelper->referenceCoordinates() == KoFlake::UserSpaceOnUse) {
716 // In Krita we normalize the shapes, bake this transform into reference rect
717 // NOTE: this is possible *only* when pattern transform is not perspective
718 // (which is always true for SVG)
719
720 const QPointF offset = bakeShapeOffset(pattHelper->patternTransform(), extraShapeOffset);
721
722 QRectF ref = pattHelper->referenceRect();
723 ref.translate(offset);
724 pattHelper->setReferenceRect(ref);
725 }
726
728 gc = m_context.currentGC();
729
730 if (!patternShapes.isEmpty()) {
731 pattHelper->setShapes(patternShapes);
732 }
733
734 return pattHelper;
735}
QPointF bakeShapeOffset(const QTransform &patternTransform, const QPointF &shapeOffset)
void applyViewBoxTransform(const QDomElement &element)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130

References KoShape::absoluteTransformation(), KoShape::applyAbsoluteTransformation(), applyViewBoxTransform(), bakeShapeOffset(), KoFlake::coordinatesFromString(), SvgGraphicsContext::currentBoundingBox, SvgLoadingContext::currentGC(), extraShapeOffset(), findPattern(), SvgUtil::fromPercentage(), KIS_SAFE_ASSERT_RECOVER_NOOP, m_context, SvgGraphicsContext::matrix, KoFlake::ObjectBoundingBox, KoShape::outline(), p, parseContainer(), parseUnitX(), parseUnitY(), SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), toQShared(), KoFlake::UserSpaceOnUse, and SvgGraphicsContext::workaroundClearInheritedFillProperties().

◆ parseSingleElement()

QList< KoShape * > SvgParser::parseSingleElement ( const QDomElement & b,
DeferredUseStore * deferredUseStore = 0 )
protected

XXX.

WARNING: 'defs' are basically 'display:none' style, therefore they should not play any role in shapes outline calculation. But setVisible(false) shapes do! Should be fixed in the future!

Definition at line 1854 of file SvgParser.cpp.

1855{
1857
1858 // save definition for later instantiation with 'use'
1860 if (deferredUseStore) {
1861 deferredUseStore->checkPendingUse(b, shapes);
1862 }
1863
1864 if (b.tagName() == "svg") {
1865 shapes += parseSvg(b);
1866 } else if (b.tagName() == "g" || b.tagName() == "a") {
1867 // treat svg link <a> as group so we don't miss its child elements
1868 shapes += parseGroup(b);
1869 } else if (b.tagName() == "symbol") {
1870 parseSymbol(b);
1871 } else if (b.tagName() == "switch") {
1873 shapes += parseContainer(b);
1875 } else if (b.tagName() == "defs") {
1876 if (b.childNodes().count() > 0) {
1882 KoShape *defsShape = parseGroup(b);
1883 defsShape->setVisible(false);
1884 m_defsShapes << defsShape; // TODO: where to delete the shape!?
1885
1886 }
1887 } else if (b.tagName() == "linearGradient" || b.tagName() == "radialGradient") {
1888 } else if (b.tagName() == "pattern") {
1889 } else if (b.tagName() == "filter") {
1890 // not supported!
1891 } else if (b.tagName() == "clipPath") {
1892 parseClipPath(b);
1893 } else if (b.tagName() == "mask") {
1894 parseClipMask(b);
1895 } else if (b.tagName() == "marker") {
1896 parseMarker(b);
1897 } else if (b.tagName() == "style") {
1899 } else if (b.tagName() == "text" || b.tagName() == "tspan" || b.tagName() == "textPath") {
1901 } else if (b.tagName() == "rect" || b.tagName() == "ellipse" || b.tagName() == "circle" || b.tagName() == "line" || b.tagName() == "polyline"
1902 || b.tagName() == "polygon" || b.tagName() == "path" || b.tagName() == "image") {
1903 KoShape *shape = createObjectDirect(b);
1904
1905 if (shape) {
1906 if (!shape->outlineRect().isNull() || !shape->boundingRect().isNull()) {
1907 shapes.append(shape);
1908 } else {
1909 debugFlake << "WARNING: shape is totally empty!" << shape->shapeId() << ppVar(shape->outlineRect());
1910 debugFlake << " " << shape->shapeId() << ppVar(shape->outline());
1911 {
1912 QString string;
1913 QTextStream stream(&string);
1915 stream << b;
1916 debugFlake << " " << string;
1917 }
1918 delete shape;
1919 }
1920 }
1921 } else if (b.tagName() == "use") {
1922 KoShape* s = parseUse(b, deferredUseStore);
1923 if (s) {
1924 shapes += s;
1925 }
1926 } else if (b.tagName() == "color-profile") {
1928 } else {
1929 // this is an unknown element, so try to load it anyway
1930 // there might be a shape that handles that element
1931 KoShape *shape = createObject(b);
1932 if (shape) {
1933 shapes.append(shape);
1934 }
1935 }
1936
1937 return shapes;
1938}
virtual QRectF outlineRect() const
Definition KoShape.cpp:561
virtual QPainterPath outline() const
Definition KoShape.cpp:554
virtual QRectF boundingRect() const
Get the bounding box of the shape.
Definition KoShape.cpp:300
void addDefinition(const QDomElement &element)
Adds a definition for later use.
void addStyleSheet(const QDomElement &styleSheet)
Adds a css style sheet.
void parseProfile(const QDomElement &element)
parses 'color-profile' tag and saves it in the context
bool parseClipPath(const QDomElement &)
Parses a clip path element.
bool parseClipMask(const QDomElement &e)
bool parseMarker(const QDomElement &e)
KoShape * parseTextElement(const QDomElement &e, KoSvgTextShape *mergeIntoShape=0)
QList< KoShape * > parseSvg(const QDomElement &e, QSizeF *fragmentSize=0)
Parses a svg fragment, returning the list of top level child shapes.
KoShape * parseUse(const QDomElement &, DeferredUseStore *deferredUseStore)
Parses a use element, returning a list of child shapes.
bool parseSymbol(const QDomElement &e)
KoShape * createObjectDirect(const QDomElement &b)
KoShape * createObject(const QDomElement &, const SvgStyles &style=SvgStyles())
Creates an object from the given xml element.
#define ppVar(var)
Definition kis_debug.h:155
void setUtf8OnStream(QTextStream &stream)

References SvgLoadingContext::addDefinition(), SvgLoadingContext::addStyleSheet(), KoShape::boundingRect(), SvgParser::DeferredUseStore::checkPendingUse(), createObject(), createObjectDirect(), debugFlake, m_context, m_defsShapes, KoShape::outline(), KoShape::outlineRect(), parseClipMask(), parseClipPath(), parseContainer(), parseGroup(), parseMarker(), SvgLoadingContext::parseProfile(), parseSvg(), parseSymbol(), parseTextElement(), parseUse(), SvgLoadingContext::popGraphicsContext(), ppVar, SvgLoadingContext::pushGraphicsContext(), KisPortingUtils::setUtf8OnStream(), KoShape::setVisible(), KoShape::shapeId(), and shapes().

◆ parseSvg()

QList< KoShape * > SvgParser::parseSvg ( const QDomElement & e,
QSizeF * fragmentSize = 0 )

Parses a svg fragment, returning the list of top level child shapes.

In internal SVG coordinate systems pixels are linked to absolute values with a fixed ratio.

See CSS specification: https://www.w3.org/TR/css-values-3/#absolute-lengths

Definition at line 1411 of file SvgParser.cpp.

1412{
1413 // check if we are the root svg element
1414 const bool isRootSvg = m_context.isRootContext();
1415
1416 // parse 'transform' field if preset
1418
1419 applyStyle(0, e, QPointF());
1420
1421 const QString w = e.attribute("width");
1422 const QString h = e.attribute("height");
1423
1424 qreal width = w.isEmpty() ? 666.0 : parseUnitX(w);
1425 qreal height = h.isEmpty() ? 555.0 : parseUnitY(h);
1426
1427 if (w.isEmpty() || h.isEmpty()) {
1428 QRectF viewRect;
1429 QTransform viewTransform_unused;
1430 QRectF fakeBoundingRect(0.0, 0.0, 1.0, 1.0);
1431
1432 if (SvgUtil::parseViewBox(e, fakeBoundingRect,
1433 &viewRect, &viewTransform_unused)) {
1434
1435 QSizeF estimatedSize = viewRect.size();
1436
1437 if (estimatedSize.isValid()) {
1438
1439 if (!w.isEmpty()) {
1440 estimatedSize = QSizeF(width, width * estimatedSize.height() / estimatedSize.width());
1441 } else if (!h.isEmpty()) {
1442 estimatedSize = QSizeF(height * estimatedSize.width() / estimatedSize.height(), height);
1443 }
1444
1445 width = estimatedSize.width();
1446 height = estimatedSize.height();
1447 }
1448 }
1449 }
1450
1451 QSizeF svgFragmentSize(QSizeF(width, height));
1452
1453 if (fragmentSize) {
1454 *fragmentSize = svgFragmentSize;
1455 }
1456
1457 gc->currentBoundingBox = QRectF(QPointF(0, 0), svgFragmentSize);
1458
1459 if (!isRootSvg) {
1460 // x and y attribute has no meaning for outermost svg elements
1461 const qreal x = parseUnit(e.attribute("x", "0"));
1462 const qreal y = parseUnit(e.attribute("y", "0"));
1463
1464 QTransform move = QTransform::fromTranslate(x, y);
1465 gc->matrix = move * gc->matrix;
1466 }
1467
1475 gc->pixelsPerInch = 96.0;
1476
1478
1480
1481 // First find the metadata
1482 for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
1483 QDomElement b = n.toElement();
1484 if (b.isNull())
1485 continue;
1486
1487 if (b.tagName() == "title") {
1488 m_documentTitle = b.text().trimmed();
1489 }
1490 else if (b.tagName() == "desc") {
1491 m_documentDescription = b.text().trimmed();
1492 }
1493 else if (b.tagName() == "metadata") {
1494 // TODO: parse the metadata
1495 }
1496 }
1497
1498
1499 // SVG 1.1: skip the rendering of the element if it has null viewBox; however an inverted viewbox is just peachy
1500 // and as mother makes them -- if mother is inkscape.
1501 if (gc->currentBoundingBox.normalized().isValid()) {
1503 }
1504
1506
1507 return shapes;
1508}
qreal pixelsPerInch
controls the resolution of the image raster
qreal parseUnit(const QString &, bool horiz=false, bool vert=false, const QRectF &bbox=QRectF())
parses a length attribute

References applyStyle(), applyViewBoxTransform(), SvgGraphicsContext::currentBoundingBox, SvgLoadingContext::isRootContext(), m_context, m_documentDescription, m_documentTitle, SvgGraphicsContext::matrix, parseContainer(), parseUnit(), parseUnitX(), parseUnitY(), SvgUtil::parseViewBox(), SvgGraphicsContext::pixelsPerInch, SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), and shapes().

◆ parseSymbol()

bool SvgParser::parseSymbol ( const QDomElement & e)
protected

Definition at line 778 of file SvgParser.cpp.

779{
780 const QString id = e.attribute("id");
781
782 if (id.isEmpty()) return false;
783
784 std::unique_ptr<KoSvgSymbol> svgSymbol(new KoSvgSymbol());
785
786 // ensure that the clip path is loaded in local coordinates system
788 m_context.currentGC()->matrix = QTransform();
789 m_context.currentGC()->currentBoundingBox = QRectF(0.0, 0.0, 1.0, 1.0);
790
791 QString title = e.firstChildElement("title").toElement().text();
792
793 std::unique_ptr<KoShape> symbolShape(parseGroup(e));
794
796
797 if (!symbolShape) return false;
798
799 svgSymbol->shape = symbolShape.release();
800 svgSymbol->title = title;
801 svgSymbol->id = id;
802 if (title.isEmpty()) svgSymbol->title = id;
803
804 if (svgSymbol->shape->boundingRect() == QRectF(0.0, 0.0, 0.0, 0.0)) {
805 debugFlake << "Symbol" << id << "seems to be empty, discarding";
806 return false;
807 }
808
809 // TODO: out default set of symbols had duplicated ids! We should
810 // make sure they are unique!
811 if (m_symbols.contains(id)) {
812 delete m_symbols[id];
813 m_symbols.remove(id);
814 }
815
816 m_symbols.insert(id, svgSymbol.release());
817
818 return true;
819}

References SvgGraphicsContext::currentBoundingBox, SvgLoadingContext::currentGC(), debugFlake, m_context, m_symbols, SvgGraphicsContext::matrix, parseGroup(), SvgLoadingContext::popGraphicsContext(), and SvgLoadingContext::pushGraphicsContext().

◆ parseTextChildren()

void SvgParser::parseTextChildren ( const QDomElement & e,
KoSvgTextLoader & textLoader,
bool hideShapesFromDefs = true )
protected

parse children of a <text > element into the root shape.

TODO: we should skip dublin core metadata too...

Definition at line 1672 of file SvgParser.cpp.

1672 {
1673 QDomText t = getTheOnlyTextChild(e);
1674 if (!t.isNull()) {
1675 textLoader.loadSvgText(t, m_context);
1676 } else {
1677 textLoader.enterNodeSubtree();
1678 for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
1679 QDomElement b = n.toElement();
1680 if (b.tagName() == "title" || b.tagName() == "desc") continue;
1681 textLoader.nextNode();
1682 if (b.isNull()) {
1683 textLoader.loadSvgText(n.toText(), m_context);
1684 KoShape *styleDummy = new KoPathShape();
1685 applyCurrentBasicStyle(styleDummy);
1686 textLoader.setStyleInfo(styleDummy);
1687 } else {
1690 textLoader.loadSvg(b, m_context);
1691 if (b.hasChildNodes()) {
1692 parseTextChildren(b, textLoader, hideShapesFromDefs);
1693 }
1694 textLoader.setTextPathOnCurrentNode(getTextPath(b, hideShapesFromDefs));
1696 }
1697 }
1698 textLoader.leaveNodeSubtree();
1699 }
1700 KoShape *styleDummy = new KoPathShape();
1701 applyCurrentBasicStyle(styleDummy);
1702 textLoader.setStyleInfo(styleDummy);
1703}
void leaveNodeSubtree()
Set the current node to its parent, leaving the subtree.
bool loadSvgText(const QDomText &text, SvgLoadingContext &context)
Loads the textt into the current node.
void setTextPathOnCurrentNode(KoShape *s)
Set the textPath on the current node.
void nextNode()
Switch to next node.
void enterNodeSubtree()
Set the current node to its first child, entering the subtree.
void setStyleInfo(KoShape *s)
Set the style info from the shape. This is necessary because SVGParser only understands loading the b...
bool loadSvg(const QDomElement &element, SvgLoadingContext &context, bool root=false)
Create a new text node.
void parseTextChildren(const QDomElement &e, KoSvgTextLoader &textLoader, bool hideShapesFromDefs=true)
parse children of a <text > element into the root shape.
KoShape * getTextPath(const QDomElement &e, bool hideShapesFromDefs=true)
Get the path for the gives textPath element.

References applyCurrentBasicStyle(), KoSvgTextLoader::enterNodeSubtree(), getTextPath(), getTheOnlyTextChild(), KoSvgTextLoader::leaveNodeSubtree(), KoSvgTextLoader::loadSvg(), KoSvgTextLoader::loadSvgText(), m_context, KoSvgTextLoader::nextNode(), parseTextChildren(), SvgLoadingContext::popGraphicsContext(), SvgLoadingContext::pushGraphicsContext(), KoSvgTextLoader::setStyleInfo(), KoSvgTextLoader::setTextPathOnCurrentNode(), and uploadStyleToContext().

◆ parseTextElement()

KoShape * SvgParser::parseTextElement ( const QDomElement & e,
KoSvgTextShape * mergeIntoShape = 0 )

Definition at line 1705 of file SvgParser.cpp.

1706{
1707 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(e.tagName() == "text" || e.tagName() == "tspan" || e.tagName() == "textPath", 0);
1709 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(e.tagName() == "text" || !mergeIntoShape, 0);
1710
1711 KoSvgTextShape *rootTextShape = 0;
1712
1713 bool hideShapesFromDefs = true;
1714 if (mergeIntoShape) {
1715 rootTextShape = mergeIntoShape;
1716 hideShapesFromDefs = false;
1717 } else {
1718 KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value("KoSvgTextShapeID");
1719 rootTextShape = dynamic_cast<KoSvgTextShape*>(factory->createDefaultShape(m_documentResourceManager));
1720 }
1721 KoSvgTextLoader textLoader(rootTextShape);
1722
1723 if (rootTextShape) {
1724 m_isInsideTextSubtree = true;
1725 }
1726
1729
1730 if (rootTextShape) {
1731 if (!m_context.currentGC()->shapeInsideValue.isEmpty()) {
1733 rootTextShape->setShapesInside(shapesInside);
1734 }
1735
1736 if (!m_context.currentGC()->shapeSubtractValue.isEmpty()) {
1737 QList<KoShape*> shapesSubtract = createListOfShapesFromCSS(e, m_context.currentGC()->shapeSubtractValue, m_context, hideShapesFromDefs);
1738 rootTextShape->setShapesSubtract(shapesSubtract);
1739 }
1740 }
1741
1742 if (e.hasAttribute("krita:textVersion")) {
1743 m_context.currentGC()->textProperties.setProperty(KoSvgTextProperties::KraTextVersionId, e.attribute("krita:textVersion", "1").toInt());
1744
1746 debugFlake << "WARNING: \"krita:textVersion\" attribute appeared in non-root text shape";
1747 }
1748 }
1749
1750 parseMetadataApplyToShape(e, rootTextShape);
1751
1752 if (!mergeIntoShape) {
1753 rootTextShape->setZIndex(m_context.nextZIndex());
1754 }
1755
1758
1759 static const KoID warning("warn_text_version_1",
1760 i18nc("warning while loading SVG text",
1761 "The document has vector text created "
1762 "in Krita 4.x. When you save the document, "
1763 "the text object will be converted into "
1764 "Krita 5 format that will no longer be "
1765 "compatible with Krita 4.x"));
1766
1767 if (!m_warnings.contains(warning)) {
1768 m_warnings << warning;
1769 }
1770 }
1771
1772 textLoader.loadSvg(e, m_context, m_resolveTextPropertiesForTopLevel);
1773
1774 // 1) apply transformation only in case we are not overriding the shape!
1775 // 2) the transformation should be applied *before* the shape is added to the group!
1776 if (!mergeIntoShape) {
1777 // groups should also have their own coordinate system!
1779 const QPointF extraOffset = extraShapeOffset(rootTextShape, m_context.currentGC()->matrix);
1780
1781 // handle id
1782 applyId(e.attribute("id"), rootTextShape);
1783 applyCurrentStyle(rootTextShape, extraOffset); // apply style to this group after size is set
1784 } else {
1785 m_context.currentGC()->matrix = mergeIntoShape->absoluteTransformation();
1786 applyCurrentBasicStyle(rootTextShape);
1787 }
1788
1789 QDomText onlyTextChild = getTheOnlyTextChild(e);
1790 if (!onlyTextChild.isNull()) {
1791 textLoader.loadSvgText(onlyTextChild, m_context);
1792
1793 } else {
1794 parseTextChildren(e, textLoader, hideShapesFromDefs);
1795 }
1796
1798
1799 m_isInsideTextSubtree = false;
1800
1801 //rootTextShape->debugParsing();
1802
1803
1804 return rootTextShape;
1805}
const T value(const QString &id) const
Definition KoID.h:30
@ KraTextVersionId
Int, used for handling incorrectly saved files.
QVariant property(PropertyId id, const QVariant &defaultValue=QVariant()) const
bool hasProperty(PropertyId id) const
void setProperty(PropertyId id, const QVariant &value)
void setShapesSubtract(QList< KoShape * > shapesSubtract)
setShapesSubtract
void setShapesInside(QList< KoShape * > shapesInside)
setShapesInside
KoSvgTextProperties textProperties
Stores textProperties.
QString shapeSubtractValue
String of value shape-subtract, will be parsed later.
QString shapeInsideValue
String of value shape-inside, will be parsed later.
QList< KoShape * > createListOfShapesFromCSS(const QDomElement e, const QString value, SvgLoadingContext &context, bool hideShapesFromDefs=true)
Create a list of shapes from a CSS shapes definition with potentially multiple shapes.
bool m_isInsideTextSubtree
Definition SvgParser.h:234
bool m_resolveTextPropertiesForTopLevel
Definition SvgParser.h:240
QVector< KoID > m_warnings
Definition SvgParser.h:237
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References KoShape::absoluteTransformation(), KoShape::applyAbsoluteTransformation(), applyCurrentBasicStyle(), applyCurrentStyle(), applyId(), KoShapeFactoryBase::createDefaultShape(), createListOfShapesFromCSS(), SvgLoadingContext::currentGC(), debugFlake, extraShapeOffset(), getTheOnlyTextChild(), KoSvgTextProperties::hasProperty(), KoShapeRegistry::instance(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, KoSvgTextProperties::KraTextVersionId, KoSvgTextLoader::loadSvg(), KoSvgTextLoader::loadSvgText(), m_context, m_documentResourceManager, m_isInsideTextSubtree, m_resolveTextPropertiesForTopLevel, m_warnings, SvgGraphicsContext::matrix, SvgLoadingContext::nextZIndex(), parseMetadataApplyToShape(), parseTextChildren(), SvgLoadingContext::popGraphicsContext(), KoSvgTextProperties::property(), SvgLoadingContext::pushGraphicsContext(), KoSvgTextProperties::setProperty(), KoSvgTextShape::setShapesInside(), KoSvgTextShape::setShapesSubtract(), KoShape::setZIndex(), SvgGraphicsContext::shapeInsideValue, SvgGraphicsContext::shapeSubtractValue, SvgGraphicsContext::textProperties, uploadStyleToContext(), and KoGenericRegistry< T >::value().

◆ parseUnit()

qreal SvgParser::parseUnit ( const QString & unit,
bool horiz = false,
bool vert = false,
const QRectF & bbox = QRectF() )
protected

parses a length attribute

Definition at line 326 of file SvgParser.cpp.

327{
328 return SvgUtil::parseUnit(m_context.currentGC(), m_context.resolvedProperties(), unit, horiz, vert, bbox);
329}
static qreal parseUnit(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, QStringView, bool horiz=false, bool vert=false, const QRectF &bbox=QRectF())
Parses a length attribute.
Definition SvgUtil.cpp:218

References SvgLoadingContext::currentGC(), m_context, SvgUtil::parseUnit(), and SvgLoadingContext::resolvedProperties().

◆ parseUnitX()

qreal SvgParser::parseUnitX ( const QString & unit)
protected

parses a length attribute in x-direction

Definition at line 331 of file SvgParser.cpp.

References SvgLoadingContext::currentGC(), m_context, SvgUtil::parseUnitX(), and SvgLoadingContext::resolvedProperties().

◆ parseUnitXY()

qreal SvgParser::parseUnitXY ( const QString & unit)
protected

parses a length attribute in xy-direction

Definition at line 341 of file SvgParser.cpp.

References SvgLoadingContext::currentGC(), m_context, SvgUtil::parseUnitXY(), and SvgLoadingContext::resolvedProperties().

◆ parseUnitY()

qreal SvgParser::parseUnitY ( const QString & unit)
protected

parses a length attribute in y-direction

Definition at line 336 of file SvgParser.cpp.

References SvgLoadingContext::currentGC(), m_context, SvgUtil::parseUnitY(), and SvgLoadingContext::resolvedProperties().

◆ parseUse()

KoShape * SvgParser::parseUse ( const QDomElement & e,
DeferredUseStore * deferredUseStore )
protected

Parses a use element, returning a list of child shapes.

Definition at line 1364 of file SvgParser.cpp.

1365{
1366 QString href = e.attribute("xlink:href");
1367 if (href.isEmpty())
1368 return 0;
1369
1370 QString key = href.mid(1);
1371 const bool gotDef = m_context.hasDefinition(key);
1372 if (gotDef) {
1373 return resolveUse(e, key);
1374 } else if (deferredUseStore) {
1375 deferredUseStore->add(&e, key);
1376 return 0;
1377 }
1378 debugFlake << "WARNING: Did not find reference for svg 'use' element. Skipping. Id: "
1379 << key;
1380 return 0;
1381}
KoShape * resolveUse(const QDomElement &e, const QString &key)

References SvgParser::DeferredUseStore::add(), debugFlake, SvgLoadingContext::hasDefinition(), m_context, and resolveUse().

◆ resolveUse()

KoShape * SvgParser::resolveUse ( const QDomElement & e,
const QString & key )
protected

Definition at line 1383 of file SvgParser.cpp.

1384{
1385 KoShape *result = 0;
1386
1388
1389 // TODO: parse 'width' and 'height' as well
1390 gc->matrix.translate(parseUnitX(e.attribute("x", "0")), parseUnitY(e.attribute("y", "0")));
1391
1392 const QDomElement &referencedElement = m_context.definition(key);
1393 result = parseGroup(e, referencedElement, false);
1394
1396 return result;
1397}

References SvgLoadingContext::definition(), m_context, SvgGraphicsContext::matrix, parseGroup(), parseUnitX(), parseUnitY(), SvgLoadingContext::popGraphicsContext(), and SvgLoadingContext::pushGraphicsContext().

◆ setDefaultKraTextVersion()

◆ setFileFetcher()

void SvgParser::setFileFetcher ( SvgParser::FileFetcherFunc func)

Definition at line 1551 of file SvgParser.cpp.

1552{
1554}
void setFileFetcher(FileFetcherFunc func)

References m_context, and SvgLoadingContext::setFileFetcher().

◆ setFillStrokeInheritByDefault()

void SvgParser::setFillStrokeInheritByDefault ( const bool enable)

Definition at line 256 of file SvgParser.cpp.

257{
259}

References m_inheritStrokeFillByDefault.

◆ setResolution()

void SvgParser::setResolution ( const QRectF boundsInPixels,
qreal pixelsPerInch )

◆ setResolveTextPropertiesForTopLevel()

void SvgParser::setResolveTextPropertiesForTopLevel ( const bool enable)

Definition at line 261 of file SvgParser.cpp.

262{
264}

References m_resolveTextPropertiesForTopLevel.

◆ setXmlBaseDir()

void SvgParser::setXmlBaseDir ( const QString & baseDir)

Sets the initial xml base directory (the directory form where the file is read)

Definition at line 218 of file SvgParser.cpp.

219{
221
223 [this](const QString &name) {
224 QStringList possibleNames;
225 possibleNames << name;
226 possibleNames << QDir::cleanPath(QDir(m_context.xmlBaseDir()).absoluteFilePath(name));
227 for (QString fileName : possibleNames) {
228 QFile file(fileName);
229 if (file.open(QIODevice::ReadOnly)) {
230 return file.readAll();
231 }
232 }
233 return QByteArray();
234 });
235}
void setInitialXmlBaseDir(const QString &baseDir)
Sets the initial xml base dir, i.e. the directory the svg file is read from.
QString xmlBaseDir() const
Returns the current xml base dir.
void setFileFetcher(FileFetcherFunc func)
const char * name(StandardAction id)

References m_context, setFileFetcher(), SvgLoadingContext::setInitialXmlBaseDir(), and SvgLoadingContext::xmlBaseDir().

◆ shapeInDefs()

bool SvgParser::shapeInDefs ( const KoShape * shape)
protected

Check whether the shapes are in the defs of the SVG document.

Definition at line 1630 of file SvgParser.cpp.

1631{
1632 for (auto defs = m_defsShapes.begin(); defs != m_defsShapes.end(); defs++) {
1633 KoShape *dShape = *defs;
1634 if (!dShape) continue;
1635 if (dShape->hasCommonParent(shape)) return true;
1636 }
1637 return false;
1638}
bool hasCommonParent(const KoShape *shape) const
Definition KoShape.cpp:505

References KoShape::hasCommonParent(), and m_defsShapes.

◆ shapes()

QList< KoShape * > SvgParser::shapes ( ) const

Returns the list of all shapes of the svg document.

Definition at line 266 of file SvgParser.cpp.

267{
268 return m_shapes;
269}

References m_shapes.

◆ takeSymbols()

QVector< KoSvgSymbol * > SvgParser::takeSymbols ( )

Takes the collection of symbols contained in the svg document. The parser will no longer know about the symbols.

Definition at line 271 of file SvgParser.cpp.

272{
273 QVector<KoSvgSymbol*> symbols = m_symbols.values().toVector();
274 m_symbols.clear();
275 return symbols;
276}

References m_symbols.

◆ uploadStyleToContext()

◆ warnings()

QStringList SvgParser::warnings ( ) const

Definition at line 1525 of file SvgParser.cpp.

1526{
1528
1529 Q_FOREACH (const KoID &id, m_warnings) {
1530 warnings << id.name();
1531 }
1532
1533 return warnings;
1534}
QStringList warnings() const

References m_warnings, and warnings().

Member Data Documentation

◆ m_clipMasks

QMap<QString, QSharedPointer<KoClipMask> > SvgParser::m_clipMasks
private

Definition at line 228 of file SvgParser.h.

◆ m_clipPaths

QMap<QString, SvgClipPathHelper> SvgParser::m_clipPaths
private

Definition at line 227 of file SvgParser.h.

◆ m_context

SvgLoadingContext SvgParser::m_context
private

Definition at line 225 of file SvgParser.h.

◆ m_defsShapes

QList<KoShape*> SvgParser::m_defsShapes
private

Definition at line 233 of file SvgParser.h.

◆ m_documentDescription

QString SvgParser::m_documentDescription
private

Definition at line 236 of file SvgParser.h.

◆ m_documentResourceManager

KoDocumentResourceManager* SvgParser::m_documentResourceManager
private

Definition at line 230 of file SvgParser.h.

◆ m_documentTitle

QString SvgParser::m_documentTitle
private

Definition at line 235 of file SvgParser.h.

◆ m_gradients

QMap<QString, SvgGradientHelper> SvgParser::m_gradients
private

Definition at line 226 of file SvgParser.h.

◆ m_inheritStrokeFillByDefault

bool SvgParser::m_inheritStrokeFillByDefault = false
private

Definition at line 239 of file SvgParser.h.

◆ m_isInsideTextSubtree

bool SvgParser::m_isInsideTextSubtree = false
private

Definition at line 234 of file SvgParser.h.

◆ m_markers

QMap<QString, QExplicitlySharedDataPointer<KoMarker> > SvgParser::m_markers
private

Definition at line 229 of file SvgParser.h.

◆ m_resolveTextPropertiesForTopLevel

bool SvgParser::m_resolveTextPropertiesForTopLevel = true
private

Definition at line 240 of file SvgParser.h.

◆ m_shapeParentTransform

QMap<KoShape *, QTransform> SvgParser::m_shapeParentTransform
private

Definition at line 238 of file SvgParser.h.

◆ m_shapes

QList<KoShape*> SvgParser::m_shapes
private

Definition at line 231 of file SvgParser.h.

◆ m_symbols

QMap<QString, KoSvgSymbol*> SvgParser::m_symbols
private

Definition at line 232 of file SvgParser.h.

◆ m_warnings

QVector<KoID> SvgParser::m_warnings
private

Definition at line 237 of file SvgParser.h.


The documentation for this class was generated from the following files: