diff options
Diffstat (limited to 'src/svg/qsvggraphics.cpp')
-rw-r--r-- | src/svg/qsvggraphics.cpp | 529 |
1 files changed, 305 insertions, 224 deletions
diff --git a/src/svg/qsvggraphics.cpp b/src/svg/qsvggraphics.cpp index 65b9304..ac8051d 100644 --- a/src/svg/qsvggraphics.cpp +++ b/src/svg/qsvggraphics.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt SVG module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qsvggraphics_p.h" @@ -49,15 +13,26 @@ #include <qtextcursor.h> #include <qtextdocument.h> +#include <QElapsedTimer> +#include <QLoggingCategory> + #include <math.h> #include <limits.h> QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcSvgDraw, "qt.svg.draw") +Q_LOGGING_CATEGORY(lcSvgTiming, "qt.svg.timing") + +#define QT_SVG_TIMING_ENTER \ + QElapsedTimer qtSvgTimer; qtSvgTimer.start(); + +#define QT_SVG_TIMING_EXIT(TYPE) \ + if (Q_UNLIKELY(lcSvgTiming().isDebugEnabled())) \ + qCDebug(lcSvgTiming) << "Drawing" << TYPE << "took" << (qtSvgTimer.nsecsElapsed() / 1000000.0f) << "ms"; #define QT_SVG_DRAW_SHAPE(command) \ - qreal oldOpacity = p->opacity(); \ + { qreal oldOpacity = p->opacity(); \ QBrush oldBrush = p->brush(); \ QPen oldPen = p->pen(); \ p->setPen(Qt::NoPen); \ @@ -70,7 +45,7 @@ Q_LOGGING_CATEGORY(lcSvgDraw, "qt.svg.draw") command; \ p->setBrush(oldBrush); \ } \ - p->setOpacity(oldOpacity); + p->setOpacity(oldOpacity); } void QSvgAnimation::draw(QPainter *, QSvgExtraStates &) @@ -91,6 +66,10 @@ QSvgEllipse::QSvgEllipse(QSvgNode *parent, const QRectF &rect) { } +QRectF QSvgEllipse::fastBounds(QPainter *p, QSvgExtraStates &) const +{ + return p->transform().mapRect(m_bounds); +} QRectF QSvgEllipse::bounds(QPainter *p, QSvgExtraStates &) const { @@ -102,9 +81,12 @@ QRectF QSvgEllipse::bounds(QPainter *p, QSvgExtraStates &) const void QSvgEllipse::draw(QPainter *p, QSvgExtraStates &states) { + QT_SVG_TIMING_ENTER applyStyle(p, states); - QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds)); + if (shouldDrawNode(p, states)) + QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds)); revertStyle(p, states); + QT_SVG_TIMING_EXIT("Ellipse") } QSvgArc::QSvgArc(QSvgNode *parent, const QPainterPath &path) @@ -114,14 +96,18 @@ QSvgArc::QSvgArc(QSvgNode *parent, const QPainterPath &path) void QSvgArc::draw(QPainter *p, QSvgExtraStates &states) { + QT_SVG_TIMING_ENTER applyStyle(p, states); - if (p->pen().widthF() != 0) { - qreal oldOpacity = p->opacity(); - p->setOpacity(oldOpacity * states.strokeOpacity); - p->drawPath(m_path); - p->setOpacity(oldOpacity); + if (shouldDrawNode(p, states)) { + if (p->pen().widthF() != 0) { + qreal oldOpacity = p->opacity(); + p->setOpacity(oldOpacity * states.strokeOpacity); + p->drawPath(m_path); + p->setOpacity(oldOpacity); + } } revertStyle(p, states); + QT_SVG_TIMING_EXIT("Arc") } QSvgImage::QSvgImage(QSvgNode *parent, const QImage &image, @@ -137,9 +123,13 @@ QSvgImage::QSvgImage(QSvgNode *parent, const QImage &image, void QSvgImage::draw(QPainter *p, QSvgExtraStates &states) { - applyStyle(p, states); - p->drawImage(m_bounds, m_image); - revertStyle(p, states); + QT_SVG_TIMING_ENTER + if (shouldDrawNode(p, states)) { + applyStyle(p, states); + p->drawImage(m_bounds, m_image); + revertStyle(p, states); + } + QT_SVG_TIMING_EXIT("Image") } @@ -151,14 +141,18 @@ QSvgLine::QSvgLine(QSvgNode *parent, const QLineF &line) void QSvgLine::draw(QPainter *p, QSvgExtraStates &states) { + QT_SVG_TIMING_ENTER applyStyle(p, states); - if (p->pen().widthF() != 0) { - qreal oldOpacity = p->opacity(); - p->setOpacity(oldOpacity * states.strokeOpacity); - p->drawLine(m_line); - p->setOpacity(oldOpacity); + if (shouldDrawNode(p, states)) { + if (p->pen().widthF() != 0) { + qreal oldOpacity = p->opacity(); + p->setOpacity(oldOpacity * states.strokeOpacity); + p->drawLine(m_line); + p->setOpacity(oldOpacity); + } } revertStyle(p, states); + QT_SVG_TIMING_EXIT("Line") } QSvgPath::QSvgPath(QSvgNode *parent, const QPainterPath &qpath) @@ -168,10 +162,19 @@ QSvgPath::QSvgPath(QSvgNode *parent, const QPainterPath &qpath) void QSvgPath::draw(QPainter *p, QSvgExtraStates &states) { + QT_SVG_TIMING_ENTER applyStyle(p, states); - m_path.setFillRule(states.fillRule); - QT_SVG_DRAW_SHAPE(p->drawPath(m_path)); + if (shouldDrawNode(p, states)) { + m_path.setFillRule(states.fillRule); + QT_SVG_DRAW_SHAPE(p->drawPath(m_path)); + } revertStyle(p, states); + QT_SVG_TIMING_EXIT("Path") +} + +QRectF QSvgPath::fastBounds(QPainter *p, QSvgExtraStates &) const +{ + return p->transform().mapRect(m_path.controlPointRect()); } QRectF QSvgPath::bounds(QPainter *p, QSvgExtraStates &) const @@ -186,6 +189,11 @@ QSvgPolygon::QSvgPolygon(QSvgNode *parent, const QPolygonF &poly) { } +QRectF QSvgPolygon::fastBounds(QPainter *p, QSvgExtraStates &) const +{ + return p->transform().mapRect(m_poly.boundingRect()); +} + QRectF QSvgPolygon::bounds(QPainter *p, QSvgExtraStates &) const { qreal sw = strokeWidth(p); @@ -200,9 +208,12 @@ QRectF QSvgPolygon::bounds(QPainter *p, QSvgExtraStates &) const void QSvgPolygon::draw(QPainter *p, QSvgExtraStates &states) { + QT_SVG_TIMING_ENTER applyStyle(p, states); - QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly, states.fillRule)); + if (shouldDrawNode(p, states)) + QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly, states.fillRule)); revertStyle(p, states); + QT_SVG_TIMING_EXIT("Polygon") } @@ -214,21 +225,25 @@ QSvgPolyline::QSvgPolyline(QSvgNode *parent, const QPolygonF &poly) void QSvgPolyline::draw(QPainter *p, QSvgExtraStates &states) { + QT_SVG_TIMING_ENTER applyStyle(p, states); - qreal oldOpacity = p->opacity(); - if (p->brush().style() != Qt::NoBrush) { - QPen save = p->pen(); - p->setPen(QPen(Qt::NoPen)); - p->setOpacity(oldOpacity * states.fillOpacity); - p->drawPolygon(m_poly, states.fillRule); - p->setPen(save); - } - if (p->pen().widthF() != 0) { - p->setOpacity(oldOpacity * states.strokeOpacity); - p->drawPolyline(m_poly); + if (shouldDrawNode(p, states)) { + qreal oldOpacity = p->opacity(); + if (p->brush().style() != Qt::NoBrush) { + QPen save = p->pen(); + p->setPen(QPen(Qt::NoPen)); + p->setOpacity(oldOpacity * states.fillOpacity); + p->drawPolygon(m_poly, states.fillRule); + p->setPen(save); + } + if (p->pen().widthF() != 0) { + p->setOpacity(oldOpacity * states.strokeOpacity); + p->drawPolyline(m_poly); + } + p->setOpacity(oldOpacity); } - p->setOpacity(oldOpacity); revertStyle(p, states); + QT_SVG_TIMING_EXIT("Polyline") } QSvgRect::QSvgRect(QSvgNode *node, const QRectF &rect, int rx, int ry) @@ -237,6 +252,11 @@ QSvgRect::QSvgRect(QSvgNode *node, const QRectF &rect, int rx, int ry) { } +QRectF QSvgRect::fastBounds(QPainter *p, QSvgExtraStates &) const +{ + return p->transform().mapRect(m_rect); +} + QRectF QSvgRect::bounds(QPainter *p, QSvgExtraStates &) const { qreal sw = strokeWidth(p); @@ -251,13 +271,17 @@ QRectF QSvgRect::bounds(QPainter *p, QSvgExtraStates &) const void QSvgRect::draw(QPainter *p, QSvgExtraStates &states) { + QT_SVG_TIMING_ENTER applyStyle(p, states); - if (m_rx || m_ry) { - QT_SVG_DRAW_SHAPE(p->drawRoundedRect(m_rect, m_rx, m_ry, Qt::RelativeSize)); - } else { - QT_SVG_DRAW_SHAPE(p->drawRect(m_rect)); + if (shouldDrawNode(p, states)) { + if (m_rx || m_ry) { + QT_SVG_DRAW_SHAPE(p->drawRoundedRect(m_rect, m_rx, m_ry, Qt::RelativeSize)); + } else { + QT_SVG_DRAW_SHAPE(p->drawRect(m_rect)); + } } revertStyle(p, states); + QT_SVG_TIMING_EXIT("Rect") } QSvgTspan * const QSvgText::LINEBREAK = 0; @@ -285,172 +309,212 @@ void QSvgText::setTextArea(const QSizeF &size) m_type = TEXTAREA; } -//QRectF QSvgText::bounds(QPainter *p, QSvgExtraStates &) const {} +QRectF QSvgText::fastBounds(QPainter *p, QSvgExtraStates &) const +{ + QFont font = p->font(); + QFontMetricsF fm(font); + + int charCount = 0; + for (int i = 0; i < m_tspans.size(); ++i) + charCount += m_tspans.at(i)->text().size(); + + QRectF approxMaximumBrect(m_coord.x(), + m_coord.y(), + charCount * fm.averageCharWidth(), + m_tspans.size() * fm.height()); + return p->transform().mapRect(approxMaximumBrect); +} + +QRectF QSvgText::bounds(QPainter *p, QSvgExtraStates &states) const +{ + QRectF boundingRect; + draw_helper(p, states, &boundingRect); + return p->transform().mapRect(boundingRect); +} void QSvgText::draw(QPainter *p, QSvgExtraStates &states) { - applyStyle(p, states); - qreal oldOpacity = p->opacity(); - p->setOpacity(oldOpacity * states.fillOpacity); - - // Force the font to have a size of 100 pixels to avoid truncation problems - // when the font is very small. - qreal scale = 100.0 / p->font().pointSizeF(); - Qt::Alignment alignment = states.textAnchor; - - QTransform oldTransform = p->worldTransform(); - p->scale(1 / scale, 1 / scale); - - qreal y = 0; - bool initial = true; - qreal px = m_coord.x() * scale; - qreal py = m_coord.y() * scale; - QSizeF scaledSize = m_size * scale; - - if (m_type == TEXTAREA) { - if (alignment == Qt::AlignHCenter) - px += scaledSize.width() / 2; - else if (alignment == Qt::AlignRight) - px += scaledSize.width(); - } + QT_SVG_TIMING_ENTER + draw_helper(p, states); + QT_SVG_TIMING_EXIT("Text") +} - QRectF bounds; - if (m_size.height() != 0) - bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used. +void QSvgText::draw_helper(QPainter *p, QSvgExtraStates &states, QRectF *boundingRect) const +{ + const bool isPainting = (boundingRect == nullptr); + applyStyle(p, states); + if (!isPainting || shouldDrawNode(p, states)) { + qreal oldOpacity = p->opacity(); + p->setOpacity(oldOpacity * states.fillOpacity); - bool appendSpace = false; - QList<QString> paragraphs; - QList<QList<QTextLayout::FormatRange> > formatRanges(1); - paragraphs.push_back(QString()); + // Force the font to have a size of 100 pixels to avoid truncation problems + // when the font is very small. + qreal scale = 100.0 / p->font().pointSizeF(); + Qt::Alignment alignment = states.textAnchor; + + QTransform oldTransform = p->worldTransform(); + p->scale(1 / scale, 1 / scale); + + qreal y = 0; + bool initial = true; + qreal px = m_coord.x() * scale; + qreal py = m_coord.y() * scale; + QSizeF scaledSize = m_size * scale; + + if (m_type == TEXTAREA) { + if (alignment == Qt::AlignHCenter) + px += scaledSize.width() / 2; + else if (alignment == Qt::AlignRight) + px += scaledSize.width(); + } - for (int i = 0; i < m_tspans.size(); ++i) { - if (m_tspans[i] == LINEBREAK) { - if (m_type == TEXTAREA) { - if (paragraphs.back().isEmpty()) { - QFont font = p->font(); - font.setPixelSize(font.pointSizeF() * scale); - - QTextLayout::FormatRange range; - range.start = 0; - range.length = 1; - range.format.setFont(font); - formatRanges.back().append(range); - - paragraphs.back().append(QLatin1Char(' '));; + QRectF bounds; + if (m_size.height() != 0) + bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used. + + bool appendSpace = false; + QList<QString> paragraphs; + QList<QList<QTextLayout::FormatRange> > formatRanges(1); + paragraphs.push_back(QString()); + + for (int i = 0; i < m_tspans.size(); ++i) { + if (m_tspans[i] == LINEBREAK) { + if (m_type == TEXTAREA) { + if (paragraphs.back().isEmpty()) { + QFont font = p->font(); + font.setPixelSize(font.pointSizeF() * scale); + + QTextLayout::FormatRange range; + range.start = 0; + range.length = 1; + range.format.setFont(font); + formatRanges.back().append(range); + + paragraphs.back().append(QLatin1Char(' '));; + } + appendSpace = false; + paragraphs.push_back(QString()); + formatRanges.resize(formatRanges.size() + 1); } - appendSpace = false; - paragraphs.push_back(QString()); - formatRanges.resize(formatRanges.size() + 1); - } - } else { - WhitespaceMode mode = m_tspans[i]->whitespaceMode(); - m_tspans[i]->applyStyle(p, states); + } else { + WhitespaceMode mode = m_tspans[i]->whitespaceMode(); + m_tspans[i]->applyStyle(p, states); - QFont font = p->font(); - font.setPixelSize(font.pointSizeF() * scale); + QFont font = p->font(); + font.setPixelSize(font.pointSizeF() * scale); - QString newText(m_tspans[i]->text()); - newText.replace(QLatin1Char('\t'), QLatin1Char(' ')); - newText.replace(QLatin1Char('\n'), QLatin1Char(' ')); + QString newText(m_tspans[i]->text()); + newText.replace(QLatin1Char('\t'), QLatin1Char(' ')); + newText.replace(QLatin1Char('\n'), QLatin1Char(' ')); - bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' ')); - if (appendSpace || prependSpace) - paragraphs.back().append(QLatin1Char(' ')); + bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' ')); + if (appendSpace || prependSpace) + paragraphs.back().append(QLatin1Char(' ')); - bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' '))); + bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' '))); - if (mode == Default) { - newText = newText.simplified(); - if (newText.isEmpty()) - appendSpaceNext = false; - } + if (mode == Default) { + newText = newText.simplified(); + if (newText.isEmpty()) + appendSpaceNext = false; + } - QTextLayout::FormatRange range; - range.start = paragraphs.back().length(); - range.length = newText.length(); - range.format.setFont(font); - range.format.setTextOutline(p->pen()); - range.format.setForeground(p->brush()); - - if (appendSpace) { - Q_ASSERT(!formatRanges.back().isEmpty()); - ++formatRanges.back().back().length; - } else if (prependSpace) { - --range.start; - ++range.length; - } - formatRanges.back().append(range); + QTextLayout::FormatRange range; + range.start = paragraphs.back().size(); + range.length = newText.size(); + range.format.setFont(font); + range.format.setTextOutline(p->pen()); + range.format.setForeground(p->brush()); + + if (appendSpace) { + Q_ASSERT(!formatRanges.back().isEmpty()); + ++formatRanges.back().back().length; + } else if (prependSpace) { + --range.start; + ++range.length; + } + formatRanges.back().append(range); - appendSpace = appendSpaceNext; - paragraphs.back() += newText; + appendSpace = appendSpaceNext; + paragraphs.back() += newText; - m_tspans[i]->revertStyle(p, states); + m_tspans[i]->revertStyle(p, states); + } } - } - if (states.svgFont) { - // SVG fonts not fully supported... - QString text = paragraphs.front(); - for (int i = 1; i < paragraphs.size(); ++i) { - text.append(QLatin1Char('\n')); - text.append(paragraphs[i]); - } - states.svgFont->draw(p, m_coord * scale, text, p->font().pointSizeF() * scale, states.textAnchor); - } else { - for (int i = 0; i < paragraphs.size(); ++i) { - QTextLayout tl(paragraphs[i]); - QTextOption op = tl.textOption(); - op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); - tl.setTextOption(op); - tl.setFormats(formatRanges[i]); - tl.beginLayout(); - - forever { - QTextLine line = tl.createLine(); - if (!line.isValid()) - break; - if (m_size.width() != 0) - line.setLineWidth(scaledSize.width()); + if (states.svgFont) { + // SVG fonts not fully supported... + QString text = paragraphs.front(); + for (int i = 1; i < paragraphs.size(); ++i) { + text.append(QLatin1Char('\n')); + text.append(paragraphs[i]); } - tl.endLayout(); - - bool endOfBoundsReached = false; - for (int i = 0; i < tl.lineCount(); ++i) { - QTextLine line = tl.lineAt(i); - - qreal x = 0; - if (alignment == Qt::AlignHCenter) - x -= 0.5 * line.naturalTextWidth(); - else if (alignment == Qt::AlignRight) - x -= line.naturalTextWidth(); - - if (initial && m_type == TEXT) - y -= line.ascent(); - initial = false; - - line.setPosition(QPointF(x, y)); - - // Check if the current line fits into the bounding rectangle. - if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width()) - || (m_size.height() != 0 && y + line.height() > scaledSize.height())) { - // I need to set the bounds height to 'y-epsilon' to avoid drawing the current - // line. Since the font is scaled to 100 units, 1 should be a safe epsilon. - bounds.setHeight(y - 1); - endOfBoundsReached = true; - break; + states.svgFont->draw(p, m_coord * scale, text, p->font().pointSizeF() * scale, states.textAnchor); + } else { + QRectF brect; + for (int i = 0; i < paragraphs.size(); ++i) { + QTextLayout tl(paragraphs[i]); + QTextOption op = tl.textOption(); + op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + tl.setTextOption(op); + tl.setFormats(formatRanges[i]); + tl.beginLayout(); + + forever { + QTextLine line = tl.createLine(); + if (!line.isValid()) + break; + if (m_size.width() != 0) + line.setLineWidth(scaledSize.width()); + } + tl.endLayout(); + + bool endOfBoundsReached = false; + for (int i = 0; i < tl.lineCount(); ++i) { + QTextLine line = tl.lineAt(i); + + qreal x = 0; + if (alignment == Qt::AlignHCenter) + x -= 0.5 * line.naturalTextWidth(); + else if (alignment == Qt::AlignRight) + x -= line.naturalTextWidth(); + + if (initial && m_type == TEXT) + y -= line.ascent(); + initial = false; + + line.setPosition(QPointF(x, y)); + brect |= line.naturalTextRect(); + + // Check if the current line fits into the bounding rectangle. + if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width()) + || (m_size.height() != 0 && y + line.height() > scaledSize.height())) { + // I need to set the bounds height to 'y-epsilon' to avoid drawing the current + // line. Since the font is scaled to 100 units, 1 should be a safe epsilon. + bounds.setHeight(y - 1); + endOfBoundsReached = true; + break; + } + + y += 1.1 * line.height(); } + if (isPainting) + tl.draw(p, QPointF(px, py), QList<QTextLayout::FormatRange>(), bounds); - y += 1.1 * line.height(); + if (endOfBoundsReached) + break; + } + if (boundingRect) { + brect.translate(m_coord * scale); + if (bounds.height() > 0) + brect.setBottom(qMin(brect.bottom(), bounds.bottom())); + *boundingRect = QTransform::fromScale(1 / scale, 1 / scale).mapRect(brect); } - tl.draw(p, QPointF(px, py), QList<QTextLayout::FormatRange>(), bounds); - - if (endOfBoundsReached) - break; } - } - p->setWorldTransform(oldTransform, false); - p->setOpacity(oldOpacity); + p->setWorldTransform(oldTransform, false); + p->setOpacity(oldOpacity); + } revertStyle(p, states); } @@ -469,6 +533,7 @@ QSvgUse::QSvgUse(const QPointF &start, QSvgNode *parent, QSvgNode *node) void QSvgUse::draw(QPainter *p, QSvgExtraStates &states) { + QT_SVG_TIMING_ENTER if (Q_UNLIKELY(!m_link || isDescendantOf(m_link) || m_recursing)) return; @@ -498,6 +563,7 @@ void QSvgUse::draw(QPainter *p, QSvgExtraStates &states) } revertStyle(p, states); + QT_SVG_TIMING_EXIT("Use") } void QSvgVideo::draw(QPainter *p, QSvgExtraStates &states) @@ -584,6 +650,11 @@ QRectF QSvgUse::bounds(QPainter *p, QSvgExtraStates &states) const return bounds; } +QRectF QSvgPolyline::fastBounds(QPainter *p, QSvgExtraStates &) const +{ + return p->transform().mapRect(m_poly.boundingRect()); +} + QRectF QSvgPolyline::bounds(QPainter *p, QSvgExtraStates &) const { qreal sw = strokeWidth(p); @@ -596,6 +667,11 @@ QRectF QSvgPolyline::bounds(QPainter *p, QSvgExtraStates &) const } } +QRectF QSvgArc::fastBounds(QPainter *p, QSvgExtraStates &) const +{ + return p->transform().mapRect(m_path.controlPointRect()); +} + QRectF QSvgArc::bounds(QPainter *p, QSvgExtraStates &) const { qreal sw = strokeWidth(p); @@ -608,17 +684,22 @@ QRectF QSvgImage::bounds(QPainter *p, QSvgExtraStates &) const return p->transform().mapRect(m_bounds); } -QRectF QSvgLine::bounds(QPainter *p, QSvgExtraStates &) const +QRectF QSvgLine::fastBounds(QPainter *p, QSvgExtraStates &) const +{ + QPointF p1 = p->transform().map(m_line.p1()); + QPointF p2 = p->transform().map(m_line.p2()); + qreal minX = qMin(p1.x(), p2.x()); + qreal minY = qMin(p1.y(), p2.y()); + qreal maxX = qMax(p1.x(), p2.x()); + qreal maxY = qMax(p1.y(), p2.y()); + return QRectF(minX, minY, maxX - minX, maxY - minY); +} + +QRectF QSvgLine::bounds(QPainter *p, QSvgExtraStates &s) const { qreal sw = strokeWidth(p); if (qFuzzyIsNull(sw)) { - QPointF p1 = p->transform().map(m_line.p1()); - QPointF p2 = p->transform().map(m_line.p2()); - qreal minX = qMin(p1.x(), p2.x()); - qreal minY = qMin(p1.y(), p2.y()); - qreal maxX = qMax(p1.x(), p2.x()); - qreal maxY = qMax(p1.y(), p2.y()); - return QRectF(minX, minY, maxX - minX, maxY - minY); + return fastBounds(p, s); } else { QPainterPath path; path.moveTo(m_line.p1()); |