src/svg/qsvggraphics.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 "qsvggraphics_p.h"
       
    43 
       
    44 #ifndef QT_NO_SVG
       
    45 
       
    46 #include "qsvgfont_p.h"
       
    47 
       
    48 #include "qpainter.h"
       
    49 #include "qtextdocument.h"
       
    50 #include "qabstracttextdocumentlayout.h"
       
    51 #include "qtextcursor.h"
       
    52 #include "qdebug.h"
       
    53 
       
    54 #include <math.h>
       
    55 #include <limits.h>
       
    56 
       
    57 QT_BEGIN_NAMESPACE
       
    58 
       
    59 #define QT_SVG_DRAW_SHAPE(command)                          \
       
    60     qreal oldOpacity = p->opacity();                        \
       
    61     QBrush oldBrush = p->brush();                           \
       
    62     QPen oldPen = p->pen();                                 \
       
    63     p->setPen(Qt::NoPen);                                   \
       
    64     p->setOpacity(oldOpacity * states.fillOpacity);         \
       
    65     command;                                                \
       
    66     p->setPen(oldPen);                                      \
       
    67     if (oldPen.widthF() != 0) {                             \
       
    68         p->setOpacity(oldOpacity * states.strokeOpacity);   \
       
    69         p->setBrush(Qt::NoBrush);                           \
       
    70         command;                                            \
       
    71         p->setBrush(oldBrush);                              \
       
    72     }                                                       \
       
    73     p->setOpacity(oldOpacity);
       
    74 
       
    75 
       
    76 void QSvgAnimation::draw(QPainter *, QSvgExtraStates &)
       
    77 {
       
    78     qWarning("<animation> no implemented");
       
    79 }
       
    80 
       
    81 static inline QRectF boundsOnStroke(const QPainterPath &path, qreal width)
       
    82 {
       
    83     QPainterPathStroker stroker;
       
    84     stroker.setWidth(width);
       
    85     QPainterPath stroke = stroker.createStroke(path);
       
    86     return stroke.boundingRect();
       
    87 }
       
    88 
       
    89 QSvgCircle::QSvgCircle(QSvgNode *parent, const QRectF &rect)
       
    90     : QSvgNode(parent), m_bounds(rect)
       
    91 {
       
    92 }
       
    93 
       
    94 
       
    95 QRectF QSvgCircle::bounds() const
       
    96 {
       
    97     qreal sw = strokeWidth();
       
    98     if (qFuzzyIsNull(sw))
       
    99         return m_bounds;
       
   100     else {
       
   101         QPainterPath path;
       
   102         path.addRect(m_bounds);
       
   103         return boundsOnStroke(path, sw);
       
   104     }
       
   105 }
       
   106 
       
   107 void QSvgCircle::draw(QPainter *p, QSvgExtraStates &states)
       
   108 {
       
   109     applyStyle(p, states);
       
   110     QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds));
       
   111     revertStyle(p, states);
       
   112 }
       
   113 
       
   114 QSvgArc::QSvgArc(QSvgNode *parent, const QPainterPath &path)
       
   115     : QSvgNode(parent), cubic(path)
       
   116 {
       
   117     m_cachedBounds = path.boundingRect();
       
   118 }
       
   119 
       
   120 void QSvgArc::draw(QPainter *p, QSvgExtraStates &states)
       
   121 {
       
   122     applyStyle(p, states);
       
   123     if (p->pen().widthF() != 0) {
       
   124         qreal oldOpacity = p->opacity();
       
   125         p->setOpacity(oldOpacity * states.strokeOpacity);
       
   126         p->drawPath(cubic);
       
   127         p->setOpacity(oldOpacity);
       
   128     }
       
   129     revertStyle(p, states);
       
   130 }
       
   131 
       
   132 QSvgEllipse::QSvgEllipse(QSvgNode *parent, const QRectF &rect)
       
   133     : QSvgNode(parent), m_bounds(rect)
       
   134 {
       
   135 }
       
   136 
       
   137 QRectF QSvgEllipse::bounds() const
       
   138 {
       
   139     qreal sw = strokeWidth();
       
   140     if (qFuzzyIsNull(sw))
       
   141         return m_bounds;
       
   142     else {
       
   143         QPainterPath path;
       
   144         path.addEllipse(m_bounds);
       
   145         return boundsOnStroke(path, sw);
       
   146     }
       
   147 }
       
   148 
       
   149 void QSvgEllipse::draw(QPainter *p, QSvgExtraStates &states)
       
   150 {
       
   151     applyStyle(p, states);
       
   152     QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds));
       
   153     revertStyle(p, states);
       
   154 }
       
   155 
       
   156 QSvgImage::QSvgImage(QSvgNode *parent, const QImage &image,
       
   157                      const QRect &bounds)
       
   158     : QSvgNode(parent), m_image(image),
       
   159       m_bounds(bounds)
       
   160 {
       
   161     if (m_bounds.width() == 0)
       
   162         m_bounds.setWidth(m_image.width());
       
   163     if (m_bounds.height() == 0)
       
   164         m_bounds.setHeight(m_image.height());
       
   165 }
       
   166 
       
   167 void QSvgImage::draw(QPainter *p, QSvgExtraStates &states)
       
   168 {
       
   169     applyStyle(p, states);
       
   170     p->drawImage(m_bounds, m_image);
       
   171     revertStyle(p, states);
       
   172 }
       
   173 
       
   174 
       
   175 QSvgLine::QSvgLine(QSvgNode *parent, const QLineF &line)
       
   176     : QSvgNode(parent), m_bounds(line)
       
   177 {
       
   178 }
       
   179 
       
   180 
       
   181 void QSvgLine::draw(QPainter *p, QSvgExtraStates &states)
       
   182 {
       
   183     applyStyle(p, states);
       
   184     if (p->pen().widthF() != 0) {
       
   185         qreal oldOpacity = p->opacity();
       
   186         p->setOpacity(oldOpacity * states.strokeOpacity);
       
   187         p->drawLine(m_bounds);
       
   188         p->setOpacity(oldOpacity);
       
   189     }
       
   190     revertStyle(p, states);
       
   191 }
       
   192 
       
   193 QSvgPath::QSvgPath(QSvgNode *parent, const QPainterPath &qpath)
       
   194     : QSvgNode(parent), m_path(qpath)
       
   195 {
       
   196 }
       
   197 
       
   198 void QSvgPath::draw(QPainter *p, QSvgExtraStates &states)
       
   199 {
       
   200     applyStyle(p, states);
       
   201     m_path.setFillRule(states.fillRule);
       
   202     QT_SVG_DRAW_SHAPE(p->drawPath(m_path));
       
   203     revertStyle(p, states);
       
   204 }
       
   205 
       
   206 QRectF QSvgPath::bounds() const
       
   207 {
       
   208     qreal sw = strokeWidth();
       
   209     if (qFuzzyIsNull(sw)) {
       
   210         if (m_cachedBounds.isNull())
       
   211             //m_cachedBounds = m_path.controlPointRect();
       
   212             m_cachedBounds = m_path.boundingRect();
       
   213 
       
   214         return m_cachedBounds;
       
   215     }
       
   216     else {
       
   217         return boundsOnStroke(m_path, sw);
       
   218     }
       
   219 }
       
   220 
       
   221 QSvgPolygon::QSvgPolygon(QSvgNode *parent, const QPolygonF &poly)
       
   222     : QSvgNode(parent), m_poly(poly)
       
   223 {
       
   224 }
       
   225 
       
   226 QRectF QSvgPolygon::bounds() const
       
   227 {
       
   228     qreal sw = strokeWidth();
       
   229     if (qFuzzyIsNull(sw))
       
   230         return m_poly.boundingRect();
       
   231     else {
       
   232         QPainterPath path;
       
   233         path.addPolygon(m_poly);
       
   234         return boundsOnStroke(path, sw);
       
   235     }
       
   236 }
       
   237 
       
   238 void QSvgPolygon::draw(QPainter *p, QSvgExtraStates &states)
       
   239 {
       
   240     applyStyle(p, states);
       
   241     QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly, states.fillRule));
       
   242     revertStyle(p, states);
       
   243 }
       
   244 
       
   245 
       
   246 QSvgPolyline::QSvgPolyline(QSvgNode *parent, const QPolygonF &poly)
       
   247     : QSvgNode(parent), m_poly(poly)
       
   248 {
       
   249 
       
   250 }
       
   251 
       
   252 void QSvgPolyline::draw(QPainter *p, QSvgExtraStates &states)
       
   253 {
       
   254     applyStyle(p, states);
       
   255     qreal oldOpacity = p->opacity();
       
   256     if (p->brush().style() != Qt::NoBrush) {
       
   257         QPen save = p->pen();
       
   258         p->setPen(QPen(Qt::NoPen));
       
   259         p->setOpacity(oldOpacity * states.fillOpacity);
       
   260         p->drawPolygon(m_poly, states.fillRule);
       
   261         p->setPen(save);
       
   262     }
       
   263     if (p->pen().widthF() != 0) {
       
   264         p->setOpacity(oldOpacity * states.strokeOpacity);
       
   265         p->drawPolyline(m_poly);
       
   266     }
       
   267     p->setOpacity(oldOpacity);
       
   268     revertStyle(p, states);
       
   269 }
       
   270 
       
   271 QSvgRect::QSvgRect(QSvgNode *node, const QRectF &rect, int rx, int ry)
       
   272     : QSvgNode(node),
       
   273       m_rect(rect), m_rx(rx), m_ry(ry)
       
   274 {
       
   275 }
       
   276 
       
   277 QRectF QSvgRect::bounds() const
       
   278 {
       
   279     qreal sw = strokeWidth();
       
   280     if (qFuzzyIsNull(sw))
       
   281         return m_rect;
       
   282     else {
       
   283         QPainterPath path;
       
   284         path.addRect(m_rect);
       
   285         return boundsOnStroke(path, sw);
       
   286     }
       
   287 }
       
   288 
       
   289 void QSvgRect::draw(QPainter *p, QSvgExtraStates &states)
       
   290 {
       
   291     applyStyle(p, states);
       
   292     if (m_rx || m_ry) {
       
   293         QT_SVG_DRAW_SHAPE(p->drawRoundedRect(m_rect, m_rx, m_ry, Qt::RelativeSize));
       
   294     } else {
       
   295         QT_SVG_DRAW_SHAPE(p->drawRect(m_rect));
       
   296     }
       
   297     revertStyle(p, states);
       
   298 }
       
   299 
       
   300 QSvgTspan * const QSvgText::LINEBREAK = 0;
       
   301 
       
   302 QSvgText::QSvgText(QSvgNode *parent, const QPointF &coord)
       
   303     : QSvgNode(parent)
       
   304     , m_coord(coord)
       
   305     , m_type(TEXT)
       
   306     , m_size(0, 0)
       
   307     , m_mode(Default)
       
   308 {
       
   309 }
       
   310 
       
   311 QSvgText::~QSvgText()
       
   312 {
       
   313     for (int i = 0; i < m_tspans.size(); ++i) {
       
   314         if (m_tspans[i] != LINEBREAK)
       
   315             delete m_tspans[i];
       
   316     }
       
   317 }
       
   318 
       
   319 void QSvgText::setTextArea(const QSizeF &size)
       
   320 {
       
   321     m_size = size;
       
   322     m_type = TEXTAREA;
       
   323 }
       
   324 
       
   325 //QRectF QSvgText::bounds() const {}
       
   326 
       
   327 void QSvgText::draw(QPainter *p, QSvgExtraStates &states)
       
   328 {
       
   329     applyStyle(p, states);
       
   330     qreal oldOpacity = p->opacity();
       
   331     p->setOpacity(oldOpacity * states.fillOpacity);
       
   332 
       
   333     // Force the font to have a size of 100 pixels to avoid truncation problems
       
   334     // when the font is very small.
       
   335     qreal scale = 100.0 / p->font().pointSizeF();
       
   336     Qt::Alignment alignment = states.textAnchor;
       
   337 
       
   338     QTransform oldTransform = p->worldTransform();
       
   339     p->scale(1 / scale, 1 / scale);
       
   340 
       
   341     qreal y = 0;
       
   342     bool initial = true;
       
   343     qreal px = m_coord.x() * scale;
       
   344     qreal py = m_coord.y() * scale;
       
   345     QSizeF scaledSize = m_size * scale;
       
   346 
       
   347     if (m_type == TEXTAREA) {
       
   348         if (alignment == Qt::AlignHCenter)
       
   349             px += scaledSize.width() / 2;
       
   350         else if (alignment == Qt::AlignRight)
       
   351             px += scaledSize.width();
       
   352     }
       
   353 
       
   354     QRectF bounds;
       
   355     if (m_size.height() != 0)
       
   356         bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used.
       
   357 
       
   358     bool appendSpace = false;
       
   359     QVector<QString> paragraphs;
       
   360     QStack<QTextCharFormat> formats;
       
   361     QVector<QList<QTextLayout::FormatRange> > formatRanges;
       
   362     paragraphs.push_back(QString());
       
   363     formatRanges.push_back(QList<QTextLayout::FormatRange>());
       
   364 
       
   365     for (int i = 0; i < m_tspans.size(); ++i) {
       
   366         if (m_tspans[i] == LINEBREAK) {
       
   367             if (m_type == TEXTAREA) {
       
   368                 if (paragraphs.back().isEmpty()) {
       
   369                     QFont font = p->font();
       
   370                     font.setPixelSize(font.pointSizeF() * scale);
       
   371 
       
   372                     QTextLayout::FormatRange range;
       
   373                     range.start = 0;
       
   374                     range.length = 1;
       
   375                     range.format.setFont(font);
       
   376                     formatRanges.back().append(range);
       
   377 
       
   378                     paragraphs.back().append(QLatin1Char(' '));;
       
   379                 }
       
   380                 appendSpace = false;
       
   381                 paragraphs.push_back(QString());
       
   382                 formatRanges.push_back(QList<QTextLayout::FormatRange>());
       
   383             }
       
   384         } else {
       
   385             WhitespaceMode mode = m_tspans[i]->whitespaceMode();
       
   386             m_tspans[i]->applyStyle(p, states);
       
   387 
       
   388             QFont font = p->font();
       
   389             font.setPixelSize(font.pointSizeF() * scale);
       
   390 
       
   391             QString newText(m_tspans[i]->text());
       
   392             newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
       
   393             newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
       
   394 
       
   395             bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
       
   396             if (appendSpace || prependSpace)
       
   397                 paragraphs.back().append(QLatin1Char(' '));
       
   398 
       
   399             bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
       
   400 
       
   401             if (mode == Default) {
       
   402                 newText = newText.simplified();
       
   403                 if (newText.isEmpty())
       
   404                     appendSpaceNext = false;
       
   405             }
       
   406 
       
   407             QTextLayout::FormatRange range;
       
   408             range.start = paragraphs.back().length();
       
   409             range.length = newText.length();
       
   410             range.format.setFont(font);
       
   411             range.format.setTextOutline(p->pen());
       
   412             range.format.setForeground(p->brush());
       
   413 
       
   414             if (appendSpace) {
       
   415                 Q_ASSERT(!formatRanges.back().isEmpty());
       
   416                 ++formatRanges.back().back().length;
       
   417             } else if (prependSpace) {
       
   418                 --range.start;
       
   419                 ++range.length;
       
   420             }
       
   421             formatRanges.back().append(range);
       
   422 
       
   423             appendSpace = appendSpaceNext;
       
   424             paragraphs.back() += newText;
       
   425 
       
   426             m_tspans[i]->revertStyle(p, states);
       
   427         }
       
   428     }
       
   429 
       
   430     if (states.svgFont) {
       
   431         // SVG fonts not fully supported...
       
   432         QString text = paragraphs.front();
       
   433         for (int i = 1; i < paragraphs.size(); ++i) {
       
   434             text.append(QLatin1Char('\n'));
       
   435             text.append(paragraphs[i]);
       
   436         }
       
   437         states.svgFont->draw(p, m_coord * scale, text, p->font().pointSizeF() * scale, states.textAnchor);
       
   438     } else {
       
   439         for (int i = 0; i < paragraphs.size(); ++i) {
       
   440             QTextLayout tl(paragraphs[i]);
       
   441             QTextOption op = tl.textOption();
       
   442             op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
       
   443             tl.setTextOption(op);
       
   444             tl.setAdditionalFormats(formatRanges[i]);
       
   445             tl.beginLayout();
       
   446 
       
   447             forever {
       
   448                 QTextLine line = tl.createLine();
       
   449                 if (!line.isValid())
       
   450                     break;
       
   451                 if (m_size.width() != 0)
       
   452                     line.setLineWidth(scaledSize.width());
       
   453             }
       
   454             tl.endLayout();
       
   455 
       
   456             bool endOfBoundsReached = false;
       
   457             for (int i = 0; i < tl.lineCount(); ++i) {
       
   458                 QTextLine line = tl.lineAt(i);
       
   459 
       
   460                 qreal x = 0;
       
   461                 if (alignment == Qt::AlignHCenter)
       
   462                     x -= 0.5 * line.naturalTextWidth();
       
   463                 else if (alignment == Qt::AlignRight)
       
   464                     x -= line.naturalTextWidth();
       
   465 
       
   466                 if (initial && m_type == TEXT)
       
   467                     y -= line.ascent();
       
   468                 initial = false;
       
   469 
       
   470                 line.setPosition(QPointF(x, y));
       
   471 
       
   472                 // Check if the current line fits into the bounding rectangle.
       
   473                 if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
       
   474                     || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
       
   475                     // I need to set the bounds height to 'y-epsilon' to avoid drawing the current
       
   476                     // line. Since the font is scaled to 100 units, 1 should be a safe epsilon.
       
   477                     bounds.setHeight(y - 1);
       
   478                     endOfBoundsReached = true;
       
   479                     break;
       
   480                 }
       
   481 
       
   482                 y += 1.1 * line.height();
       
   483             }
       
   484             tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
       
   485 
       
   486             if (endOfBoundsReached)
       
   487                 break;
       
   488         }
       
   489     }
       
   490 
       
   491     p->setWorldTransform(oldTransform, false);
       
   492     p->setOpacity(oldOpacity);
       
   493     revertStyle(p, states);
       
   494 }
       
   495 
       
   496 void QSvgText::addText(const QString &text)
       
   497 {
       
   498     m_tspans.append(new QSvgTspan(this, false));
       
   499     m_tspans.back()->setWhitespaceMode(m_mode);
       
   500     m_tspans.back()->addText(text);
       
   501 }
       
   502 
       
   503 QSvgUse::QSvgUse(const QPointF &start, QSvgNode *parent, QSvgNode *node)
       
   504     : QSvgNode(parent), m_link(node), m_start(start)
       
   505 {
       
   506 
       
   507 }
       
   508 
       
   509 void QSvgUse::draw(QPainter *p, QSvgExtraStates &states)
       
   510 {
       
   511     applyStyle(p, states);
       
   512 
       
   513     if (!m_start.isNull()) {
       
   514         p->translate(m_start);
       
   515     }
       
   516     m_link->draw(p, states);
       
   517     if (!m_start.isNull()) {
       
   518         p->translate(-m_start);
       
   519     }
       
   520 
       
   521     revertStyle(p, states);
       
   522 }
       
   523 
       
   524 void QSvgVideo::draw(QPainter *p, QSvgExtraStates &states)
       
   525 {
       
   526     applyStyle(p, states);
       
   527 
       
   528     revertStyle(p, states);
       
   529 }
       
   530 
       
   531 QSvgNode::Type QSvgAnimation::type() const
       
   532 {
       
   533     return ANIMATION;
       
   534 }
       
   535 
       
   536 QSvgNode::Type QSvgArc::type() const
       
   537 {
       
   538     return ARC;
       
   539 }
       
   540 
       
   541 QSvgNode::Type QSvgCircle::type() const
       
   542 {
       
   543     return CIRCLE;
       
   544 }
       
   545 
       
   546 QSvgNode::Type QSvgEllipse::type() const
       
   547 {
       
   548     return ELLIPSE;
       
   549 }
       
   550 
       
   551 QSvgNode::Type QSvgImage::type() const
       
   552 {
       
   553     return IMAGE;
       
   554 }
       
   555 
       
   556 QSvgNode::Type QSvgLine::type() const
       
   557 {
       
   558     return LINE;
       
   559 }
       
   560 
       
   561 QSvgNode::Type QSvgPath::type() const
       
   562 {
       
   563     return PATH;
       
   564 }
       
   565 
       
   566 QSvgNode::Type QSvgPolygon::type() const
       
   567 {
       
   568     return POLYGON;
       
   569 }
       
   570 
       
   571 QSvgNode::Type QSvgPolyline::type() const
       
   572 {
       
   573     return POLYLINE;
       
   574 }
       
   575 
       
   576 QSvgNode::Type QSvgRect::type() const
       
   577 {
       
   578     return RECT;
       
   579 }
       
   580 
       
   581 QSvgNode::Type QSvgText::type() const
       
   582 {
       
   583     return m_type;
       
   584 }
       
   585 
       
   586 QSvgNode::Type QSvgUse::type() const
       
   587 {
       
   588     return USE;
       
   589 }
       
   590 
       
   591 QSvgNode::Type QSvgVideo::type() const
       
   592 {
       
   593     return VIDEO;
       
   594 }
       
   595 
       
   596 QRectF QSvgUse::bounds() const
       
   597 {
       
   598     if (m_link && m_bounds.isEmpty())  {
       
   599         m_bounds = m_link->bounds();
       
   600         m_bounds = QRectF(m_bounds.x()+m_start.x(),
       
   601                           m_bounds.y()+m_start.y(),
       
   602                           m_bounds.width(),
       
   603                           m_bounds.height());
       
   604 
       
   605         return m_bounds;
       
   606     }
       
   607     return m_bounds;
       
   608 }
       
   609 
       
   610 QRectF QSvgUse::transformedBounds(const QTransform &transform) const
       
   611 {
       
   612     QRectF bounds;
       
   613     QTransform t = transform;
       
   614 
       
   615     if (m_link)  {
       
   616         QSvgTransformStyle *transStyle = m_style.transform;
       
   617         if (transStyle) {
       
   618             t = transStyle->qtransform() * t;
       
   619         }
       
   620         t.translate(m_start.x(), m_start.y());
       
   621 
       
   622         bounds = m_link->transformedBounds(t);
       
   623 
       
   624         return bounds;
       
   625     }
       
   626     return bounds;
       
   627 }
       
   628 
       
   629 QRectF QSvgPolyline::bounds() const
       
   630 {
       
   631     qreal sw = strokeWidth();
       
   632     if (qFuzzyIsNull(sw))
       
   633         return m_poly.boundingRect();
       
   634     else {
       
   635         QPainterPath path;
       
   636         path.addPolygon(m_poly);
       
   637         return boundsOnStroke(path, sw);
       
   638     }
       
   639 }
       
   640 
       
   641 QRectF QSvgArc::bounds() const
       
   642 {
       
   643     qreal sw = strokeWidth();
       
   644     if (qFuzzyIsNull(sw))
       
   645         return m_cachedBounds;
       
   646     else {
       
   647         return boundsOnStroke(cubic, sw);
       
   648     }
       
   649 }
       
   650 
       
   651 QRectF QSvgImage::bounds() const
       
   652 {
       
   653     return m_bounds;
       
   654 }
       
   655 
       
   656 QRectF QSvgLine::bounds() const
       
   657 {
       
   658     qreal sw = strokeWidth();
       
   659     if (qFuzzyIsNull(sw)) {
       
   660         qreal minX = qMin(m_bounds.x1(), m_bounds.x2());
       
   661         qreal minY = qMin(m_bounds.y1(), m_bounds.y2());
       
   662         qreal maxX = qMax(m_bounds.x1(), m_bounds.x2());
       
   663         qreal maxY = qMax(m_bounds.y1(), m_bounds.y2());
       
   664         return QRectF(minX, minY, maxX-minX, maxY-minY);
       
   665     } else {
       
   666         QPainterPath path;
       
   667         path.moveTo(m_bounds.x1(), m_bounds.y1());
       
   668         path.lineTo(m_bounds.x2(), m_bounds.y2());
       
   669         return boundsOnStroke(path, sw);
       
   670     }
       
   671 }
       
   672 
       
   673 QT_END_NAMESPACE
       
   674 
       
   675 #endif // QT_NO_SVG