/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the QtSvg module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qsvggenerator.h" #ifndef QT_NO_SVGGENERATOR #include "qpainterpath.h" #include "private/qpaintengine_p.h" #include "private/qtextengine_p.h" #include "private/qdrawhelper_p.h" #include "qfile.h" #include "qtextcodec.h" #include "qtextstream.h" #include "qbuffer.h" #include "qmath.h" #include "qdebug.h" QT_BEGIN_NAMESPACE static void translate_color(const QColor &color, QString *color_string, QString *opacity_string) { Q_ASSERT(color_string); Q_ASSERT(opacity_string); *color_string = QString::fromLatin1("#%1%2%3") .arg(color.red(), 2, 16, QLatin1Char('0')) .arg(color.green(), 2, 16, QLatin1Char('0')) .arg(color.blue(), 2, 16, QLatin1Char('0')); *opacity_string = QString::number(color.alphaF()); } static void translate_dashPattern(QVector pattern, const qreal& width, QString *pattern_string) { Q_ASSERT(pattern_string); // Note that SVG operates in absolute lengths, whereas Qt uses a length/width ratio. foreach (qreal entry, pattern) *pattern_string += QString::fromLatin1("%1,").arg(entry * width); pattern_string->chop(1); } class QSvgPaintEnginePrivate : public QPaintEnginePrivate { public: QSvgPaintEnginePrivate() { size = QSize(); viewBox = QRectF(); outputDevice = 0; resolution = 72; attributes.document_title = QLatin1String("Qt Svg Document"); attributes.document_description = QLatin1String("Generated with Qt"); attributes.font_family = QLatin1String("serif"); attributes.font_size = QLatin1String("10pt"); attributes.font_style = QLatin1String("normal"); attributes.font_weight = QLatin1String("normal"); afterFirstUpdate = false; numGradients = 0; } QSize size; QRectF viewBox; QIODevice *outputDevice; QTextStream *stream; int resolution; QString header; QString defs; QString body; bool afterFirstUpdate; QBrush brush; QPen pen; QMatrix matrix; QFont font; QString generateGradientName() { ++numGradients; currentGradientName = QString::fromLatin1("gradient%1").arg(numGradients); return currentGradientName; } QString currentGradientName; int numGradients; struct _attributes { QString document_title; QString document_description; QString font_weight; QString font_size; QString font_family; QString font_style; QString stroke, strokeOpacity; QString dashPattern, dashOffset; QString fill, fillOpacity; } attributes; }; static inline QPaintEngine::PaintEngineFeatures svgEngineFeatures() { return QPaintEngine::PaintEngineFeatures( QPaintEngine::AllFeatures & ~QPaintEngine::PatternBrush & ~QPaintEngine::PerspectiveTransform & ~QPaintEngine::ConicalGradientFill & ~QPaintEngine::PorterDuff); } class QSvgPaintEngine : public QPaintEngine { Q_DECLARE_PRIVATE(QSvgPaintEngine) public: QSvgPaintEngine() : QPaintEngine(*new QSvgPaintEnginePrivate, svgEngineFeatures()) { } bool begin(QPaintDevice *device); bool end(); void updateState(const QPaintEngineState &state); void popGroup(); void drawPath(const QPainterPath &path); void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); void drawTextItem(const QPointF &pt, const QTextItem &item); void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlag = Qt::AutoColor); QPaintEngine::Type type() const { return QPaintEngine::SVG; } QSize size() const { return d_func()->size; } void setSize(const QSize &size) { Q_ASSERT(!isActive()); d_func()->size = size; } QRectF viewBox() const { return d_func()->viewBox; } void setViewBox(const QRectF &viewBox) { Q_ASSERT(!isActive()); d_func()->viewBox = viewBox; } QString documentTitle() const { return d_func()->attributes.document_title; } void setDocumentTitle(const QString &title) { d_func()->attributes.document_title = title; } QString documentDescription() const { return d_func()->attributes.document_description; } void setDocumentDescription(const QString &description) { d_func()->attributes.document_description = description; } QIODevice *outputDevice() const { return d_func()->outputDevice; } void setOutputDevice(QIODevice *device) { Q_ASSERT(!isActive()); d_func()->outputDevice = device; } int resolution() { return d_func()->resolution; } void setResolution(int resolution) { Q_ASSERT(!isActive()); d_func()->resolution = resolution; } void saveLinearGradientBrush(const QGradient *g) { QTextStream str(&d_func()->defs, QIODevice::Append); const QLinearGradient *grad = static_cast(g); str << QLatin1String("start().x()<< QLatin1String("\" ") << QLatin1String("y1=\"") <start().y()<< QLatin1String("\" ") << QLatin1String("x2=\"") <finalStop().x() << QLatin1String("\" ") << QLatin1String("y2=\"") <finalStop().y() << QLatin1String("\" "); } str << QLatin1String("id=\"") << d_func()->generateGradientName() << QLatin1String("\">\n"); saveGradientStops(str, g); str << QLatin1String("") <defs, QIODevice::Append); const QRadialGradient *grad = static_cast(g); str << QLatin1String("center().x()<< QLatin1String("\" ") << QLatin1String("cy=\"") <center().y()<< QLatin1String("\" ") << QLatin1String("r=\"") <radius() << QLatin1String("\" ") << QLatin1String("fx=\"") <focalPoint().x() << QLatin1String("\" ") << QLatin1String("fy=\"") <focalPoint().y() << QLatin1String("\" "); } str << QLatin1String("xml:id=\"") <generateGradientName()<< QLatin1String("\">\n"); saveGradientStops(str, g); str << QLatin1String("") << endl; } void saveConicalGradientBrush(const QGradient *) { qWarning("svg's don't support conical gradients!"); } void saveGradientStops(QTextStream &str, const QGradient *g) { QGradientStops stops = g->stops(); if (g->interpolationMode() == QGradient::ColorInterpolation) { bool constantAlpha = true; int alpha = stops.at(0).second.alpha(); for (int i = 1; i < stops.size(); ++i) constantAlpha &= (stops.at(i).second.alpha() == alpha); if (!constantAlpha) { const qreal spacing = 0.02; QGradientStops newStops; QRgb fromColor = PREMUL(stops.at(0).second.rgba()); QRgb toColor; for (int i = 0; i + 1 < stops.size(); ++i) { int parts = qCeil((stops.at(i + 1).first - stops.at(i).first) / spacing); newStops.append(stops.at(i)); toColor = PREMUL(stops.at(i + 1).second.rgba()); if (parts > 1) { qreal step = (stops.at(i + 1).first - stops.at(i).first) / parts; for (int j = 1; j < parts; ++j) { QRgb color = INV_PREMUL(INTERPOLATE_PIXEL_256(fromColor, 256 - 256 * j / parts, toColor, 256 * j / parts)); newStops.append(QGradientStop(stops.at(i).first + j * step, QColor::fromRgba(color))); } } fromColor = toColor; } newStops.append(stops.back()); stops = newStops; } } foreach(QGradientStop stop, stops) { QString color = QString::fromLatin1("#%1%2%3") .arg(stop.second.red(), 2, 16, QLatin1Char('0')) .arg(stop.second.green(), 2, 16, QLatin1Char('0')) .arg(stop.second.blue(), 2, 16, QLatin1Char('0')); str << QLatin1String(" \n"); } } void saveGradientUnits(QTextStream &str, const QGradient *gradient) { str << QLatin1String("gradientUnits=\""); if (gradient && gradient->coordinateMode() == QGradient::ObjectBoundingMode) str << QLatin1String("objectBoundingBox"); else str << QLatin1String("userSpaceOnUse"); str << QLatin1String("\" "); } void generateQtDefaults() { *d_func()->stream << QLatin1String("fill=\"none\" "); *d_func()->stream << QLatin1String("stroke=\"black\" "); *d_func()->stream << QLatin1String("vector-effect=\"non-scaling-stroke\" "); *d_func()->stream << QLatin1String("stroke-width=\"1\" "); *d_func()->stream << QLatin1String("fill-rule=\"evenodd\" "); *d_func()->stream << QLatin1String("stroke-linecap=\"square\" "); *d_func()->stream << QLatin1String("stroke-linejoin=\"bevel\" "); *d_func()->stream << QLatin1String(">\n"); } inline QTextStream &stream() { return *d_func()->stream; } void qpenToSvg(const QPen &spen) { QString width; d_func()->pen = spen; switch (spen.style()) { case Qt::NoPen: stream() << QLatin1String("stroke=\"none\" "); d_func()->attributes.stroke = QLatin1String("none"); d_func()->attributes.strokeOpacity = QString(); return; break; case Qt::SolidLine: { QString color, colorOpacity; translate_color(spen.color(), &color, &colorOpacity); d_func()->attributes.stroke = color; d_func()->attributes.strokeOpacity = colorOpacity; stream() << QLatin1String("stroke=\"")<attributes.stroke = color; d_func()->attributes.strokeOpacity = colorOpacity; d_func()->attributes.dashPattern = dashPattern; d_func()->attributes.dashOffset = dashOffset; stream() << QLatin1String("stroke=\"")<brush = sbrush; switch (sbrush.style()) { case Qt::SolidPattern: { QString color, colorOpacity; translate_color(sbrush.color(), &color, &colorOpacity); stream() << "fill=\"" << color << "\" "; stream() << "fill-opacity=\"" << colorOpacity << "\" "; d_func()->attributes.fill = color; d_func()->attributes.fillOpacity = colorOpacity; } break; case Qt::LinearGradientPattern: saveLinearGradientBrush(sbrush.gradient()); d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName); d_func()->attributes.fillOpacity = QString(); stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" "); break; case Qt::RadialGradientPattern: saveRadialGradientBrush(sbrush.gradient()); d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName); d_func()->attributes.fillOpacity = QString(); stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" "); break; case Qt::ConicalGradientPattern: saveConicalGradientBrush(sbrush.gradient()); d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName); d_func()->attributes.fillOpacity = QString(); stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" "); break; case Qt::NoBrush: stream() << QLatin1String("fill=\"none\" "); d_func()->attributes.fill = QLatin1String("none"); d_func()->attributes.fillOpacity = QString(); return; break; default: break; } } void qfontToSvg(const QFont &sfont) { Q_D(QSvgPaintEngine); d->font = sfont; if (d->font.pixelSize() == -1) d->attributes.font_size = QString::number(d->font.pointSizeF() * d->resolution / 72); else d->attributes.font_size = QString::number(d->font.pixelSize()); int svgWeight = d->font.weight(); switch (svgWeight) { case QFont::Light: svgWeight = 100; break; case QFont::Normal: svgWeight = 400; break; case QFont::Bold: svgWeight = 700; break; default: svgWeight *= 10; } d->attributes.font_weight = QString::number(svgWeight); d->attributes.font_family = d->font.family(); d->attributes.font_style = d->font.italic() ? QLatin1String("italic") : QLatin1String("normal"); *d->stream << "font-family=\"" << d->attributes.font_family << "\" " << "font-size=\"" << d->attributes.font_size << "\" " << "font-weight=\"" << d->attributes.font_weight << "\" " << "font-style=\"" << d->attributes.font_style << "\" " << endl; } }; class QSvgGeneratorPrivate { public: QSvgPaintEngine *engine; uint owns_iodevice : 1; QString fileName; }; /*! \class QSvgGenerator \ingroup multimedia \since 4.3 \brief The QSvgGenerator class provides a paint device that is used to create SVG drawings. \reentrant \sa QSvgRenderer, QSvgWidget */ /*! Constructs a new generator. */ QSvgGenerator::QSvgGenerator() : d_ptr(new QSvgGeneratorPrivate) { Q_D(QSvgGenerator); d->engine = new QSvgPaintEngine; d->owns_iodevice = false; } /*! Destroys the generator. */ QSvgGenerator::~QSvgGenerator() { Q_D(QSvgGenerator); if (d->owns_iodevice) delete d->engine->outputDevice(); delete d->engine; delete d_ptr; } /*! \property QSvgGenerator::title \brief the title of the generated SVG drawing \since 4.5 \sa description */ QString QSvgGenerator::title() const { Q_D(const QSvgGenerator); return d->engine->documentTitle(); } void QSvgGenerator::setTitle(const QString &title) { Q_D(QSvgGenerator); d->engine->setDocumentTitle(title); } /*! \property QSvgGenerator::description \brief the description of the generated SVG drawing \since 4.5 \sa title */ QString QSvgGenerator::description() const { Q_D(const QSvgGenerator); return d->engine->documentDescription(); } void QSvgGenerator::setDescription(const QString &description) { Q_D(QSvgGenerator); d->engine->setDocumentDescription(description); } /*! \property QSvgGenerator::size \brief the size of the generated SVG drawing \since 4.5 By default this property is set to \c{QSize(-1, -1)}, which indicates that the generator should not output the width and height attributes of the \c element. \note It is not possible to change this property while a QPainter is active on the generator. \sa viewBox, resolution */ QSize QSvgGenerator::size() const { Q_D(const QSvgGenerator); return d->engine->size(); } void QSvgGenerator::setSize(const QSize &size) { Q_D(QSvgGenerator); if (d->engine->isActive()) { qWarning("QSvgGenerator::setSize(), cannot set size while SVG is being generated"); return; } d->engine->setSize(size); } /*! \property QSvgGenerator::viewBox \brief the viewBox of the generated SVG drawing \since 4.5 By default this property is set to \c{QRect(0, 0, -1, -1)}, which indicates that the generator should not output the viewBox attribute of the \c element. \note It is not possible to change this property while a QPainter is active on the generator. \sa viewBox(), size, resolution */ QRectF QSvgGenerator::viewBoxF() const { Q_D(const QSvgGenerator); return d->engine->viewBox(); } /*! \since 4.5 Returns viewBoxF().toRect(). \sa viewBoxF() */ QRect QSvgGenerator::viewBox() const { Q_D(const QSvgGenerator); return d->engine->viewBox().toRect(); } void QSvgGenerator::setViewBox(const QRectF &viewBox) { Q_D(QSvgGenerator); if (d->engine->isActive()) { qWarning("QSvgGenerator::setViewBox(), cannot set viewBox while SVG is being generated"); return; } d->engine->setViewBox(viewBox); } void QSvgGenerator::setViewBox(const QRect &viewBox) { setViewBox(QRectF(viewBox)); } /*! \property QSvgGenerator::fileName \brief the target filename for the generated SVG drawing \since 4.5 \sa outputDevice */ QString QSvgGenerator::fileName() const { Q_D(const QSvgGenerator); return d->fileName; } void QSvgGenerator::setFileName(const QString &fileName) { Q_D(QSvgGenerator); if (d->engine->isActive()) { qWarning("QSvgGenerator::setFileName(), cannot set file name while SVG is being generated"); return; } if (d->owns_iodevice) delete d->engine->outputDevice(); d->owns_iodevice = true; d->fileName = fileName; QFile *file = new QFile(fileName); d->engine->setOutputDevice(file); } /*! \property QSvgGenerator::outputDevice \brief the output device for the generated SVG drawing \since 4.5 If both output device and file name are specified, the output device will have precedence. \sa fileName */ QIODevice *QSvgGenerator::outputDevice() const { Q_D(const QSvgGenerator); return d->engine->outputDevice(); } void QSvgGenerator::setOutputDevice(QIODevice *outputDevice) { Q_D(QSvgGenerator); if (d->engine->isActive()) { qWarning("QSvgGenerator::setOutputDevice(), cannot set output device while SVG is being generated"); return; } d->owns_iodevice = false; d->engine->setOutputDevice(outputDevice); d->fileName = QString(); } /*! \property QSvgGenerator::resolution \brief the resolution of the generated output \since 4.5 The resolution is specified in dots per inch, and is used to calculate the physical size of an SVG drawing. \sa size, viewBox */ int QSvgGenerator::resolution() const { Q_D(const QSvgGenerator); return d->engine->resolution(); } void QSvgGenerator::setResolution(int dpi) { Q_D(QSvgGenerator); d->engine->setResolution(dpi); } /*! Returns the paint engine used to render graphics to be converted to SVG format information. */ QPaintEngine *QSvgGenerator::paintEngine() const { Q_D(const QSvgGenerator); return d->engine; } /*! \reimp */ int QSvgGenerator::metric(QPaintDevice::PaintDeviceMetric metric) const { Q_D(const QSvgGenerator); switch (metric) { case QPaintDevice::PdmDepth: return 32; case QPaintDevice::PdmWidth: return d->engine->size().width(); case QPaintDevice::PdmHeight: return d->engine->size().height(); case QPaintDevice::PdmDpiX: return d->engine->resolution(); case QPaintDevice::PdmDpiY: return d->engine->resolution(); case QPaintDevice::PdmHeightMM: return qRound(d->engine->size().height() * 25.4 / d->engine->resolution()); case QPaintDevice::PdmWidthMM: return qRound(d->engine->size().width() * 25.4 / d->engine->resolution()); case QPaintDevice::PdmNumColors: return 0xffffffff; case QPaintDevice::PdmPhysicalDpiX: return d->engine->resolution(); case QPaintDevice::PdmPhysicalDpiY: return d->engine->resolution(); default: qWarning("QSvgGenerator::metric(), unhandled metric %d\n", metric); break; } return 0; } /***************************************************************************** * class QSvgPaintEngine */ bool QSvgPaintEngine::begin(QPaintDevice *) { Q_D(QSvgPaintEngine); if (!d->outputDevice) { qWarning("QSvgPaintEngine::begin(), no output device"); return false; } if (!d->outputDevice->isOpen()) { if (!d->outputDevice->open(QIODevice::WriteOnly | QIODevice::Text)) { qWarning("QSvgPaintEngine::begin(), could not open output device: '%s'", qPrintable(d->outputDevice->errorString())); return false; } } else if (!d->outputDevice->isWritable()) { qWarning("QSvgPaintEngine::begin(), could not write to read-only output device: '%s'", qPrintable(d->outputDevice->errorString())); return false; } d->stream = new QTextStream(&d->header); // stream out the header... *d->stream << "" << endl << "size.isValid()) { qreal wmm = d->size.width() * 25.4 / d->resolution; qreal hmm = d->size.height() * 25.4 / d->resolution; *d->stream << " width=\"" << wmm << "mm\" height=\"" << hmm << "mm\"" << endl; } if (d->viewBox.isValid()) { *d->stream << " viewBox=\"" << d->viewBox.left() << " " << d->viewBox.top(); *d->stream << " " << d->viewBox.width() << " " << d->viewBox.height() << "\"" << endl; } *d->stream << " xmlns=\"http://www.w3.org/2000/svg\"" << " xmlns:xlink=\"http://www.w3.org/1999/xlink\" " << " version=\"1.2\" baseProfile=\"tiny\">" << endl; if (!d->attributes.document_title.isEmpty()) { *d->stream << "" << d->attributes.document_title << "" << endl; } if (!d->attributes.document_description.isEmpty()) { *d->stream << "" << d->attributes.document_description << "" << endl; } d->stream->setString(&d->defs); *d->stream << "\n"; d->stream->setString(&d->body); // Start the initial graphics state... *d->stream << "stream << endl; return true; } bool QSvgPaintEngine::end() { Q_D(QSvgPaintEngine); d->stream->setString(&d->defs); *d->stream << "\n"; d->stream->setDevice(d->outputDevice); #ifndef QT_NO_TEXTCODEC d->stream->setCodec(QTextCodec::codecForName("UTF-8")); #endif *d->stream << d->header; *d->stream << d->defs; *d->stream << d->body; if (d->afterFirstUpdate) *d->stream << "" << endl; // close the updateState *d->stream << "" << endl // close the Qt defaults << "" << endl; delete d->stream; return true; } void QSvgPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) { drawImage(r, pm.toImage(), sr); } void QSvgPaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlag flags) { //Q_D(QSvgPaintEngine); Q_UNUSED(sr); Q_UNUSED(flags); stream() << "\n"; } void QSvgPaintEngine::updateState(const QPaintEngineState &state) { Q_D(QSvgPaintEngine); QPaintEngine::DirtyFlags flags = state.state(); // always stream full gstate, which is not required, but... flags |= QPaintEngine::AllDirty; // close old state and start a new one... if (d->afterFirstUpdate) *d->stream << "\n\n"; *d->stream << "matrix = state.matrix(); *d->stream << "transform=\"matrix(" << d->matrix.m11() << "," << d->matrix.m12() << "," << d->matrix.m21() << "," << d->matrix.m22() << "," << d->matrix.dx() << "," << d->matrix.dy() << ")\"" << endl; } if (flags & QPaintEngine::DirtyFont) { qfontToSvg(state.font()); } if (flags & QPaintEngine::DirtyOpacity) { if (!qFuzzyCompare(state.opacity(), 1)) stream() << "opacity=\""<stream << ">" << endl; d->afterFirstUpdate = true; } void QSvgPaintEngine::drawPath(const QPainterPath &p) { Q_D(QSvgPaintEngine); *d->stream << "stream << "fill-rule="; if (p.fillRule() == Qt::OddEvenFill) *d->stream << "\"evenodd\" "; else *d->stream << "\"nonzero\" "; *d->stream << "d=\""; for (int i=0; istream << "M" << e.x << "," << e.y; break; case QPainterPath::LineToElement: *d->stream << "L" << e.x << "," << e.y; break; case QPainterPath::CurveToElement: *d->stream << "C" << e.x << "," << e.y; ++i; while (i < p.elementCount()) { const QPainterPath::Element &e = p.elementAt(i); if (e.type != QPainterPath::CurveToDataElement) { --i; break; } else *d->stream << " "; *d->stream << e.x << "," << e.y; ++i; } break; default: break; } if (i != p.elementCount() - 1) { *d->stream << " "; } } *d->stream << "\"/>" << endl; } void QSvgPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) { Q_ASSERT(pointCount >= 2); //Q_D(QSvgPaintEngine); QPainterPath path(points[0]); for (int i=1; i" <pen.style() == Qt::NoPen) return; const QTextItemInt &ti = static_cast(textItem); QString s = QString::fromRawData(ti.chars, ti.num_chars); *d->stream << "attributes.stroke << "\" " << "fill-opacity=\"" << d->attributes.strokeOpacity << "\" " << "stroke=\"none\" " << "x=\"" << pt.x() << "\" y=\"" << pt.y() << "\" "; qfontToSvg(textItem.font()); *d->stream << " >" << Qt::escape(s) << "" << endl; } QT_END_NAMESPACE #endif // QT_NO_SVGGENERATOR