Commit b1293f77 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement loading and saving of text shape into the stripped SVG

The conversion is performed by KoSvgTextShapeMarkupConverter. It also
provides some kind of feedback about the errors in the user's text.
parent 95034944
......@@ -206,6 +206,7 @@ set(kritaflake_SRCS
text/KoSvgTextProperties.cpp
text/KoSvgTextChunkShape.cpp
text/KoSvgTextShape.cpp
text/KoSvgTextShapeMarkupConverter.cpp
FlakeDebug.cpp
tests/MockShapes.cpp
......
......@@ -37,7 +37,7 @@ KoShapeUngroupCommand::KoShapeUngroupCommand(KoShapeContainer *container, const
d->shapes = orderdShapes;
QList<KoShape*> ancestors = d->container->parent()? d->container->parent()->shapes(): topLevelShapes;
if (ancestors.count()) {
if (!ancestors.isEmpty()) {
qSort(ancestors.begin(), ancestors.end(), KoShape::compareShapeZIndex);
QList<KoShape*>::const_iterator it(qFind(ancestors, d->container));
......
......@@ -1271,12 +1271,18 @@ KoXmlText getTheOnlyTextChild(const KoXmlElement &e)
firstChild.toText() : KoXmlText();
}
KoShape *SvgParser::parseTextElement(const KoXmlElement &e)
KoShape *SvgParser::parseTextElement(const KoXmlElement &e, KoSvgTextShape *mergeIntoShape)
{
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(e.tagName() == "text" || e.tagName() == "tspan", 0);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_isInsideTextSubtree || e.tagName() == "text", 0);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(e.tagName() == "text" || !mergeIntoShape, 0);
KoSvgTextShape *rootTextShape = 0;
if (e.tagName() == "text") {
rootTextShape = mergeIntoShape ? mergeIntoShape : new KoSvgTextShape();
}
KoSvgTextShape *rootTextShape = e.tagName() == "text" ? new KoSvgTextShape() : 0;
if (rootTextShape) {
m_isInsideTextSubtree = true;
}
......@@ -1297,13 +1303,18 @@ KoShape *SvgParser::parseTextElement(const KoXmlElement &e)
addToGroup(childShapes, textChunk);
}
// groups should also have their own coordinate system!
textChunk->applyAbsoluteTransformation(m_context.currentGC()->matrix);
const QPointF extraOffset = extraShapeOffset(textChunk, m_context.currentGC()->matrix);
// apply transformation only in case we are not overriding the shape!
if (!mergeIntoShape) {
// groups should also have their own coordinate system!
textChunk->applyAbsoluteTransformation(m_context.currentGC()->matrix);
const QPointF extraOffset = extraShapeOffset(textChunk, m_context.currentGC()->matrix);
// handle id
applyId(e.attribute("id"), textChunk);
applyCurrentStyle(textChunk, extraOffset); // apply style to this group after size is set
// handle id
applyId(e.attribute("id"), textChunk);
applyCurrentStyle(textChunk, extraOffset); // apply style to this group after size is set
} else {
applyCurrentBasicStyle(textChunk);
}
m_context.popGraphicsContext();
......@@ -1365,6 +1376,12 @@ QList<KoShape*> SvgParser::parseContainer(const KoXmlElement &e, bool parseTextN
return shapes;
}
void SvgParser::parseDefsElement(const KoXmlElement &e)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(e.tagName() == "defs");
parseSingleElement(e);
}
QList<KoShape*> SvgParser::parseSingleElement(const KoXmlElement &b)
{
QList<KoShape*> shapes;
......@@ -1390,6 +1407,8 @@ QList<KoShape*> SvgParser::parseSingleElement(const KoXmlElement &b)
*/
KoShape *defsShape = parseGroup(b);
defsShape->setVisible(false);
// TODO: where to delete the shape!?
}
} else if (b.tagName() == "linearGradient" || b.tagName() == "radialGradient") {
} else if (b.tagName() == "pattern") {
......
......@@ -46,7 +46,7 @@ class KoDocumentResourceManager;
class KoVectorPatternBackground;
class KoMarker;
class KoPathShape;
class KoSvgTextShape;
class KRITAFLAKE_EXPORT SvgParser
{
......@@ -70,12 +70,14 @@ public:
QList<QExplicitlySharedDataPointer<KoMarker>> knownMarkers() const;
void parseDefsElement(const KoXmlElement &e);
KoShape* parseTextElement(const KoXmlElement &e, KoSvgTextShape *mergeIntoShape = 0);
protected:
/// Parses a group-like element element, saving all its topmost properties
KoShape* parseGroup(const KoXmlElement &e, const KoXmlElement &overrideChildrenFrom = KoXmlElement());
KoShape* parseTextNode(const KoXmlText &e);
KoShape* parseTextElement(const KoXmlElement &e);
/// Parses a container element, returning a list of child shapes
QList<KoShape*> parseContainer(const KoXmlElement &, bool parseTextNodes = false);
QList<KoShape*> parseSingleElement(const KoXmlElement &b);
......
......@@ -39,13 +39,16 @@
class Q_DECL_HIDDEN SvgSavingContext::Private
{
public:
Private(QIODevice &outputDevice)
: output(outputDevice), styleWriter(0), shapeWriter(0)
Private(QIODevice *_mainDevice, QIODevice *_styleDevice)
: mainDevice(_mainDevice)
, styleDevice(_styleDevice)
, styleWriter(0)
, shapeWriter(0)
, saveInlineImages(true)
{
styleWriter = new KoXmlWriter(&styleBuffer, 1);
styleWriter.reset(new KoXmlWriter(&styleBuffer, 1));
styleWriter->startElement("defs");
shapeWriter = new KoXmlWriter(&shapeBuffer, 1);
shapeWriter.reset(new KoXmlWriter(&shapeBuffer, 1));
const qreal scaleToUserSpace = SvgUtil::toUserSpace(1.0);
userSpaceMatrix.scale(scaleToUserSpace, scaleToUserSpace);
......@@ -53,24 +56,30 @@ public:
~Private()
{
delete styleWriter;
delete shapeWriter;
}
QIODevice &output;
QIODevice *mainDevice;
QIODevice *styleDevice;
QBuffer styleBuffer;
QBuffer shapeBuffer;
KoXmlWriter *styleWriter;
KoXmlWriter *shapeWriter;
QScopedPointer<KoXmlWriter> styleWriter;
QScopedPointer<KoXmlWriter> shapeWriter;
QHash<QString, int> uniqueNames;
QHash<const KoShape*, QString> shapeIds;
QTransform userSpaceMatrix;
bool saveInlineImages;
bool strippedTextMode = false;
};
SvgSavingContext::SvgSavingContext(QIODevice &outputDevice, bool saveInlineImages)
: d(new Private(outputDevice))
: d(new Private(&outputDevice, 0))
{
d->saveInlineImages = saveInlineImages;
}
SvgSavingContext::SvgSavingContext(QIODevice &shapesDevice, QIODevice &styleDevice, bool saveInlineImages)
: d(new Private(&shapesDevice, &styleDevice))
{
d->saveInlineImages = saveInlineImages;
}
......@@ -78,9 +87,15 @@ SvgSavingContext::SvgSavingContext(QIODevice &outputDevice, bool saveInlineImage
SvgSavingContext::~SvgSavingContext()
{
d->styleWriter->endElement();
d->output.write(d->styleBuffer.data());
d->output.write("\n");
d->output.write(d->shapeBuffer.data());
if (d->styleDevice) {
d->styleDevice->write(d->styleBuffer.data());
} else {
d->mainDevice->write(d->styleBuffer.data());
d->mainDevice->write("\n");
}
d->mainDevice->write(d->shapeBuffer.data());
delete d;
}
......@@ -151,7 +166,7 @@ bool SvgSavingContext::isSavingInlineImages() const
QString SvgSavingContext::createFileName(const QString &extension)
{
QFile *file = qobject_cast<QFile*>(&d->output);
QFile *file = qobject_cast<QFile*>(d->mainDevice);
if (!file)
return QString();
......@@ -229,3 +244,13 @@ QString SvgSavingContext::saveImage(KoImageData *image)
}
return QString();
}
void SvgSavingContext::setStrippedTextMode(bool value)
{
d->strippedTextMode = value;
}
bool SvgSavingContext::strippedTextMode() const
{
return d->strippedTextMode;
}
......@@ -20,6 +20,8 @@
#ifndef SVGSAVINGCONTEXT_H
#define SVGSAVINGCONTEXT_H
#include <QtGlobal>
class KoXmlWriter;
class KoShape;
class KoImageData;
......@@ -36,6 +38,7 @@ class KRITAFLAKE_EXPORT SvgSavingContext
public:
/// Creates a new svg saving context on the specified output device
explicit SvgSavingContext(QIODevice &outputDevice, bool saveInlineImages = true);
explicit SvgSavingContext(QIODevice &shapesDevice, QIODevice &styleDevice, bool saveInlineImages = true);
/// Virtual destructor
virtual ~SvgSavingContext();
......@@ -67,6 +70,12 @@ public:
/// Saves given image and returns the href used
QString saveImage(KoImageData *image);
void setStrippedTextMode(bool value);
bool strippedTextMode() const;
private:
Q_DISABLE_COPY(SvgSavingContext);
private:
class Private;
Private * const d;
......
......@@ -140,6 +140,16 @@ bool SvgWriter::saveDetached(QIODevice &outputDevice)
return true;
}
bool SvgWriter::saveDetached(SvgSavingContext &savingContext)
{
if (m_toplevelShapes.isEmpty())
return false;
saveShapes(m_toplevelShapes, savingContext);
return true;
}
void SvgWriter::saveShapes(const QList<KoShape *> shapes, SvgSavingContext &savingContext)
{
// top level shapes
......
......@@ -62,6 +62,8 @@ public:
bool saveDetached(QIODevice &outputDevice);
bool saveDetached(SvgSavingContext &savingContext);
private:
void saveShapes(const QList<KoShape*> shapes, SvgSavingContext &savingContext);
......
......@@ -878,6 +878,139 @@ void TestSvgText::testMulticolorText()
t.test_standard("text_multicolor", QSize(30, 30), 72.0);
}
#include <KoSvgTextShapeMarkupConverter.h>
#include <KoColorBackground.h>
void TestSvgText::testConvertToStrippedSvg()
{
const QString data =
"<svg width=\"100px\" height=\"30px\""
" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
"<g id=\"test\">"
" <rect id=\"boundingRect\" x=\"4\" y=\"5\" width=\"89\" height=\"19\""
" fill=\"none\" stroke=\"red\"/>"
" <text transform=\"translate(2)\" id=\"testRect\" x=\"2\" y=\"24\""
" font-family=\"Verdana\" font-size=\"15\" fill=\"blue\" >"
" S<tspan fill=\"red\">A</tspan><![CDATA[some stuff<><><<<>]]>"
" </text>"
"</g>"
"</svg>";
SvgRenderTester t (data);
t.parser.setResolution(QRectF(QPointF(), QSizeF(30,30)) /* px */, 72.0/* ppi */);
t.run();
KoSvgTextShape *baseShape = dynamic_cast<KoSvgTextShape*>(t.findShape("testRect"));
QVERIFY(baseShape);
{
KoColorBackground *bg = dynamic_cast<KoColorBackground*>(baseShape->background().data());
QVERIFY(bg);
QCOMPARE(bg->color(), QColor(Qt::blue));
}
KoSvgTextShapeMarkupConverter converter(baseShape);
QString svgText;
QString stylesText;
QVERIFY(converter.convertToSvg(&svgText, &stylesText));
QCOMPARE(stylesText, QString("<defs/>"));
QCOMPARE(svgText, QString("<text fill=\"#0000ff\" font-family=\"Verdana\" font-size=\"15\"><tspan x=\"2\" y=\"24\">S</tspan><tspan fill=\"#ff0000\">A</tspan><tspan>some stuff&lt;&gt;&lt;&gt;&lt;&lt;&lt;&gt;</tspan></text>"));
// test loading
svgText = "<text fill=\"#00ff00\" font-family=\"Verdana\" font-size=\"19\"><tspan x=\"2\" y=\"24\">S</tspan><tspan fill=\"#ff0000\">A</tspan><tspan>some stuff&lt;&gt;&lt;&gt;&lt;&lt;&lt;&gt;</tspan></text>";
QVERIFY(converter.convertFromSvg(svgText, stylesText, QRectF(0,0,30,30), 72.0));
{
KoColorBackground *bg = dynamic_cast<KoColorBackground*>(baseShape->background().data());
QVERIFY(bg);
QCOMPARE(bg->color(), QColor(Qt::green));
}
{
KoSvgTextProperties props = baseShape->textProperties();
QVERIFY(props.hasProperty(KoSvgTextProperties::FontSizeId));
const qreal fontSize = props.property(KoSvgTextProperties::FontSizeId).toReal();
QCOMPARE(fontSize, 19.0);
}
QCOMPARE(baseShape->shapeCount(), 3);
}
void TestSvgText::testConvertToStrippedSvgNullOrigin()
{
const QString data =
"<svg width=\"100px\" height=\"30px\""
" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
"<g id=\"test\">"
" <rect id=\"boundingRect\" x=\"4\" y=\"5\" width=\"89\" height=\"19\""
" fill=\"none\" stroke=\"red\"/>"
" <text transform=\"translate(2)\" id=\"testRect\" x=\"0\" y=\"0\""
" font-family=\"Verdana\" font-size=\"15\" fill=\"blue\" >"
" S<tspan fill=\"red\">A</tspan><![CDATA[some stuff<><><<<>]]>"
" </text>"
"</g>"
"</svg>";
SvgRenderTester t (data);
t.parser.setResolution(QRectF(QPointF(), QSizeF(30,30)) /* px */, 72.0/* ppi */);
t.run();
KoSvgTextShape *baseShape = dynamic_cast<KoSvgTextShape*>(t.findShape("testRect"));
QVERIFY(baseShape);
KoSvgTextShapeMarkupConverter converter(baseShape);
QString svgText;
QString stylesText;
QVERIFY(converter.convertToSvg(&svgText, &stylesText));
QCOMPARE(stylesText, QString("<defs/>"));
QCOMPARE(svgText, QString("<text fill=\"#0000ff\" font-family=\"Verdana\" font-size=\"15\"><tspan>S</tspan><tspan fill=\"#ff0000\">A</tspan><tspan>some stuff&lt;&gt;&lt;&gt;&lt;&lt;&lt;&gt;</tspan></text>"));
}
void TestSvgText::testConvertFromIncorrectStrippedSvg()
{
QScopedPointer<KoSvgTextShape> baseShape(new KoSvgTextShape());
KoSvgTextShapeMarkupConverter converter(baseShape.data());
QString svgText;
QString stylesText;
svgText = "<text>blah text</text>";
QVERIFY(converter.convertFromSvg(svgText, stylesText, QRectF(0,0,30,30), 72.0));
QCOMPARE(converter.errors().size(), 0);
svgText = "<text>>><<><blah text</text>";
QVERIFY(!converter.convertFromSvg(svgText, stylesText, QRectF(0,0,30,30), 72.0));
qDebug() << ppVar(converter.errors());
QCOMPARE(converter.errors().size(), 1);
svgText = "<notext>blah text</notext>";
QVERIFY(!converter.convertFromSvg(svgText, stylesText, QRectF(0,0,30,30), 72.0));
qDebug() << ppVar(converter.errors());
QCOMPARE(converter.errors().size(), 1);
svgText = "<defs/>";
QVERIFY(!converter.convertFromSvg(svgText, stylesText, QRectF(0,0,30,30), 72.0));
qDebug() << ppVar(converter.errors());
QCOMPARE(converter.errors().size(), 1);
}
QTEST_MAIN(TestSvgText)
......@@ -47,6 +47,10 @@ private Q_SLOTS:
void testTextOutlineSolid();
void testNbspHandling();
void testMulticolorText();
void testConvertToStrippedSvg();
void testConvertToStrippedSvgNullOrigin();
void testConvertFromIncorrectStrippedSvg();
};
#endif // TESTSVGTEXT_H
......@@ -37,7 +37,7 @@
#include <kis_dom_utils.h>
#include <text/KoSvgTextChunkShapeLayoutInterface.h>
#include <commands/KoShapeUngroupCommand.h>
namespace {
QVector<qreal> parseListAttributeX(const QString &value, SvgLoadingContext &context)
......@@ -294,6 +294,7 @@ void writeTextListAttribute(const QString &attribute, const QVector<qreal> &valu
void appendLazy(QVector<qreal> *list, boost::optional<qreal> value, int iteration, qreal defaultValue)
{
if (!value) return;
if (value && *value == defaultValue && list->isEmpty()) return;
while (list->size() < iteration) {
list->append(defaultValue);
......@@ -308,12 +309,20 @@ bool KoSvgTextChunkShape::saveSvg(SvgSavingContext &context)
if (isRootTextNode()) {
context.shapeWriter().startElement("text", false);
context.shapeWriter().addAttribute("id", context.getID(this));
SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
SvgStyleWriter::saveSvgStyle(this, context);
if (!context.strippedTextMode()) {
context.shapeWriter().addAttribute("id", context.getID(this));
SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
SvgStyleWriter::saveSvgStyle(this, context);
} else {
SvgStyleWriter::saveSvgFill(this, context);
SvgStyleWriter::saveSvgStroke(this, context);
}
} else {
context.shapeWriter().startElement("tspan", false);
SvgStyleWriter::saveSvgBasicStyle(this, context);
if (!context.strippedTextMode()) {
SvgStyleWriter::saveSvgBasicStyle(this, context);
}
}
if (layoutInterface()->isTextNode()) {
......@@ -397,6 +406,27 @@ void KoSvgTextChunkShapePrivate::loadContextBasedProperties(SvgGraphicsContext *
fontFamiliesList = gc->fontFamiliesList;
}
void KoSvgTextChunkShape::resetTextShape()
{
Q_D(KoSvgTextChunkShape);
using namespace KoSvgText;
d->properties = KoSvgTextProperties();
d->font = QFont();
d->fontFamiliesList = QStringList();
d->textLength = AutoValue();
d->lengthAdjust = LengthAdjustSpacing;
d->localTransformations.clear();
d->text.clear();
// all the subchunks are destroyed!
qDeleteAll(shapes());
}
bool KoSvgTextChunkShape::loadSvg(const KoXmlElement &e, SvgLoadingContext &context)
{
Q_D(KoSvgTextChunkShape);
......
......@@ -35,11 +35,14 @@ public:
KoSvgTextChunkShape(const KoSvgTextChunkShape &rhs);
~KoSvgTextChunkShape() override;
KoShape* cloneShape() const;
KoShape* cloneShape() const override;
void paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override;
void saveOdf(KoShapeSavingContext &Context) const override;
bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &Context) override;
virtual void resetTextShape();
bool saveSvg(SvgSavingContext &context) override;
bool loadSvg(const KoXmlElement &element, SvgLoadingContext &context) override;
bool loadSvgTextNode(const KoXmlText &text, SvgLoadingContext &context);
......
......@@ -104,6 +104,12 @@ void KoSvgTextShape::paintStroke(QPainter &painter, const KoViewConverter &conve
// do nothing! everything is painted in paintComponent()
}
void KoSvgTextShape::resetTextShape()
{
KoSvgTextChunkShape::resetTextShape();
relayout();
}
struct TextChunk {
QString text;
QList<QTextLayout::FormatRange> formats;
......@@ -179,6 +185,9 @@ void KoSvgTextShape::relayout()
{
Q_D(KoSvgTextShape);
d->layouts.clear();
d->layoutOffsets.clear();
QPointF currentTextPos;
QVector<TextChunk> textChunks = mergeIntoChunks(layoutInterface()->collectSubChunks());
......
......@@ -34,11 +34,13 @@ public:
KoSvgTextShape(const KoSvgTextShape &rhs);
~KoSvgTextShape() override;
KoShape* cloneShape() const;
KoShape* cloneShape() const override;
void paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override;
void paintStroke(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override;
void resetTextShape() override;
void relayout();
protected:
......
/*
* Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KoSvgTextShapeMarkupConverter.h"
#include "klocalizedstring.h"
#include "kis_assert.h"
#include "kis_debug.h"
#include <QBuffer>
#include <KoSvgTextShape.h>
#include <SvgWriter.h>
#include <SvgSavingContext.h>
#include <KoXmlReader.h>
#include <SvgParser.h>
#include <KoDocumentResourceManager.h>
struct KoSvgTextShapeMarkupConverter::Private {
Private(KoSvgTextShape *_shape) : shape(_shape) {}
KoSvgTextShape *shape;
QStringList errors;
QStringList warnings;
void clearErrors() {
errors.clear();
warnings.clear();
}
};
KoSvgTextShapeMarkupConverter::KoSvgTextShapeMarkupConverter(KoSvgTextShape *shape)
: m_d(new Private(shape))
{
}
KoSvgTextShapeMarkupConverter::~KoSvgTextShapeMarkupConverter()
{
}
bool KoSvgTextShapeMarkupConverter::convertToSvg(QString *svgText, QString *stylesText)
{
m_d->clearErrors();
QBuffer shapesBuffer;
QBuffer stylesBuffer;
shapesBuffer.open(QIODevice::WriteOnly);
stylesBuffer.open(QIODevice::WriteOnly);
{
SvgSavingContext savingContext(shapesBuffer, stylesBuffer);
savingContext.setStrippedTextMode(true);
SvgWriter writer({m_d->shape}, QSizeF(666, 666)); // size is not used since we don't save the preamble of the document
writer.saveDetached(savingContext);
}
shapesBuffer.close();
stylesBuffer.close();
*svgText = QString(shapesBuffer.data());
*stylesText = QString(stylesBuffer.data());
return true;
}
bool KoSvgTextShapeMarkupConverter::convertFromSvg(const QString &svgText, const QString &stylesText,
const QRectF &boundsInPixels, qreal pixelsPerInch)
{
m_d->clearErrors();
const QString fullText = QString("<svg>\n%1\n%2\n</svg>\n").arg(stylesText).arg(svgText);
KoXmlDocument doc;
QString errorMessage;
int errorLine = 0;
int errorColumn = 0;
const bool xmlResult = doc.setContent(fullText, &errorMessage, &errorLine, &errorColumn);
if (!xmlResult) {
m_d->errors << QString("line %1, col %2: %3").arg(errorLine).arg(errorColumn).arg(errorMessage);
return false;
}
m_d->shape->resetTextShape();
KoDocumentResourceManager resourceManager;
SvgParser parser(&resourceManager);
parser.setResolution(boundsInPixels, pixelsPerInch);
KoXmlElement root = doc.documentElement();
KoXmlNode node = root.firstChild();
bool textNodeFound = false;
for (; !node.isNull(); node = node.nextSibling()) {
KoXmlElement el = node.toElement();
if (el.isNull()) continue;
if (el.tagName() == "defs") {
parser.parseDefsElement(el);
} else if (el.tagName() == "text") {
if (textNodeFound) {
m_d->errors << i18n("More than one 'text' node found!");
return false;
}
KoShape *shape = parser.parseTextElement(el, m_d->shape);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(shape == m_d->shape, false);
textNodeFound = true;
break;
} else {
m_d->errors << i18n("Unknown node of type \'%1\' found!", el.tagName());
return false;
}
}
if (!textNodeFound) {
m_d->errors << i18n("No \'text\' node found!");
return false;
}
return true;
}
QStringList KoSvgTextShapeMarkupConverter::errors() const
{
return m_d->errors;
}
QStringList KoSvgTextShapeMarkupConverter::warnings() const
{
return m_d->warnings;
}