/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtSvg module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** 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.1, 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. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qsvgrenderer.h" | |
#ifndef QT_NO_SVGRENDERER | |
#include "qsvgtinydocument_p.h" | |
#include "qbytearray.h" | |
#include "qtimer.h" | |
#include "qdebug.h" | |
#include "private/qobject_p.h" | |
QT_BEGIN_NAMESPACE | |
/*! | |
\class QSvgRenderer | |
\ingroup painting | |
\brief The QSvgRenderer class is used to draw the contents of SVG files onto paint devices. | |
\since 4.1 | |
\reentrant | |
Using QSvgRenderer, Scalable Vector Graphics (SVG) can be rendered onto any QPaintDevice | |
subclass, including QWidget, QImage, and QGLWidget. | |
QSvgRenderer provides an API that supports basic features of SVG rendering, such as loading | |
and rendering of static drawings, and more interactive features like animation. Since the | |
rendering is performed using QPainter, SVG drawings can be rendered on any subclass of | |
QPaintDevice. | |
SVG drawings are either loaded when an QSvgRenderer is constructed, or loaded later | |
using the load() functions. Data is either supplied directly as serialized XML, or | |
indirectly using a file name. If a valid file has been loaded, either when the renderer | |
is constructed or at some later time, isValid() returns true; otherwise it returns false. | |
QSvgRenderer provides the render() slot to render the current document, or the current | |
frame of an animated document, using a given painter. | |
The defaultSize() function provides information about the amount of space that is required | |
to render the currently loaded SVG file. This is useful for paint devices, such as QWidget, | |
that often need to supply a size hint to their parent layout. | |
The default size of a drawing may differ from its visible area, found using the \l viewBox | |
property. | |
Animated SVG drawings are supported, and can be controlled with a simple collection of | |
functions and properties: | |
\list | |
\o The animated() function indicates whether a drawing contains animation information. | |
\omit | |
\o The animationDuration() function provides the duration in milliseconds of the | |
animation, without taking any looping into account. | |
\o The \l currentFrame property contains the current frame of the animation. | |
\endomit | |
\o The \l framesPerSecond property contains the rate at which the animation plays. | |
\endlist | |
Finally, the QSvgRenderer class provides the repaintNeeded() signal which is emitted | |
whenever the rendering of the document needs to be updated. | |
\sa QSvgWidget, {QtSvg Module}, {SVG Viewer Example}, QPicture | |
*/ | |
class QSvgRendererPrivate : public QObjectPrivate | |
{ | |
Q_DECLARE_PUBLIC(QSvgRenderer) | |
public: | |
explicit QSvgRendererPrivate() | |
: QObjectPrivate(), | |
render(0), timer(0), | |
fps(30) | |
{} | |
~QSvgRendererPrivate() | |
{ | |
delete render; | |
} | |
static void callRepaintNeeded(QSvgRenderer *const q); | |
QSvgTinyDocument *render; | |
QTimer *timer; | |
int fps; | |
}; | |
/*! | |
Constructs a new renderer with the given \a parent. | |
*/ | |
QSvgRenderer::QSvgRenderer(QObject *parent) | |
: QObject(*(new QSvgRendererPrivate), parent) | |
{ | |
} | |
/*! | |
Constructs a new renderer with the given \a parent and loads the contents of the | |
SVG file with the specified \a filename. | |
*/ | |
QSvgRenderer::QSvgRenderer(const QString &filename, QObject *parent) | |
: QObject(*new QSvgRendererPrivate, parent) | |
{ | |
load(filename); | |
} | |
/*! | |
Constructs a new renderer with the given \a parent and loads the SVG data | |
from the byte array specified by \a contents. | |
*/ | |
QSvgRenderer::QSvgRenderer(const QByteArray &contents, QObject *parent) | |
: QObject(*new QSvgRendererPrivate, parent) | |
{ | |
load(contents); | |
} | |
/*! | |
\since 4.5 | |
Constructs a new renderer with the given \a parent and loads the SVG data | |
using the stream reader specified by \a contents. | |
*/ | |
QSvgRenderer::QSvgRenderer(QXmlStreamReader *contents, QObject *parent) | |
: QObject(*new QSvgRendererPrivate, parent) | |
{ | |
load(contents); | |
} | |
/*! | |
Destroys the renderer. | |
*/ | |
QSvgRenderer::~QSvgRenderer() | |
{ | |
} | |
/*! | |
Returns true if there is a valid current document; otherwise returns false. | |
*/ | |
bool QSvgRenderer::isValid() const | |
{ | |
Q_D(const QSvgRenderer); | |
return d->render; | |
} | |
/*! | |
Returns the default size of the document contents. | |
*/ | |
QSize QSvgRenderer::defaultSize() const | |
{ | |
Q_D(const QSvgRenderer); | |
if (d->render) | |
return d->render->size(); | |
else | |
return QSize(); | |
} | |
/*! | |
Returns viewBoxF().toRect(). | |
\sa viewBoxF() | |
*/ | |
QRect QSvgRenderer::viewBox() const | |
{ | |
Q_D(const QSvgRenderer); | |
if (d->render) | |
return d->render->viewBox().toRect(); | |
else | |
return QRect(); | |
} | |
/*! | |
\property QSvgRenderer::viewBox | |
\brief the rectangle specifying the visible area of the document in logical coordinates | |
\since 4.2 | |
*/ | |
void QSvgRenderer::setViewBox(const QRect &viewbox) | |
{ | |
Q_D(QSvgRenderer); | |
if (d->render) | |
d->render->setViewBox(viewbox); | |
} | |
/*! | |
Returns true if the current document contains animated elements; otherwise | |
returns false. | |
\sa framesPerSecond() | |
*/ | |
bool QSvgRenderer::animated() const | |
{ | |
Q_D(const QSvgRenderer); | |
if (d->render) | |
return d->render->animated(); | |
else | |
return false; | |
} | |
/*! | |
\property QSvgRenderer::framesPerSecond | |
\brief the number of frames per second to be shown | |
The number of frames per second is 0 if the current document is not animated. | |
\sa animated() | |
*/ | |
int QSvgRenderer::framesPerSecond() const | |
{ | |
Q_D(const QSvgRenderer); | |
return d->fps; | |
} | |
void QSvgRenderer::setFramesPerSecond(int num) | |
{ | |
Q_D(QSvgRenderer); | |
if (num < 0) { | |
qWarning("QSvgRenderer::setFramesPerSecond: Cannot set negative value %d", num); | |
return; | |
} | |
d->fps = num; | |
} | |
/*! | |
\property QSvgRenderer::currentFrame | |
\brief the current frame of the document's animation, or 0 if the document is not animated | |
\internal | |
\sa animationDuration(), framesPerSecond, animated() | |
*/ | |
/*! | |
\internal | |
*/ | |
int QSvgRenderer::currentFrame() const | |
{ | |
Q_D(const QSvgRenderer); | |
return d->render->currentFrame(); | |
} | |
/*! | |
\internal | |
*/ | |
void QSvgRenderer::setCurrentFrame(int frame) | |
{ | |
Q_D(QSvgRenderer); | |
d->render->setCurrentFrame(frame); | |
} | |
/*! | |
\internal | |
Returns the number of frames in the animation, or 0 if the current document is not | |
animated. | |
\sa animated(), framesPerSecond | |
*/ | |
int QSvgRenderer::animationDuration() const | |
{ | |
Q_D(const QSvgRenderer); | |
return d->render->animationDuration(); | |
} | |
/*! | |
\internal | |
\since 4.5 | |
We can't have template functions, that's loadDocument(), as friends, for this | |
code, so we let this function be a friend of QSvgRenderer instead. | |
*/ | |
void QSvgRendererPrivate::callRepaintNeeded(QSvgRenderer *const q) | |
{ | |
q->repaintNeeded(); | |
} | |
template<typename TInputType> | |
static bool loadDocument(QSvgRenderer *const q, | |
QSvgRendererPrivate *const d, | |
const TInputType &in) | |
{ | |
delete d->render; | |
d->render = QSvgTinyDocument::load(in); | |
if (d->render && d->render->animated() && d->fps > 0) { | |
if (!d->timer) | |
d->timer = new QTimer(q); | |
else | |
d->timer->stop(); | |
q->connect(d->timer, SIGNAL(timeout()), | |
q, SIGNAL(repaintNeeded())); | |
d->timer->start(1000/d->fps); | |
} else if (d->timer) { | |
d->timer->stop(); | |
} | |
//force first update | |
QSvgRendererPrivate::callRepaintNeeded(q); | |
return d->render; | |
} | |
/*! | |
Loads the SVG file specified by \a filename, returning true if the content | |
was successfully parsed; otherwise returns false. | |
*/ | |
bool QSvgRenderer::load(const QString &filename) | |
{ | |
Q_D(QSvgRenderer); | |
return loadDocument(this, d, filename); | |
} | |
/*! | |
Loads the specified SVG format \a contents, returning true if the content | |
was successfully parsed; otherwise returns false. | |
*/ | |
bool QSvgRenderer::load(const QByteArray &contents) | |
{ | |
Q_D(QSvgRenderer); | |
return loadDocument(this, d, contents); | |
} | |
/*! | |
Loads the specified SVG in \a contents, returning true if the content | |
was successfully parsed; otherwise returns false. | |
The reader will be used from where it currently is positioned. If \a contents | |
is \c null, behavior is undefined. | |
\since 4.5 | |
*/ | |
bool QSvgRenderer::load(QXmlStreamReader *contents) | |
{ | |
Q_D(QSvgRenderer); | |
return loadDocument(this, d, contents); | |
} | |
/*! | |
Renders the current document, or the current frame of an animated | |
document, using the given \a painter. | |
*/ | |
void QSvgRenderer::render(QPainter *painter) | |
{ | |
Q_D(QSvgRenderer); | |
if (d->render) { | |
d->render->draw(painter); | |
} | |
} | |
/*! | |
\fn void QSvgRenderer::repaintNeeded() | |
This signal is emitted whenever the rendering of the document | |
needs to be updated, usually for the purposes of animation. | |
*/ | |
/*! | |
Renders the given element with \a elementId using the given \a painter | |
on the specified \a bounds. If the bounding rectangle is not specified | |
the SVG element is mapped to the whole paint device. | |
*/ | |
void QSvgRenderer::render(QPainter *painter, const QString &elementId, | |
const QRectF &bounds) | |
{ | |
Q_D(QSvgRenderer); | |
if (d->render) { | |
d->render->draw(painter, elementId, bounds); | |
} | |
} | |
/*! | |
Renders the current document, or the current frame of an animated | |
document, using the given \a painter on the specified \a bounds within | |
the painter. If the bounding rectangle is not specified | |
the SVG file is mapped to the whole paint device. | |
*/ | |
void QSvgRenderer::render(QPainter *painter, const QRectF &bounds) | |
{ | |
Q_D(QSvgRenderer); | |
if (d->render) { | |
d->render->draw(painter, bounds); | |
} | |
} | |
QRectF QSvgRenderer::viewBoxF() const | |
{ | |
Q_D(const QSvgRenderer); | |
if (d->render) | |
return d->render->viewBox(); | |
else | |
return QRect(); | |
} | |
void QSvgRenderer::setViewBox(const QRectF &viewbox) | |
{ | |
Q_D(QSvgRenderer); | |
if (d->render) | |
d->render->setViewBox(viewbox); | |
} | |
/*! | |
\since 4.2 | |
Returns bounding rectangle of the item with the given \a id. | |
The transformation matrix of parent elements is not affecting | |
the bounds of the element. | |
\sa matrixForElement() | |
*/ | |
QRectF QSvgRenderer::boundsOnElement(const QString &id) const | |
{ | |
Q_D(const QSvgRenderer); | |
QRectF bounds; | |
if (d->render) | |
bounds = d->render->boundsOnElement(id); | |
return bounds; | |
} | |
/*! | |
\since 4.2 | |
Returns true if the element with the given \a id exists | |
in the currently parsed SVG file and is a renderable | |
element. | |
Note: this method returns true only for elements that | |
can be rendered. Which implies that elements that are considered | |
part of the fill/stroke style properties, e.g. radialGradients | |
even tough marked with "id" attributes will not be found by this | |
method. | |
*/ | |
bool QSvgRenderer::elementExists(const QString &id) const | |
{ | |
Q_D(const QSvgRenderer); | |
bool exists = false; | |
if (d->render) | |
exists = d->render->elementExists(id); | |
return exists; | |
} | |
/*! | |
\since 4.2 | |
Returns the transformation matrix for the element | |
with the given \a id. The matrix is a product of | |
the transformation of the element's parents. The transformation of | |
the element itself is not included. | |
To find the bounding rectangle of the element in logical coordinates, | |
you can apply the matrix on the rectangle returned from boundsOnElement(). | |
\sa boundsOnElement() | |
*/ | |
QMatrix QSvgRenderer::matrixForElement(const QString &id) const | |
{ | |
Q_D(const QSvgRenderer); | |
QMatrix mat; | |
if (d->render) | |
mat = d->render->matrixForElement(id); | |
return mat; | |
} | |
QT_END_NAMESPACE | |
#include "moc_qsvgrenderer.cpp" | |
#endif // QT_NO_SVGRENDERER |