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 1400 of file SvgParser.cpp.

1401{
1402 m_shapes += shapes;
1403
1404 if (!group || shapes.isEmpty())
1405 return;
1406
1407 // not normalized
1408 KoShapeGroupCommand cmd(group, shapes, false);
1409 cmd.redo();
1410}
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 1307 of file SvgParser.cpp.

1308{
1310 if (! gc)
1311 return;
1312
1313 if (gc->clipPathId.isEmpty())
1314 return;
1315
1316 SvgClipPathHelper *clipPath = findClipPath(gc->clipPathId);
1317 if (!clipPath || clipPath->isEmpty())
1318 return;
1319
1321
1322 Q_FOREACH (KoShape *item, clipPath->shapes()) {
1323 KoShape *clonedShape = item->cloneShape();
1324 KIS_ASSERT_RECOVER(clonedShape) { continue; }
1325
1326 shapes.append(clonedShape);
1327 }
1328
1329 if (!shapeToOriginalUserCoordinates.isNull()) {
1330 const QTransform t =
1331 QTransform::fromTranslate(shapeToOriginalUserCoordinates.x(),
1332 shapeToOriginalUserCoordinates.y());
1333
1334 Q_FOREACH(KoShape *s, shapes) {
1336 }
1337 }
1338
1339 KoClipPath *clipPathObject = new KoClipPath(shapes,
1342 shape->setClipPath(clipPathObject);
1343}
Clip path used to clip shapes.
void applyAbsoluteTransformation(const QTransform &matrix)
Definition KoShape.cpp:353
void setClipPath(KoClipPath *clipPath)
Sets a new clip path, removing the old one.
Definition KoShape.cpp:926
virtual KoShape * cloneShape() const
creates a deep copy of the shape or shape's subtree
Definition KoShape.cpp:172
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 936 of file SvgParser.cpp.

937{
938 if (!shape) return;
939
941 KIS_ASSERT(gc);
942
943 if (!dynamic_cast<KoShapeGroup*>(shape)) {
944 applyFillStyle(shape);
945 applyStrokeStyle(shape);
946 }
947
948 if (!gc->display || !gc->visible) {
959 shape->setVisible(false);
960 }
961 shape->setTransparency(1.0 - gc->opacity);
962
963 applyPaintOrder(shape);
964}
void setTransparency(qreal transparency)
Definition KoShape.cpp:642
void setVisible(bool on)
Definition KoShape.cpp:795
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 921 of file SvgParser.cpp.

922{
923 if (!shape) return;
924
926
927 if (KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape)) {
928 applyMarkers(pathShape);
929 }
930
931 applyClipping(shape, shapeToOriginalUserCoordinates);
932 applyMaskClipping(shape, shapeToOriginalUserCoordinates);
933
934}
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 1135 of file SvgParser.cpp.

1136{
1138 if (! gc)
1139 return;
1140
1143 } else if (gc->fillType == SvgGraphicsContext::Solid) {
1145 } else if (gc->fillType == SvgGraphicsContext::Complex) {
1146 // try to find referenced gradient
1147 SvgGradientHelper *gradient = findGradient(gc->fillId);
1148 if (gradient) {
1149 QTransform transform;
1150
1151 if (gradient->isMeshGradient()) {
1153
1154 QScopedPointer<SvgMeshGradient> result(prepareMeshGradientForShape(gradient, shape, gc));
1155
1156 bg = toQShared(new KoMeshGradientBackground(result.data(), transform));
1157 shape->setBackground(bg);
1158 } else if (gradient->gradient()) {
1159 QGradient *result = prepareGradientForShape(gradient, shape, gc, &transform);
1160 if (result) {
1162 bg = toQShared(new KoGradientBackground(result));
1163 bg->setTransform(transform);
1164 shape->setBackground(bg);
1165 }
1166 }
1167 } else {
1169 findPattern(gc->fillId, shape);
1170
1171 if (pattern) {
1172 shape->setBackground(pattern);
1173 } else {
1174 // no referenced fill found, use fallback color
1176 }
1177 }
1178 } else if (gc->fillType == SvgGraphicsContext::Inherit) {
1179 shape->setInheritBackground(true);
1180 }
1181
1182 KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
1183 if (path)
1184 path->setFillRule(gc->fillRule);
1185}
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:773
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
Definition KoShape.cpp:751
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 2239 of file SvgParser.cpp.

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

