src/svg/qsvgrenderer.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtSvg module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qsvgrenderer.h"
       
    43 
       
    44 #ifndef QT_NO_SVGRENDERER
       
    45 
       
    46 #include "qsvgtinydocument_p.h"
       
    47 
       
    48 #include "qbytearray.h"
       
    49 #include "qtimer.h"
       
    50 #include "qdebug.h"
       
    51 #include "private/qobject_p.h"
       
    52 
       
    53 
       
    54 QT_BEGIN_NAMESPACE
       
    55 
       
    56 /*!
       
    57     \class QSvgRenderer
       
    58     \ingroup painting
       
    59 
       
    60     \brief The QSvgRenderer class is used to draw the contents of SVG files onto paint devices.
       
    61     \since 4.1
       
    62     \reentrant
       
    63 
       
    64     Using QSvgRenderer, Scalable Vector Graphics (SVG) can be rendered onto any QPaintDevice
       
    65     subclass, including QWidget, QImage, and QGLWidget.
       
    66 
       
    67     QSvgRenderer provides an API that supports basic features of SVG rendering, such as loading
       
    68     and rendering of static drawings, and more interactive features like animation. Since the
       
    69     rendering is performed using QPainter, SVG drawings can be rendered on any subclass of
       
    70     QPaintDevice.
       
    71 
       
    72     SVG drawings are either loaded when an QSvgRenderer is constructed, or loaded later
       
    73     using the load() functions. Data is either supplied directly as serialized XML, or
       
    74     indirectly using a file name. If a valid file has been loaded, either when the renderer
       
    75     is constructed or at some later time, isValid() returns true; otherwise it returns false.
       
    76     QSvgRenderer provides the render() slot to render the current document, or the current
       
    77     frame of an animated document, using a given painter.
       
    78 
       
    79     The defaultSize() function provides information about the amount of space that is required
       
    80     to render the currently loaded SVG file. This is useful for paint devices, such as QWidget,
       
    81     that often need to supply a size hint to their parent layout.
       
    82     The default size of a drawing may differ from its visible area, found using the \l viewBox
       
    83     property.
       
    84 
       
    85     Animated SVG drawings are supported, and can be controlled with a simple collection of
       
    86     functions and properties:
       
    87 
       
    88     \list
       
    89     \o The animated() function indicates whether a drawing contains animation information.
       
    90     \omit
       
    91     \o The animationDuration() function provides the duration in milliseconds of the
       
    92        animation, without taking any looping into account.
       
    93     \o The \l currentFrame property contains the current frame of the animation.
       
    94     \endomit
       
    95     \o The \l framesPerSecond property contains the rate at which the animation plays.
       
    96     \endlist
       
    97 
       
    98     Finally, the QSvgRenderer class provides the repaintNeeded() signal which is emitted
       
    99     whenever the rendering of the document needs to be updated.
       
   100 
       
   101     \sa QSvgWidget, {QtSvg Module}, {SVG Viewer Example}, QPicture
       
   102 */
       
   103 
       
   104 class QSvgRendererPrivate : public QObjectPrivate
       
   105 {
       
   106     Q_DECLARE_PUBLIC(QSvgRenderer)
       
   107 public:
       
   108     explicit QSvgRendererPrivate()
       
   109         : QObjectPrivate(),
       
   110           render(0), timer(0),
       
   111           fps(30)
       
   112     {}
       
   113     ~QSvgRendererPrivate()
       
   114     {
       
   115         delete render;
       
   116     }
       
   117 
       
   118     static void callRepaintNeeded(QSvgRenderer *const q);
       
   119 
       
   120     QSvgTinyDocument *render;
       
   121     QTimer *timer;
       
   122     int fps;
       
   123 };
       
   124 
       
   125 /*!
       
   126     Constructs a new renderer with the given \a parent.
       
   127 */
       
   128 QSvgRenderer::QSvgRenderer(QObject *parent)
       
   129     : QObject(*(new QSvgRendererPrivate), parent)
       
   130 {
       
   131 }
       
   132 
       
   133 /*!
       
   134     Constructs a new renderer with the given \a parent and loads the contents of the
       
   135     SVG file with the specified \a filename.
       
   136 */
       
   137 QSvgRenderer::QSvgRenderer(const QString &filename, QObject *parent)
       
   138     : QObject(*new QSvgRendererPrivate, parent)
       
   139 {
       
   140     load(filename);
       
   141 }
       
   142 
       
   143 /*!
       
   144     Constructs a new renderer with the given \a parent and loads the SVG data
       
   145     from the byte array specified by \a contents.
       
   146 */
       
   147 QSvgRenderer::QSvgRenderer(const QByteArray &contents, QObject *parent)
       
   148     : QObject(*new QSvgRendererPrivate, parent)
       
   149 {
       
   150     load(contents);
       
   151 }
       
   152 
       
   153 /*!
       
   154     \since 4.5
       
   155 
       
   156     Constructs a new renderer with the given \a parent and loads the SVG data
       
   157     using the stream reader specified by \a contents.
       
   158 */
       
   159 QSvgRenderer::QSvgRenderer(QXmlStreamReader *contents, QObject *parent)
       
   160     : QObject(*new QSvgRendererPrivate, parent)
       
   161 {
       
   162     load(contents);
       
   163 }
       
   164 
       
   165 /*!
       
   166     Destroys the renderer.
       
   167 */
       
   168 QSvgRenderer::~QSvgRenderer()
       
   169 {
       
   170 
       
   171 }
       
   172 
       
   173 /*!
       
   174     Returns true if there is a valid current document; otherwise returns false.
       
   175 */
       
   176 bool QSvgRenderer::isValid() const
       
   177 {
       
   178     Q_D(const QSvgRenderer);
       
   179     return d->render;
       
   180 }
       
   181 
       
   182 /*!
       
   183     Returns the default size of the document contents.
       
   184 */
       
   185 QSize QSvgRenderer::defaultSize() const
       
   186 {
       
   187     Q_D(const QSvgRenderer);
       
   188     if (d->render)
       
   189         return d->render->size();
       
   190     else
       
   191         return QSize();
       
   192 }
       
   193 
       
   194 /*!
       
   195     Returns viewBoxF().toRect().
       
   196 
       
   197     \sa viewBoxF()
       
   198 */
       
   199 QRect QSvgRenderer::viewBox() const
       
   200 {
       
   201     Q_D(const QSvgRenderer);
       
   202     if (d->render)
       
   203         return d->render->viewBox().toRect();
       
   204     else
       
   205         return QRect();
       
   206 }
       
   207 
       
   208 /*!
       
   209     \property QSvgRenderer::viewBox
       
   210     \brief the rectangle specifying the visible area of the document in logical coordinates
       
   211     \since 4.2
       
   212 */
       
   213 void QSvgRenderer::setViewBox(const QRect &viewbox)
       
   214 {
       
   215     Q_D(QSvgRenderer);
       
   216     if (d->render)
       
   217         d->render->setViewBox(viewbox);
       
   218 }
       
   219 
       
   220 /*!
       
   221     Returns true if the current document contains animated elements; otherwise
       
   222     returns false.
       
   223 
       
   224     \sa framesPerSecond()
       
   225 */
       
   226 bool QSvgRenderer::animated() const
       
   227 {
       
   228     Q_D(const QSvgRenderer);
       
   229     if (d->render)
       
   230         return d->render->animated();
       
   231     else
       
   232         return false;
       
   233 }
       
   234 
       
   235 /*!
       
   236     \property QSvgRenderer::framesPerSecond
       
   237     \brief the number of frames per second to be shown
       
   238 
       
   239     The number of frames per second is 0 if the current document is not animated.
       
   240 
       
   241     \sa animated()
       
   242 */
       
   243 int QSvgRenderer::framesPerSecond() const
       
   244 {
       
   245     Q_D(const QSvgRenderer);
       
   246     return d->fps;
       
   247 }
       
   248 
       
   249 void QSvgRenderer::setFramesPerSecond(int num)
       
   250 {
       
   251     Q_D(QSvgRenderer);
       
   252     if (num < 0) {
       
   253         qWarning("QSvgRenderer::setFramesPerSecond: Cannot set negative value %d", num);
       
   254         return;
       
   255     }
       
   256     d->fps = num;
       
   257 }
       
   258 
       
   259 /*!
       
   260   \property QSvgRenderer::currentFrame
       
   261   \brief the current frame of the document's animation, or 0 if the document is not animated
       
   262   \internal
       
   263 
       
   264   \sa animationDuration(), framesPerSecond, animated()
       
   265 */
       
   266 
       
   267 /*!
       
   268   \internal
       
   269 */
       
   270 int QSvgRenderer::currentFrame() const
       
   271 {
       
   272     Q_D(const QSvgRenderer);
       
   273     return d->render->currentFrame();
       
   274 }
       
   275 
       
   276 /*!
       
   277   \internal
       
   278 */
       
   279 void QSvgRenderer::setCurrentFrame(int frame)
       
   280 {
       
   281     Q_D(QSvgRenderer);
       
   282     d->render->setCurrentFrame(frame);
       
   283 }
       
   284 
       
   285 /*!
       
   286     \internal
       
   287 
       
   288     Returns the number of frames in the animation, or 0 if the current document is not
       
   289     animated.
       
   290 
       
   291     \sa animated(), framesPerSecond
       
   292 */
       
   293 int QSvgRenderer::animationDuration() const
       
   294 {
       
   295     Q_D(const QSvgRenderer);
       
   296     return d->render->animationDuration();
       
   297 }
       
   298 
       
   299 /*!
       
   300  \internal
       
   301  \since 4.5
       
   302 
       
   303  We can't have template functions, that's loadDocument(), as friends, for this
       
   304  code, so we let this function be a friend of QSvgRenderer instead.
       
   305  */
       
   306 void QSvgRendererPrivate::callRepaintNeeded(QSvgRenderer *const q)
       
   307 {
       
   308     q->repaintNeeded();
       
   309 }
       
   310 
       
   311 template<typename TInputType>
       
   312 static bool loadDocument(QSvgRenderer *const q,
       
   313                          QSvgRendererPrivate *const d,
       
   314                          const TInputType &in)
       
   315 {
       
   316     delete d->render;
       
   317     d->render = QSvgTinyDocument::load(in);
       
   318     if (d->render && d->render->animated() && d->fps > 0) {
       
   319         if (!d->timer)
       
   320             d->timer = new QTimer(q);
       
   321         else
       
   322             d->timer->stop();
       
   323         q->connect(d->timer, SIGNAL(timeout()),
       
   324                    q, SIGNAL(repaintNeeded()));
       
   325         d->timer->start(1000/d->fps);
       
   326     } else if (d->timer) {
       
   327         d->timer->stop();
       
   328     }
       
   329 
       
   330     //force first update
       
   331     QSvgRendererPrivate::callRepaintNeeded(q);
       
   332 
       
   333     return d->render;
       
   334 }
       
   335 
       
   336 /*!
       
   337     Loads the SVG file specified by \a filename, returning true if the content
       
   338     was successfully parsed; otherwise returns false.
       
   339 */
       
   340 bool QSvgRenderer::load(const QString &filename)
       
   341 {
       
   342     Q_D(QSvgRenderer);
       
   343     return loadDocument(this, d, filename);
       
   344 }
       
   345 
       
   346 /*!
       
   347     Loads the specified SVG format \a contents, returning true if the content
       
   348     was successfully parsed; otherwise returns false.
       
   349 */
       
   350 bool QSvgRenderer::load(const QByteArray &contents)
       
   351 {
       
   352     Q_D(QSvgRenderer);
       
   353     return loadDocument(this, d, contents);
       
   354 }
       
   355 
       
   356 /*!
       
   357   Loads the specified SVG in \a contents, returning true if the content
       
   358   was successfully parsed; otherwise returns false.
       
   359 
       
   360   The reader will be used from where it currently is positioned. If \a contents
       
   361   is \c null, behavior is undefined.
       
   362 
       
   363   \since 4.5
       
   364 */
       
   365 bool QSvgRenderer::load(QXmlStreamReader *contents)
       
   366 {
       
   367     Q_D(QSvgRenderer);
       
   368     return loadDocument(this, d, contents);
       
   369 }
       
   370 
       
   371 /*!
       
   372     Renders the current document, or the current frame of an animated
       
   373     document, using the given \a painter.
       
   374 */
       
   375 void QSvgRenderer::render(QPainter *painter)
       
   376 {
       
   377     Q_D(QSvgRenderer);
       
   378     if (d->render) {
       
   379         d->render->draw(painter);
       
   380     }
       
   381 }
       
   382 
       
   383 /*!
       
   384     \fn void QSvgRenderer::repaintNeeded()
       
   385 
       
   386     This signal is emitted whenever the rendering of the document
       
   387     needs to be updated, usually for the purposes of animation.
       
   388 */
       
   389 
       
   390 /*!
       
   391     Renders the given element with \a elementId using the given \a painter
       
   392     on the specified \a bounds. If the bounding rectangle is not specified
       
   393     the SVG element is mapped to the whole paint device.
       
   394 */
       
   395 void QSvgRenderer::render(QPainter *painter, const QString &elementId,
       
   396                           const QRectF &bounds)
       
   397 {
       
   398     Q_D(QSvgRenderer);
       
   399     if (d->render) {
       
   400         d->render->draw(painter, elementId, bounds);
       
   401     }
       
   402 }
       
   403 
       
   404 /*!
       
   405     Renders the current document, or the current frame of an animated
       
   406     document, using the given \a painter on the specified \a bounds within
       
   407     the painter.  If the bounding rectangle is not specified
       
   408     the SVG file is mapped to the whole paint device.
       
   409 */
       
   410 void QSvgRenderer::render(QPainter *painter, const QRectF &bounds)
       
   411 {
       
   412     Q_D(QSvgRenderer);
       
   413     if (d->render) {
       
   414         d->render->draw(painter, bounds);
       
   415     }
       
   416 }
       
   417 
       
   418 QRectF QSvgRenderer::viewBoxF() const
       
   419 {
       
   420     Q_D(const QSvgRenderer);
       
   421     if (d->render)
       
   422         return d->render->viewBox();
       
   423     else
       
   424         return QRect();
       
   425 }
       
   426 
       
   427 void QSvgRenderer::setViewBox(const QRectF &viewbox)
       
   428 {
       
   429     Q_D(QSvgRenderer);
       
   430     if (d->render)
       
   431         d->render->setViewBox(viewbox);
       
   432 }
       
   433 
       
   434 /*!
       
   435     \since 4.2
       
   436 
       
   437     Returns bounding rectangle of the item with the given \a id.
       
   438     The transformation matrix of parent elements is not affecting
       
   439     the bounds of the element.
       
   440 
       
   441     \sa matrixForElement()
       
   442 */
       
   443 QRectF QSvgRenderer::boundsOnElement(const QString &id) const
       
   444 {
       
   445     Q_D(const QSvgRenderer);
       
   446     QRectF bounds;
       
   447     if (d->render)
       
   448         bounds = d->render->boundsOnElement(id);
       
   449     return bounds;
       
   450 }
       
   451 
       
   452 
       
   453 /*!
       
   454     \since 4.2
       
   455 
       
   456     Returns true if the element with the given \a id exists
       
   457     in the currently parsed SVG file and is a renderable
       
   458     element.
       
   459 
       
   460     Note: this method returns true only for elements that
       
   461     can be rendered. Which implies that elements that are considered
       
   462     part of the fill/stroke style properties, e.g. radialGradients
       
   463     even tough marked with "id" attributes will not be found by this
       
   464     method.
       
   465 */
       
   466 bool QSvgRenderer::elementExists(const QString &id) const
       
   467 {
       
   468     Q_D(const QSvgRenderer);
       
   469     bool exists = false;
       
   470     if (d->render)
       
   471         exists = d->render->elementExists(id);
       
   472     return exists;
       
   473 }
       
   474 
       
   475 /*!
       
   476     \since 4.2
       
   477 
       
   478     Returns the transformation matrix for the element
       
   479     with the given \a id. The matrix is a product of
       
   480     the transformation of the element's parents. The transformation of
       
   481     the element itself is not included.
       
   482 
       
   483     To find the bounding rectangle of the element in logical coordinates,
       
   484     you can apply the matrix on the rectangle returned from boundsOnElement().
       
   485 
       
   486     \sa boundsOnElement()
       
   487 */
       
   488 QMatrix QSvgRenderer::matrixForElement(const QString &id) const
       
   489 {
       
   490     Q_D(const QSvgRenderer);
       
   491     QMatrix mat;
       
   492     if (d->render)
       
   493         mat = d->render->matrixForElement(id);
       
   494     return mat;
       
   495 }
       
   496 
       
   497 QT_END_NAMESPACE
       
   498 
       
   499 #include "moc_qsvgrenderer.cpp"
       
   500 
       
   501 #endif // QT_NO_SVGRENDERER