1252{
1254 if (!gc)
1255 return;
1256
1257 if (!gc->markerStartId.isEmpty() && m_markers.contains(gc->markerStartId)) {
1259 }
1260
1261 if (!gc->markerMidId.isEmpty() && m_markers.contains(gc->markerMidId)) {
1263 }
1264
1265 if (!gc->markerEndId.isEmpty() && m_markers.contains(gc->markerEndId)) {
1267 }
1268
1270}
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 1345 of file SvgParser.cpp.

1346{
1348 if (!gc)
1349 return;
1350
1351 if (gc->clipMaskId.isEmpty())
1352 return;
1353
1354
1355 QSharedPointer<KoClipMask> originalClipMask = m_clipMasks.value(gc->clipMaskId);
1356 if (!originalClipMask || originalClipMask->isEmpty()) return;
1357
1358 KoClipMask *clipMask = originalClipMask->clone();
1359
1360 clipMask->setExtraShapeOffset(shapeToOriginalUserCoordinates);
1361
1362 shape->setClipMask(clipMask);
1363}
void setClipMask(KoClipMask *clipMask)
Sets a new clip mask, removing the old one. The mask is owned by the shape.
Definition KoShape.cpp:938
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 1272 of file SvgParser.cpp.

1273{
1275 if (!gc)
1276 return;
1277
1278 if (!gc->paintOrder.isEmpty() && gc->paintOrder != "inherit") {
1279 QStringList paintOrder = gc->paintOrder.split(" ");
1281 Q_FOREACH(const QString p, paintOrder) {
1282 if (p == "fill") {
1283 order.append(KoShape::Fill);
1284 } else if (p == "stroke") {
1285 order.append(KoShape::Stroke);
1286 } else if (p == "markers") {
1287 order.append(KoShape::Markers);
1288 }
1289 }
1290 if (paintOrder.size() == 1 && order.isEmpty()) { // Normal
1292 }
1293 if (order.size() == 1) {
1294 if (order.first() == KoShape::Fill) {
1296 } else if (order.first() == KoShape::Stroke) {
1298 } else if (order.first() == KoShape::Markers) {
1300 }
1301 } else if (order.size() > 1) {
1302 shape->setPaintOrder(order.at(0), order.at(1));
1303 }
1304 }
1305}
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:669
static QVector< PaintOrder > defaultPaintOrder()
default paint order as per SVG specification
Definition KoShape.cpp:704
@ 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 1208 of file SvgParser.cpp.

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

968{
969 applyStyle(obj, m_context.styleParser().collectStyles(e), shapeToOriginalUserCoordinates);
970}
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 972 of file SvgParser.cpp.

973{
975 if (!gc)
976 return;
977
979
980 if (!obj)
981 return;
982
983 if (!dynamic_cast<KoShapeGroup*>(obj)) {
984 applyFillStyle(obj);
985 applyStrokeStyle(obj);
986 }
987
988 if (KoPathShape *pathShape = dynamic_cast<KoPathShape*>(obj)) {
989 applyMarkers(pathShape);
990 }
991
992 applyClipping(obj, shapeToOriginalUserCoordinates);
993 applyMaskClipping(obj, shapeToOriginalUserCoordinates);
994
995 if (!gc->display || !gc->visible) {
996 obj->setVisible(false);
997 }
998 obj->setTransparency(1.0 - gc->opacity);
999 applyPaintOrder(obj);
1000}
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 1511 of file SvgParser.cpp.

1512{
1514
1515 QRectF viewRect = gc->currentBoundingBox;
1516 QTransform viewTransform;
1517
1519 &viewRect, &viewTransform)) {
1520
1521 gc->matrix = viewTransform * gc->matrix;
1522 gc->currentBoundingBox = viewRect;
1523 }
1524}
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 2193 of file SvgParser.cpp.

2194{
2195 QList<KoShape*> shapeList;
2196 if (value == "auto" || value == "none") {
2197 return shapeList;
2198 }
2199 QStringList params = value.split(")");
2200 Q_FOREACH(const QString param, params) {
2201 KoShape *s = createShapeFromCSS(e, param.trimmed()+")", context, hideShapesFromDefs);
2202 if (s) {
2203 shapeList.append(s);
2204 }
2205 }
2206 return shapeList;
2207}
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 2040 of file SvgParser.cpp.

2041{
2043
2045 if (obj) {
2047 const QPointF extraOffset = extraShapeOffset(obj, m_context.currentGC()->matrix);
2048
2049 SvgStyles objStyle = style.isEmpty() ? m_context.styleParser().collectStyles(b) : style;
2050 m_context.styleParser().parseFont(objStyle);
2051 applyStyle(obj, objStyle, extraOffset);
2052
2053 // handle id
2054 applyId(b.attribute("id"), obj);
2057 }
2058
2060
2061 if (obj) {
2063 }
2064
2065 return obj;
2066}
QPointF extraShapeOffset(const KoShape *shape, const QTransform coordinateSystemOnLoading)
QMap< QString, QString > SvgStyles
void setZIndex(qint16 zIndex)
Definition KoShape.cpp:787
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 2014 of file SvgParser.cpp.

2015{
2018
2020 if (obj) {
2022 const QPointF extraOffset = extraShapeOffset(obj, m_context.currentGC()->matrix);
2023
2024 applyCurrentStyle(obj, extraOffset);
2025
2026 // handle id
2027 applyId(b.attribute("id"), obj);
2030 }
2031
2033
2034 if (obj) {
2036 }
2037 return obj;
2038}
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 1944 of file SvgParser.cpp.

1945{
1946 KoShape *obj = 0;
1947 if (element.tagName() == "line") {
1948 KoPathShape *path = static_cast<KoPathShape*>(createShape(KoPathShapeId));
1949 if (path) {
1950 double x1 = element.attribute("x1").isEmpty() ? 0.0 : parseUnitX(element.attribute("x1"));
1951 double y1 = element.attribute("y1").isEmpty() ? 0.0 : parseUnitY(element.attribute("y1"));
1952 double x2 = element.attribute("x2").isEmpty() ? 0.0 : parseUnitX(element.attribute("x2"));
1953 double y2 = element.attribute("y2").isEmpty() ? 0.0 : parseUnitY(element.attribute("y2"));
1954 path->clear();
1955 path->moveTo(QPointF(x1, y1));
1956 path->lineTo(QPointF(x2, y2));
1957 path->normalize();
1958 obj = path;
1959 }
1960 } else if (element.tagName() == "polyline" || element.tagName() == "polygon") {
1961 KoPathShape *path = static_cast<KoPathShape*>(createShape(KoPathShapeId));
1962 if (path) {
1963 path->clear();
1964
1965 bool bFirst = true;
1966 QStringList pointList = SvgUtil::simplifyList(element.attribute("points"));
1967 for (QStringList::Iterator it = pointList.begin(); it != pointList.end(); ++it) {
1968 QPointF point;
1970 ++it;
1971 if (it == pointList.end())
1972 break;
1974 if (bFirst) {
1975 path->moveTo(point);
1976 bFirst = false;
1977 } else
1978 path->lineTo(point);
1979 }
1980 if (element.tagName() == "polygon")
1981 path->close();
1982
1983 path->setPosition(path->normalize());
1984
1985 obj = path;
1986 }
1987 } else if (element.tagName() == "path") {
1988 KoPathShape *path = static_cast<KoPathShape*>(createShape(KoPathShapeId));
1989 if (path) {
1990 path->clear();
1991
1992 KoPathShapeLoader loader(path);
1993 loader.parseSvg(element.attribute("d"), true);
1994 path->setPosition(path->normalize());
1995
1996 QPointF newPosition = QPointF(SvgUtil::fromUserSpace(path->position().x()),
1997 SvgUtil::fromUserSpace(path->position().y()));
1998 QSizeF newSize = QSizeF(SvgUtil::fromUserSpace(path->size().width()),
1999 SvgUtil::fromUserSpace(path->size().height()));
2000
2001 path->setSize(newSize);
2002 path->setPosition(newPosition);
2003
2004 if (element.hasAttribute("sodipodi:nodetypes")) {
2005 path->loadNodeTypes(element.attribute("sodipodi:nodetypes"));
2006 }
2007 obj = path;
2008 }
2009 }
2010
2011 return obj;
2012}
#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 2209 of file SvgParser.cpp.

2210{
2211 KoShapeFactoryBase *factory = KoShapeRegistry::instance()->get(shapeID);
2212 if (!factory) {
2213 debugFlake << "Could not find factory for shape id" << shapeID;
2214 return 0;
2215 }
2216
2218 if (!shape) {
2219 debugFlake << "Could not create Default shape for shape id" << shapeID;
2220 return 0;
2221 }
2222 if (shape->shapeId().isEmpty()) {
2223 shape->setShapeId(factory->id());
2224 }
2225
2226 // reset transformation that might come from the default shape
2227 shape->setTransformation(QTransform());
2228
2229 // reset border
2230 // ??? KoShapeStrokeModelSP oldStroke = shape->stroke();
2232
2233 // reset fill
2235
2236 return shape;
2237}
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:880
void setTransformation(const QTransform &matrix)
Definition KoShape.cpp:374
void setShapeId(const QString &id)
Definition KoShape.cpp:885

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 2113 of file SvgParser.cpp.

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

2069{
2070 KoShape *object = 0;
2071
2072
2073 const QString tagName = SvgUtil::mapExtendedShapeTag(element.tagName(), element);
2075
2076 foreach (KoShapeFactoryBase *f, factories) {
2077 KoShape *shape = f->createDefaultShape(m_documentResourceManager);
2078 if (!shape)
2079 continue;
2080
2081 SvgShape *svgShape = dynamic_cast<SvgShape*>(shape);
2082 if (!svgShape) {
2083 delete shape;
2084 continue;
2085 }
2086
2087 // reset transformation that might come from the default shape
2088 shape->setTransformation(QTransform());
2089
2090 // reset border
2091 KoShapeStrokeModelSP oldStroke = shape->stroke();
2093
2094 // reset fill
2096
2097 if (!svgShape->loadSvg(element, context)) {
2098 delete shape;
2099 continue;
2100 }
2101
2102 object = shape;
2103 break;
2104 }
2105
2106 if (!object) {
2107 object = createPath(element);
2108 }
2109
2110 return object;
2111}
QList< KoShapeFactoryBase * > factoriesForElement(const QString &nameSpace, const QString &elementName)
virtual KoShapeStrokeModelSP stroke() const
Definition KoShape.cpp:890
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 1547 of file SvgParser.cpp.

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

References m_documentDescription.

◆ documentTitle()

QString SvgParser::documentTitle ( ) const

Definition at line 1542 of file SvgParser.cpp.

1543{
1544 return m_documentTitle;
1545}
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 319 of file SvgParser.cpp.

320{
321 return m_clipPaths.contains(id) ? &m_clipPaths[id] : 0;
322}
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 282 of file SvgParser.cpp.

283{
284 SvgGradientHelper *result = 0;
285
286 // check if gradient was already parsed, and return it
287 if (m_gradients.contains(id)) {
288 result = &m_gradients[ id ];
289 }
290
291 // check if gradient was stored for later parsing
292 if (!result && m_context.hasDefinition(id)) {
293 const QDomElement &e = m_context.definition(id);
294 if (e.tagName().contains("Gradient")) {
295 result = parseGradient(m_context.definition(id));
296 } else if (e.tagName() == "meshgradient") {
298 }
299 }
300
301 return result;
302}
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 304 of file SvgParser.cpp.

305{
307
308 // check if gradient was stored for later parsing
309 if (m_context.hasDefinition(id)) {
310 const QDomElement &e = m_context.definition(id);
311 if (e.tagName() == "pattern") {
312 result = parsePattern(m_context.definition(id), shape);
313 }
314 }
315
316 return result;
317}
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 1641 of file SvgParser.cpp.

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

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 1624 of file SvgParser.cpp.

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

◆ knownMarkers()

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

Definition at line 1537 of file SvgParser.cpp.

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

References m_markers.

◆ parseAngular()

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

parses a angular attribute values, result in radians

Definition at line 347 of file SvgParser.cpp.

348{
350}
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 869 of file SvgParser.cpp.

870{
872
873 const QString id = e.attribute("id");
874 if (id.isEmpty()) return false;
875
876 clipMask->setCoordinates(KoFlake::coordinatesFromString(e.attribute("maskUnits"), KoFlake::ObjectBoundingBox));
877 clipMask->setContentCoordinates(KoFlake::coordinatesFromString(e.attribute("maskContentUnits"), KoFlake::UserSpaceOnUse));
878
879 QRectF maskRect;
880
881 if (clipMask->coordinates() == KoFlake::ObjectBoundingBox) {
882 maskRect.setRect(
883 SvgUtil::fromPercentage(e.attribute("x", "-10%")),
884 SvgUtil::fromPercentage(e.attribute("y", "-10%")),
885 SvgUtil::fromPercentage(e.attribute("width", "120%")),
886 SvgUtil::fromPercentage(e.attribute("height", "120%")));
887 } else {
888 maskRect.setRect(
889 parseUnitX(e.attribute("x", "-10%")), // yes, percents are insane in this case,
890 parseUnitY(e.attribute("y", "-10%")), // but this is what SVG 1.1 tells us...
891 parseUnitX(e.attribute("width", "120%")),
892 parseUnitY(e.attribute("height", "120%")));
893 }
894
895 clipMask->setMaskRect(maskRect);
896
897
898 // ensure that the clip mask is loaded in local coordinates system
900 m_context.currentGC()->matrix = QTransform();
902
903 KoShape *clipShape = parseGroup(e);
904
906
907 if (!clipShape) return false;
908 clipMask->setShapes({clipShape});
909
910 m_clipMasks.insert(id, clipMask);
911 return true;
912}
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 842 of file SvgParser.cpp.

843{
844 SvgClipPathHelper clipPath;
845
846 const QString id = e.attribute("id");
847 if (id.isEmpty()) return false;
848
849 clipPath.setClipPathUnits(
850 KoFlake::coordinatesFromString(e.attribute("clipPathUnits"), KoFlake::UserSpaceOnUse));
851
852 // ensure that the clip path is loaded in local coordinates system
854 m_context.currentGC()->matrix = QTransform();
856
857 KoShape *clipShape = parseGroup(e);
858
860
861 if (!clipShape) return false;
862
863 clipPath.setShapes({clipShape});
864 m_clipPaths.insert(id, clipPath);
865
866 return true;
867}
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 1808 of file SvgParser.cpp.

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

References parseSingleElement(), and shapes().

◆ parseDefsElement()

void SvgParser::parseDefsElement ( const QDomElement & e)

Definition at line 1849 of file SvgParser.cpp.

1850{
1851 KIS_SAFE_ASSERT_RECOVER_RETURN(e.tagName() == "defs");
1853}
#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 353 of file SvgParser.cpp.

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

1568{
1569 if (createContext) {
1571 }
1572
1573 KoShapeGroup *group = new KoShapeGroup();
1574 group->setZIndex(m_context.nextZIndex());
1575
1576 // groups should also have their own coordinate system!
1578 const QPointF extraOffset = extraShapeOffset(group, m_context.currentGC()->matrix);
1579
1581
1582 QList<KoShape*> childShapes;
1583
1584 if (!overrideChildrenFrom.isNull()) {
1585 // we upload styles from both: <use> and <defs>
1586 uploadStyleToContext(overrideChildrenFrom);
1587 if (overrideChildrenFrom.tagName() == "symbol") {
1588 childShapes = {parseGroup(overrideChildrenFrom)};
1589 } else {
1590 childShapes = parseSingleElement(overrideChildrenFrom, 0);
1591 }
1592 } else {
1593 childShapes = parseContainer(b);
1594 }
1595
1596 // handle id
1597 applyId(b.attribute("id"), group);
1598
1599 if (b.hasAttribute(KoSvgTextShape_TEXTCONTOURGROUP)) {
1600 Q_FOREACH(KoShape *shape, childShapes) {
1601 if (shape->shapeId() == KoSvgTextShape_SHAPEID) {
1602 shape->setTransformation(group->transformation());
1603
1604 if (createContext) {
1606 }
1607 return shape;
1608 }
1609 }
1610 }
1611 addToGroup(childShapes, group);
1612
1613 applyCurrentStyle(group, extraOffset); // apply style to this group after size is set
1614
1615 parseMetadataApplyToShape(b, group);
1616
1617 if (createContext) {
1619 }
1620
1621 return group;
1622}
#define KoSvgTextShape_SHAPEID
#define KoSvgTextShape_TEXTCONTOURGROUP
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:383
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 738 of file SvgParser.cpp.

739{
740 const QString id = e.attribute("id");
741 if (id.isEmpty()) return false;
742
743 QScopedPointer<KoMarker> marker(new KoMarker());
744 marker->setCoordinateSystem(
745 KoMarker::coordinateSystemFromString(e.attribute("markerUnits", "strokeWidth")));
746
747 marker->setReferencePoint(QPointF(parseUnitX(e.attribute("refX")),
748 parseUnitY(e.attribute("refY"))));
749
750 marker->setReferenceSize(QSizeF(parseUnitX(e.attribute("markerWidth", "3")),
751 parseUnitY(e.attribute("markerHeight", "3"))));
752
753 const QString orientation = e.attribute("orient", "0");
754
755 if (orientation == "auto") {
756 marker->setAutoOrientation(true);
757 } else {
758 marker->setExplicitOrientation(parseAngular(orientation));
759 }
760
761 // ensure that the clip path is loaded in local coordinates system
763 m_context.currentGC()->matrix = QTransform();
764 m_context.currentGC()->currentBoundingBox = QRectF(QPointF(0, 0), marker->referenceSize());
765
766 KoShape *markerShape = parseGroup(e);
767
769
770 if (!markerShape) return false;
771
772 marker->setShapes({markerShape});
773
774 m_markers.insert(id, QExplicitlySharedDataPointer<KoMarker>(marker.take()));
775
776 return true;
777}
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 464 of file SvgParser.cpp.

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

556{
557 // path and its associated color
559
561 if (!gc) return rawstops;
562
563 QDomElement e = meshpatchNode.toElement();
564
565 QDomElement stop;
566
567 forEachElement(stop, e) {
568 qreal X = 0; // dummy value, don't care, just to ensure the function won't blow up (also to avoid a Coverity issue)
569 QColor color = m_context.styleParser().parseColorStop(stop, gc, X).second;
570
571 QString pathStr = stop.attribute("path");
572
573 rawstops.append({pathStr, color});
574 }
575
576 return rawstops;
577}
#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 822 of file SvgParser.cpp.

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

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

1856{
1858
1859 // save definition for later instantiation with 'use'
1861 if (deferredUseStore) {
1862 deferredUseStore->checkPendingUse(b, shapes);
1863 }
1864
1865 if (b.tagName() == "svg") {
1866 shapes += parseSvg(b);
1867 } else if (b.tagName() == "g" || b.tagName() == "a") {
1868 // treat svg link <a> as group so we don't miss its child elements
1869 shapes += parseGroup(b);
1870 } else if (b.tagName() == "symbol") {
1871 parseSymbol(b);
1872 } else if (b.tagName() == "switch") {
1874 shapes += parseContainer(b);
1876 } else if (b.tagName() == "defs") {
1877 if (b.childNodes().count() > 0) {
1883 KoShape *defsShape = parseGroup(b);
1884 defsShape->setVisible(false);
1885 m_defsShapes << defsShape; // TODO: where to delete the shape!?
1886
1887 }
1888 } else if (b.tagName() == "linearGradient" || b.tagName() == "radialGradient") {
1889 } else if (b.tagName() == "pattern") {
1890 } else if (b.tagName() == "filter") {
1891 // not supported!
1892 } else if (b.tagName() == "clipPath") {
1893 parseClipPath(b);
1894 } else if (b.tagName() == "mask") {
1895 parseClipMask(b);
1896 } else if (b.tagName() == "marker") {
1897 parseMarker(b);
1898 } else if (b.tagName() == "style") {
1900 } else if (b.tagName() == "text" || b.tagName() == "tspan" || b.tagName() == "textPath") {
1902 } else if (b.tagName() == "rect" || b.tagName() == "ellipse" || b.tagName() == "circle" || b.tagName() == "line" || b.tagName() == "polyline"
1903 || b.tagName() == "polygon" || b.tagName() == "path" || b.tagName() == "image") {
1904 KoShape *shape = createObjectDirect(b);
1905
1906 if (shape) {
1907 if (!shape->outlineRect().isNull() || !shape->boundingRect().isNull()) {
1908 shapes.append(shape);
1909 } else {
1910 debugFlake << "WARNING: shape is totally empty!" << shape->shapeId() << ppVar(shape->outlineRect());
1911 debugFlake << " " << shape->shapeId() << ppVar(shape->outline());
1912 {
1913 QString string;
1914 QTextStream stream(&string);
1916 stream << b;
1917 debugFlake << " " << string;
1918 }
1919 delete shape;
1920 }
1921 }
1922 } else if (b.tagName() == "use") {
1923 KoShape* s = parseUse(b, deferredUseStore);
1924 if (s) {
1925 shapes += s;
1926 }
1927 } else if (b.tagName() == "color-profile") {
1929 } else {
1930 // this is an unknown element, so try to load it anyway
1931 // there might be a shape that handles that element
1932 KoShape *shape = createObject(b);
1933 if (shape) {
1934 shapes.append(shape);
1935 }
1936 }
1937
1938 return shapes;
1939}
virtual QRectF outlineRect() const
Definition KoShape.cpp:566
virtual QPainterPath outline() const
Definition KoShape.cpp:559
virtual QRectF boundingRect() const
Get the bounding box of the shape.
Definition KoShape.cpp:299
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 1412 of file SvgParser.cpp.

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

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

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 1673 of file SvgParser.cpp.

1673 {
1674 QDomText t = getTheOnlyTextChild(e);
1675 if (!t.isNull()) {
1676 textLoader.loadSvgText(t, m_context);
1677 } else {
1678 textLoader.enterNodeSubtree();
1679 for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
1680 QDomElement b = n.toElement();
1681 if (b.tagName() == "title" || b.tagName() == "desc") continue;
1682 textLoader.nextNode();
1683 if (b.isNull()) {
1684 textLoader.loadSvgText(n.toText(), m_context);
1685 KoShape *styleDummy = new KoPathShape();
1686 applyCurrentBasicStyle(styleDummy);
1687 textLoader.setStyleInfo(styleDummy);
1688 } else {
1691 textLoader.loadSvg(b, m_context);
1692 if (b.hasChildNodes()) {
1693 parseTextChildren(b, textLoader, hideShapesFromDefs);
1694 }
1695 textLoader.setTextPathOnCurrentNode(getTextPath(b, hideShapesFromDefs));
1697 }
1698 }
1699 textLoader.leaveNodeSubtree();
1700 }
1701 KoShape *styleDummy = new KoPathShape();
1702 applyCurrentBasicStyle(styleDummy);
1703 textLoader.setStyleInfo(styleDummy);
1704}
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 1706 of file SvgParser.cpp.

1707{
1708 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(e.tagName() == "text" || e.tagName() == "tspan" || e.tagName() == "textPath", 0);
1710 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(e.tagName() == "text" || !mergeIntoShape, 0);
1711
1712 KoSvgTextShape *rootTextShape = 0;
1713
1714 bool hideShapesFromDefs = true;
1715 if (mergeIntoShape) {
1716 rootTextShape = mergeIntoShape;
1717 hideShapesFromDefs = false;
1718 } else {
1719 KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value("KoSvgTextShapeID");
1720 rootTextShape = dynamic_cast<KoSvgTextShape*>(factory->createDefaultShape(m_documentResourceManager));
1721 }
1722 KoSvgTextLoader textLoader(rootTextShape);
1723
1724 if (rootTextShape) {
1725 m_isInsideTextSubtree = true;
1726 }
1727
1730
1731 if (rootTextShape) {
1732 if (!m_context.currentGC()->shapeInsideValue.isEmpty()) {
1734 rootTextShape->setShapesInside(shapesInside);
1735 }
1736
1737 if (!m_context.currentGC()->shapeSubtractValue.isEmpty()) {
1738 QList<KoShape*> shapesSubtract = createListOfShapesFromCSS(e, m_context.currentGC()->shapeSubtractValue, m_context, hideShapesFromDefs);
1739 rootTextShape->setShapesSubtract(shapesSubtract);
1740 }
1741 }
1742
1743 if (e.hasAttribute("krita:textVersion")) {
1744 m_context.currentGC()->textProperties.setProperty(KoSvgTextProperties::KraTextVersionId, e.attribute("krita:textVersion", "1").toInt());
1745
1747 debugFlake << "WARNING: \"krita:textVersion\" attribute appeared in non-root text shape";
1748 }
1749 }
1750
1751 parseMetadataApplyToShape(e, rootTextShape);
1752
1753 if (!mergeIntoShape) {
1754 rootTextShape->setZIndex(m_context.nextZIndex());
1755 }
1756
1759
1760 static const KoID warning("warn_text_version_1",
1761 i18nc("warning while loading SVG text",
1762 "The document has vector text created "
1763 "in Krita 4.x. When you save the document, "
1764 "the text object will be converted into "
1765 "Krita 5 format that will no longer be "
1766 "compatible with Krita 4.x"));
1767
1768 if (!m_warnings.contains(warning)) {
1769 m_warnings << warning;
1770 }
1771 }
1772
1773 textLoader.loadSvg(e, m_context, m_resolveTextPropertiesForTopLevel);
1774
1775 // 1) apply transformation only in case we are not overriding the shape!
1776 // 2) the transformation should be applied *before* the shape is added to the group!
1777 if (!mergeIntoShape) {
1778 // groups should also have their own coordinate system!
1780 const QPointF extraOffset = extraShapeOffset(rootTextShape, m_context.currentGC()->matrix);
1781
1782 // handle id
1783 applyId(e.attribute("id"), rootTextShape);
1784 applyCurrentStyle(rootTextShape, extraOffset); // apply style to this group after size is set
1785 } else {
1786 m_context.currentGC()->matrix = mergeIntoShape->absoluteTransformation();
1787 applyCurrentBasicStyle(rootTextShape);
1788 }
1789
1790 QDomText onlyTextChild = getTheOnlyTextChild(e);
1791 if (!onlyTextChild.isNull()) {
1792 textLoader.loadSvgText(onlyTextChild, m_context);
1793
1794 } else {
1795 parseTextChildren(e, textLoader, hideShapesFromDefs);
1796 }
1797
1799
1800 m_isInsideTextSubtree = false;
1801
1802 //rootTextShape->debugParsing();
1803
1804
1805 return rootTextShape;
1806}
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 327 of file SvgParser.cpp.

328{
329 return SvgUtil::parseUnit(m_context.currentGC(), m_context.resolvedProperties(), unit, horiz, vert, bbox);
330}
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 332 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 342 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 337 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 1365 of file SvgParser.cpp.

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

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

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 1552 of file SvgParser.cpp.

1553{
1555}
void setFileFetcher(FileFetcherFunc func)

References m_context, and SvgLoadingContext::setFileFetcher().

◆ setFillStrokeInheritByDefault()

void SvgParser::setFillStrokeInheritByDefault ( const bool enable)

Definition at line 257 of file SvgParser.cpp.

258{
260}

References m_inheritStrokeFillByDefault.

◆ setResolution()

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

◆ setResolveTextPropertiesForTopLevel()

void SvgParser::setResolveTextPropertiesForTopLevel ( const bool enable)

Definition at line 262 of file SvgParser.cpp.

263{
265}

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.exists()) {
230 file.open(QIODevice::ReadOnly);
231 return file.readAll();
232 }
233 }
234 return QByteArray();
235 });
236}
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 1631 of file SvgParser.cpp.

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

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 267 of file SvgParser.cpp.

268{
269 return m_shapes;
270}

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 272 of file SvgParser.cpp.

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

References m_symbols.

◆ uploadStyleToContext()

◆ warnings()

QStringList SvgParser::warnings ( ) const

Definition at line 1526 of file SvgParser.cpp.

1527{
1529
1530 Q_FOREACH (const KoID &id, m_warnings) {
1531 warnings << id.name();
1532 }
1533
1534 return warnings;
1535}
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: