1036 lines
31 KiB
C++
1036 lines
31 KiB
C++
|
|
/****************************************************************************
|
||
|
|
**
|
||
|
|
** 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$
|
||
|
|
**
|
||
|
|
****************************************************************************/
|
||
|
|
|
||
|
|
#include "qsvggraphics_p.h"
|
||
|
|
|
||
|
|
#include "qsvgfont_p.h"
|
||
|
|
|
||
|
|
#include <qabstracttextdocumentlayout.h>
|
||
|
|
#include <qdebug.h>
|
||
|
|
#include <qpainter.h>
|
||
|
|
#include <qscopedvaluerollback.h>
|
||
|
|
#include <qtextcursor.h>
|
||
|
|
#include <qtextdocument.h>
|
||
|
|
|
||
|
|
#include <math.h>
|
||
|
|
#include <limits.h>
|
||
|
|
|
||
|
|
QT_BEGIN_NAMESPACE
|
||
|
|
|
||
|
|
#define QT_SVG_DRAW_SHAPE(command) \
|
||
|
|
qreal oldOpacity = p->opacity(); \
|
||
|
|
QBrush oldBrush = p->brush(); \
|
||
|
|
QPen oldPen = p->pen(); \
|
||
|
|
p->setPen(Qt::NoPen); \
|
||
|
|
p->setOpacity(oldOpacity * states.fillOpacity); \
|
||
|
|
command; \
|
||
|
|
p->setPen(oldPen); \
|
||
|
|
if (oldPen != Qt::NoPen && oldPen.brush() != Qt::NoBrush && oldPen.widthF() != 0) { \
|
||
|
|
p->setOpacity(oldOpacity * states.strokeOpacity); \
|
||
|
|
p->setBrush(Qt::NoBrush); \
|
||
|
|
command; \
|
||
|
|
p->setBrush(oldBrush); \
|
||
|
|
} \
|
||
|
|
p->setOpacity(oldOpacity);
|
||
|
|
|
||
|
|
|
||
|
|
void QSvgAnimation::draw(QPainter *, QSvgExtraStates &)
|
||
|
|
{
|
||
|
|
qWarning("<animation> no implemented");
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline QRectF boundsOnStroke(QPainter *p, const QPainterPath &path, qreal width)
|
||
|
|
{
|
||
|
|
QPainterPathStroker stroker;
|
||
|
|
stroker.setWidth(width);
|
||
|
|
QPainterPath stroke = stroker.createStroke(path);
|
||
|
|
return p->transform().map(stroke).boundingRect();
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgEllipse::QSvgEllipse(QSvgNode *parent, const QRectF &rect)
|
||
|
|
: QSvgNode(parent), m_bounds(rect)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
QRectF QSvgEllipse::bounds(QPainter *p, QSvgExtraStates &) const
|
||
|
|
{
|
||
|
|
QPainterPath path;
|
||
|
|
path.addEllipse(m_bounds);
|
||
|
|
qreal sw = strokeWidth(p);
|
||
|
|
return qFuzzyIsNull(sw) ? p->transform().map(path).boundingRect() : boundsOnStroke(p, path, sw);
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgEllipse::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
applyStyle(p, states);
|
||
|
|
QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds));
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgArc::QSvgArc(QSvgNode *parent, const QPainterPath &path)
|
||
|
|
: QSvgNode(parent), m_path(path)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgArc::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
applyStyle(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);
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgImage::QSvgImage(QSvgNode *parent, const QImage &image,
|
||
|
|
const QRectF &bounds)
|
||
|
|
: QSvgNode(parent), m_image(image),
|
||
|
|
m_bounds(bounds)
|
||
|
|
{
|
||
|
|
if (m_bounds.width() == 0.0)
|
||
|
|
m_bounds.setWidth(static_cast<qreal>(m_image.width()));
|
||
|
|
if (m_bounds.height() == 0.0)
|
||
|
|
m_bounds.setHeight(static_cast<qreal>(m_image.height()));
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgImage::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
applyStyle(p, states);
|
||
|
|
p->drawImage(m_bounds, m_image);
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
QSvgLine::QSvgLine(QSvgNode *parent, const QLineF &line)
|
||
|
|
: QSvgNode(parent), m_line(line)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void QSvgLine::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
applyStyle(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);
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgPath::QSvgPath(QSvgNode *parent, const QPainterPath &qpath)
|
||
|
|
: QSvgNode(parent), m_path(qpath)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgPath::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
applyStyle(p, states);
|
||
|
|
m_path.setFillRule(states.fillRule);
|
||
|
|
QT_SVG_DRAW_SHAPE(p->drawPath(m_path));
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF QSvgPath::bounds(QPainter *p, QSvgExtraStates &) const
|
||
|
|
{
|
||
|
|
qreal sw = strokeWidth(p);
|
||
|
|
return qFuzzyIsNull(sw) ? p->transform().map(m_path).boundingRect()
|
||
|
|
: boundsOnStroke(p, m_path, sw);
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgPolygon::QSvgPolygon(QSvgNode *parent, const QPolygonF &poly)
|
||
|
|
: QSvgNode(parent), m_poly(poly)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF QSvgPolygon::bounds(QPainter *p, QSvgExtraStates &) const
|
||
|
|
{
|
||
|
|
qreal sw = strokeWidth(p);
|
||
|
|
if (qFuzzyIsNull(sw)) {
|
||
|
|
return p->transform().map(m_poly).boundingRect();
|
||
|
|
} else {
|
||
|
|
QPainterPath path;
|
||
|
|
path.addPolygon(m_poly);
|
||
|
|
return boundsOnStroke(p, path, sw);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgPolygon::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
applyStyle(p, states);
|
||
|
|
QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly, states.fillRule));
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
QSvgPolyline::QSvgPolyline(QSvgNode *parent, const QPolygonF &poly)
|
||
|
|
: QSvgNode(parent), m_poly(poly)
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgPolyline::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
p->setOpacity(oldOpacity);
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgRect::QSvgRect(QSvgNode *node, const QRectF &rect, int rx, int ry)
|
||
|
|
: QSvgNode(node),
|
||
|
|
m_rect(rect), m_rx(rx), m_ry(ry)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
void QSvgRect::SetRect(QRectF rect)
|
||
|
|
{
|
||
|
|
m_rect=rect;
|
||
|
|
}
|
||
|
|
QRectF &QSvgRect::rect()
|
||
|
|
{
|
||
|
|
return m_rect;
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF QSvgRect::bounds(QPainter *p, QSvgExtraStates &) const
|
||
|
|
{
|
||
|
|
qreal sw = strokeWidth(p);
|
||
|
|
if (qFuzzyIsNull(sw)) {
|
||
|
|
return p->transform().mapRect(m_rect);
|
||
|
|
} else {
|
||
|
|
QPainterPath path;
|
||
|
|
path.addRect(m_rect);
|
||
|
|
return boundsOnStroke(p, path, sw);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgRect::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
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));
|
||
|
|
}
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgTspan * const QSvgText::LINEBREAK = 0;
|
||
|
|
|
||
|
|
QSvgText::QSvgText(QSvgNode *parent, const QPointF &coord)
|
||
|
|
: QSvgNode(parent)
|
||
|
|
, m_coord(coord)
|
||
|
|
, m_type(TEXT)
|
||
|
|
, m_size(0, 0)
|
||
|
|
, m_mode(Default)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgText::~QSvgText()
|
||
|
|
{
|
||
|
|
for (int i = 0; i < m_tspans.size(); ++i) {
|
||
|
|
if (m_tspans[i] != LINEBREAK)
|
||
|
|
delete m_tspans[i];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgText::setTextArea(const QSizeF &size)
|
||
|
|
{
|
||
|
|
m_size = size;
|
||
|
|
m_type = TEXTAREA;
|
||
|
|
}
|
||
|
|
|
||
|
|
//QRectF QSvgText::bounds(QPainter *p, QSvgExtraStates &) const {}
|
||
|
|
|
||
|
|
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();
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF bounds;
|
||
|
|
if (m_size.height() != 0)
|
||
|
|
bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used.
|
||
|
|
|
||
|
|
bool appendSpace = false;
|
||
|
|
QVector<QString> paragraphs;
|
||
|
|
QVector<QVector<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);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
WhitespaceMode mode = m_tspans[i]->whitespaceMode();
|
||
|
|
m_tspans[i]->applyStyle(p, states);
|
||
|
|
|
||
|
|
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(' '));
|
||
|
|
|
||
|
|
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(' ')));
|
||
|
|
|
||
|
|
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);
|
||
|
|
|
||
|
|
appendSpace = appendSpaceNext;
|
||
|
|
paragraphs.back() += newText;
|
||
|
|
|
||
|
|
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());
|
||
|
|
}
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
y += 1.1 * line.height();
|
||
|
|
}
|
||
|
|
tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
|
||
|
|
|
||
|
|
if (endOfBoundsReached)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
p->setWorldTransform(oldTransform, false);
|
||
|
|
p->setOpacity(oldOpacity);
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
int isPrint()
|
||
|
|
{
|
||
|
|
QSharedMemory m_SharedMemory;
|
||
|
|
m_SharedMemory.setKey("SharedName");
|
||
|
|
m_SharedMemory.attach();
|
||
|
|
if(m_SharedMemory.isAttached())
|
||
|
|
{
|
||
|
|
QSharedMemory m_isColor;
|
||
|
|
int *isNo=(int*)m_SharedMemory.data();
|
||
|
|
QString cs=QString::number(*isNo)+"isScaleAndColor";
|
||
|
|
m_isColor.setKey(cs);
|
||
|
|
m_isColor.attach();
|
||
|
|
if(m_isColor.isAttached()){
|
||
|
|
float *temp=(float*)m_isColor.data();
|
||
|
|
return (int)temp[4];
|
||
|
|
}
|
||
|
|
else return 1;
|
||
|
|
}
|
||
|
|
else return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgText::draw(QPainter *p, QSvgExtraStates &states,QRectF bounds,QTransform &Transform,QRectF &sourceRect1,QMatrix &matrix)
|
||
|
|
{
|
||
|
|
float isXScale=1;
|
||
|
|
float isYScale=1;
|
||
|
|
QRectF sourceRect=sourceRect1;
|
||
|
|
sourceRect.setHeight(sourceRect1.height()*isYScale);
|
||
|
|
sourceRect.setWidth(sourceRect1.width()*isXScale);
|
||
|
|
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 =1;// 100.0 / p->font().pointSizeF();
|
||
|
|
Qt::Alignment alignment = states.textAnchor;
|
||
|
|
QFont font1=p->font();
|
||
|
|
if(font1.family()=="Cambria") font1.setFamily("微软雅黑");
|
||
|
|
QTransform oldTransform = p->worldTransform();
|
||
|
|
p->setWorldTransform(Transform, false);
|
||
|
|
p->scale(1 / scale, 1 / scale);
|
||
|
|
QTransform oldTransform1 = p->worldTransform();
|
||
|
|
|
||
|
|
qreal y = 0;
|
||
|
|
bool initial = true;
|
||
|
|
if(sourceRect.width()==0) sourceRect.setWidth(1);
|
||
|
|
if(sourceRect.height()==0) sourceRect.setHeight(1);
|
||
|
|
qreal e=bounds.width() / sourceRect.width();
|
||
|
|
qreal b=bounds.height() / sourceRect.height();
|
||
|
|
|
||
|
|
qreal dx=matrix.dx();
|
||
|
|
qreal dy=matrix.dy();
|
||
|
|
qreal w=matrix.m11();
|
||
|
|
qreal m12=matrix.m12();
|
||
|
|
qreal m21=matrix.m21();
|
||
|
|
qreal c=e;
|
||
|
|
if(c>1) c=1;
|
||
|
|
qreal h=matrix.m22()*c;
|
||
|
|
qreal px = bounds.x() * scale+(bounds.width()+bounds.width()*dx/100.0)* scale;
|
||
|
|
qreal py = bounds.y() * scale+(m_coord.y()-sourceRect.height()*dy/100)*b* scale;//百分比
|
||
|
|
if(m12==1) py=bounds.y() * scale+(bounds.height()+h)/2* scale;//距中
|
||
|
|
else if(m12==2) py=bounds.y() * scale+(bounds.height()-h)*0.9*scale;//距底
|
||
|
|
else if(m12==3) py=bounds.y() * scale+h*1.1*scale;//距顶
|
||
|
|
QSizeF scaledSize = bounds.size() * scale;
|
||
|
|
|
||
|
|
if (m_type == TEXTAREA) {
|
||
|
|
if (alignment == Qt::AlignHCenter)
|
||
|
|
px += scaledSize.width() / 2;
|
||
|
|
else if (alignment == Qt::AlignRight)
|
||
|
|
px += scaledSize.width();
|
||
|
|
}
|
||
|
|
float dpi=65;
|
||
|
|
if(p->device()) {
|
||
|
|
if(isPrint()) {
|
||
|
|
dpi=200;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
dpi=p->device()->logicalDpiX();
|
||
|
|
if(!dpi) dpi=p->device()->physicalDpiX();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
bool appendSpace = false;
|
||
|
|
QVector<QString> paragraphs;
|
||
|
|
QStack<QTextCharFormat> formats;
|
||
|
|
QVector<QList<QTextLayout::FormatRange> > formatRanges;
|
||
|
|
paragraphs.push_back(QString());
|
||
|
|
formatRanges.push_back(QList<QTextLayout::FormatRange>());
|
||
|
|
|
||
|
|
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.push_back(QList<QTextLayout::FormatRange>());
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
WhitespaceMode mode = m_tspans[i]->whitespaceMode();
|
||
|
|
m_tspans[i]->applyStyle(p, states);
|
||
|
|
|
||
|
|
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(' '));
|
||
|
|
|
||
|
|
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(' ')));
|
||
|
|
|
||
|
|
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);
|
||
|
|
|
||
|
|
appendSpace = appendSpaceNext;
|
||
|
|
paragraphs.back() += newText;
|
||
|
|
|
||
|
|
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 m = 0; m < paragraphs.size(); ++m) {
|
||
|
|
QTextLayout tl(paragraphs[m]);
|
||
|
|
QTextOption op = tl.textOption();
|
||
|
|
tl.setAdditionalFormats(formatRanges[m]);
|
||
|
|
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));
|
||
|
|
|
||
|
|
// 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();
|
||
|
|
}
|
||
|
|
QString name1=font1.rawName();
|
||
|
|
float aaaa=font1.pointSizeF();
|
||
|
|
// font1.setPointSizeF(-1);
|
||
|
|
font1.setPixelSize(aaaa);
|
||
|
|
font1.setWeight(1);
|
||
|
|
QFont p1=p->font();
|
||
|
|
float si=h*0.8/10/c;
|
||
|
|
if(b==e||(e==1&&b>2*e)) si = h/2;
|
||
|
|
QPointF pos(px,py);
|
||
|
|
QString s="";
|
||
|
|
|
||
|
|
QPointF textCenterInGeo =pos;
|
||
|
|
p->save();
|
||
|
|
QPointF t(bounds.width(),bounds.height());
|
||
|
|
QPointF nxy=p->transform().map(t);
|
||
|
|
QRectF trect=p->transform().mapRect(bounds);
|
||
|
|
QPointF textCenterInPixel = p->transform().map(textCenterInGeo);
|
||
|
|
p->setWorldTransform(QTransform());//临时切回像素坐标系
|
||
|
|
QString a=paragraphs[m];
|
||
|
|
int va=0,rep=1;
|
||
|
|
float heig=sourceRect.height()*10*c;
|
||
|
|
if(a.indexOf("$")>-1) {
|
||
|
|
rep=trect.height()/(heig);
|
||
|
|
if(rep<1) rep=1;
|
||
|
|
if(rep>1) textCenterInPixel.setY(trect.top()+(trect.height()-heig*rep)/2+heig/2);
|
||
|
|
a.replace("$","");
|
||
|
|
}
|
||
|
|
if(a.indexOf("^^")>-1) va=1;
|
||
|
|
a.replace("^^","^");
|
||
|
|
QStringList aa=a.split('^');
|
||
|
|
QStringList aa1,aa2;
|
||
|
|
int fn=3;
|
||
|
|
for (int k=0;k<aa.size();k++)
|
||
|
|
{
|
||
|
|
aa2=aa[k].split("\\n");
|
||
|
|
if(aa2.size()>1) fn=1;
|
||
|
|
aa1.append(aa2);
|
||
|
|
}
|
||
|
|
aa=aa1;
|
||
|
|
QTextOption op1=op;
|
||
|
|
op1.setAlignment(Qt::AlignLeft);
|
||
|
|
float temp =8;
|
||
|
|
int textWidth=10;
|
||
|
|
int textHeight=10;
|
||
|
|
for(int k=0;k<rep;k++) {
|
||
|
|
for(int j=0;j<aa.size();j++) {
|
||
|
|
QStringList stq=aa[j].split(",");
|
||
|
|
stq.removeAll("");
|
||
|
|
float ssss=0;
|
||
|
|
if(stq.size()>1) {
|
||
|
|
ssss=stq[1].toFloat();
|
||
|
|
}
|
||
|
|
if(!va) {
|
||
|
|
if(p->device()) {
|
||
|
|
temp=si*isXScale*1/72.*dpi;
|
||
|
|
font1.setPixelSize(temp);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
font1.setPixelSize(si*isXScale);
|
||
|
|
}
|
||
|
|
QFontMetrics fm(font1);
|
||
|
|
p->setFont(font1);
|
||
|
|
textWidth=fm.width(aa[j])+1;
|
||
|
|
textHeight = fm.height();
|
||
|
|
QRectF textRect(textCenterInPixel.x()+textWidth/5.0-textWidth,textCenterInPixel.y()+heig*k-textHeight/2.0+j*textHeight/fn,textWidth,textHeight);
|
||
|
|
// textRect.adjust(0,ssss*isXScale*1/72.*dpi,0,ssss*isXScale*1/72.*dpi);
|
||
|
|
// if(textRect.y()<trect.y()) textRect.setY(trect.y());
|
||
|
|
// if(textRect.bottom()>trect.bottom()) textRect.setBottom(trect.bottom());
|
||
|
|
if(aa[j].indexOf("@")>-1) {
|
||
|
|
const QPen pen=p->pen();
|
||
|
|
float lw=pen.widthF();
|
||
|
|
QString w;
|
||
|
|
if(stq.size()>1) w=stq[0].mid(1);
|
||
|
|
else w=aa[j].mid(1);
|
||
|
|
if (w.isEmpty())
|
||
|
|
{
|
||
|
|
w="2";
|
||
|
|
}
|
||
|
|
QPen pp=pen;
|
||
|
|
pp.setWidthF(w.toFloat()*isXScale*1/72.*dpi);
|
||
|
|
p->setPen(pp);
|
||
|
|
QPointF lt=trect.topLeft();
|
||
|
|
QPointF rt=trect.topRight();
|
||
|
|
lt.setY(textRect.y()+ssss*isXScale*1/72.*dpi);
|
||
|
|
rt.setY(textRect.y()+ssss*isXScale*1/72.*dpi);
|
||
|
|
if(lt.y()<trect.y()) lt.setY(trect.y());
|
||
|
|
if(lt.y()>trect.bottom()) lt.setY(trect.bottom());
|
||
|
|
if(rt.y()<trect.y()) rt.setY(trect.y());
|
||
|
|
if(rt.y()>trect.bottom()) rt.setY(trect.bottom());
|
||
|
|
p->drawLine(lt,rt);
|
||
|
|
pp.setWidthF(lw);
|
||
|
|
p->setPen(pp);
|
||
|
|
}
|
||
|
|
else if(name1.indexOf("@")<0)
|
||
|
|
{
|
||
|
|
p->drawText(textRect,aa[j],op1);//绘制解释层号
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
p->save();
|
||
|
|
///////////////
|
||
|
|
QPointF textCenterInGeo =textRect.center();
|
||
|
|
QPointF textCenterInPixel = p->transform().map(textCenterInGeo);
|
||
|
|
QRectF trect = p->transform().mapRect(textRect);
|
||
|
|
QTransform transform;
|
||
|
|
qreal rotatex=0;
|
||
|
|
qreal rotatey=0;
|
||
|
|
rotatex=textCenterInPixel.x();
|
||
|
|
rotatey=textCenterInPixel.y();
|
||
|
|
transform.reset();
|
||
|
|
{
|
||
|
|
transform.translate(rotatex,rotatey);
|
||
|
|
transform.rotate(-90.0);
|
||
|
|
transform.translate(-rotatex,-rotatey);
|
||
|
|
p->setWorldTransform(transform);
|
||
|
|
}
|
||
|
|
p->drawText(textRect,aa[j],op1);//绘制解释层号
|
||
|
|
p->restore();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
if(p->device()) {
|
||
|
|
temp = si/(aa.size())*isXScale*1/72.*dpi;
|
||
|
|
font1.setPixelSize(temp);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
font1.setPixelSize(si/(aa.size())*isXScale);
|
||
|
|
}
|
||
|
|
QFontMetrics fm(font1);
|
||
|
|
p->setFont(font1);
|
||
|
|
textWidth = fm.width(aa[j])+1;
|
||
|
|
textHeight = fm.height();
|
||
|
|
if(textHeight>trect.height()) textHeight=trect.height();
|
||
|
|
QRectF textRect(textCenterInPixel.x()+textWidth/5.0-textWidth+textWidth*j*3.0/4.0,textCenterInPixel.y()-textHeight/2.0-j*textHeight/fn+heig*k,textWidth,textHeight);
|
||
|
|
if(aa[j].indexOf("@")>-1) {
|
||
|
|
const QPen pen=p->pen();
|
||
|
|
float lw=pen.widthF();
|
||
|
|
QString w;
|
||
|
|
if(stq.size()>1) w=stq[0].mid(1);
|
||
|
|
else w=aa[j].mid(1);
|
||
|
|
if (w.isEmpty())
|
||
|
|
{
|
||
|
|
w="2";
|
||
|
|
}
|
||
|
|
if(stq.size()>1) w=stq[0];
|
||
|
|
/*QStringList stq=w.split(",");
|
||
|
|
stq.removeAll("");
|
||
|
|
float ssss=0;
|
||
|
|
if(stq.size()>1) {
|
||
|
|
w=stq[0];
|
||
|
|
ssss=stq[1].toFloat();
|
||
|
|
}*/
|
||
|
|
QPen pp=pen;
|
||
|
|
pp.setWidthF(w.toFloat()*isXScale*1/72.*dpi);
|
||
|
|
p->setPen(pp);
|
||
|
|
QPointF lt=trect.topLeft();
|
||
|
|
QPointF rt=trect.topRight();
|
||
|
|
lt.setY(textRect.y()+ssss*isXScale*1/72.*dpi);
|
||
|
|
rt.setY(textRect.y()+ssss*isXScale*1/72.*dpi);
|
||
|
|
if(lt.y()<trect.y()) lt.setY(trect.y());
|
||
|
|
if(lt.y()>trect.bottom()) lt.setY(trect.bottom());
|
||
|
|
if(rt.y()<trect.y()) rt.setY(trect.y());
|
||
|
|
if(rt.y()>trect.bottom()) rt.setY(trect.bottom());
|
||
|
|
lt.setY(textRect.y()+ssss*isXScale*1/72.*dpi);
|
||
|
|
rt.setY(textRect.y()+ssss*isXScale*1/72.*dpi);
|
||
|
|
p->drawLine(lt,rt);
|
||
|
|
pp.setWidthF(lw);
|
||
|
|
p->setPen(pp);
|
||
|
|
}
|
||
|
|
else if(name1.indexOf("@")<0)
|
||
|
|
{
|
||
|
|
p->drawText(textRect,aa[j],op1);//绘制解释层号
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
p->save();
|
||
|
|
///////////////
|
||
|
|
QPointF textCenterInGeo =textRect.center();
|
||
|
|
QPointF textCenterInPixel = p->transform().map(textCenterInGeo);
|
||
|
|
QRectF trect = p->transform().mapRect(textRect);
|
||
|
|
QTransform transform;
|
||
|
|
qreal rotatex=0;
|
||
|
|
qreal rotatey=0;
|
||
|
|
rotatex=textCenterInPixel.x();
|
||
|
|
rotatey=textCenterInPixel.y();
|
||
|
|
transform.reset();
|
||
|
|
{
|
||
|
|
transform.translate(rotatex,rotatey);
|
||
|
|
transform.rotate(-90.0);
|
||
|
|
transform.translate(-rotatex,-rotatey);
|
||
|
|
p->setWorldTransform(transform);
|
||
|
|
}
|
||
|
|
p->drawText(textRect,aa[j],op1);//绘制解释层号
|
||
|
|
p->restore();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
p->restore();//退出像素坐标系
|
||
|
|
p->setFont(p1);
|
||
|
|
if (endOfBoundsReached)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
p->setWorldTransform(oldTransform, false);
|
||
|
|
p->setOpacity(oldOpacity);
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgText::addText(const QString &text)
|
||
|
|
{
|
||
|
|
m_tspans.append(new QSvgTspan(this, false));
|
||
|
|
m_tspans.back()->setWhitespaceMode(m_mode);
|
||
|
|
m_tspans.back()->addText(text);
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgUse::QSvgUse(const QPointF &start, QSvgNode *parent, QSvgNode *node)
|
||
|
|
: QSvgNode(parent), m_link(node), m_start(start), m_recursing(false)
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgUse::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
if (Q_UNLIKELY(!m_link || isDescendantOf(m_link) || m_recursing))
|
||
|
|
return;
|
||
|
|
|
||
|
|
applyStyle(p, states);
|
||
|
|
|
||
|
|
if (!m_start.isNull()) {
|
||
|
|
p->translate(m_start);
|
||
|
|
}
|
||
|
|
{
|
||
|
|
QScopedValueRollback<bool> guard(m_recursing, true);
|
||
|
|
m_link->draw(p, states);
|
||
|
|
}
|
||
|
|
if (!m_start.isNull()) {
|
||
|
|
p->translate(-m_start);
|
||
|
|
}
|
||
|
|
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
void QSvgVideo::draw(QPainter *p, QSvgExtraStates &states)
|
||
|
|
{
|
||
|
|
applyStyle(p, states);
|
||
|
|
|
||
|
|
revertStyle(p, states);
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgAnimation::type() const
|
||
|
|
{
|
||
|
|
return ANIMATION;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgArc::type() const
|
||
|
|
{
|
||
|
|
return ARC;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgCircle::type() const
|
||
|
|
{
|
||
|
|
return CIRCLE;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgEllipse::type() const
|
||
|
|
{
|
||
|
|
return ELLIPSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgImage::type() const
|
||
|
|
{
|
||
|
|
return IMAGE;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgLine::type() const
|
||
|
|
{
|
||
|
|
return LINE;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgPath::type() const
|
||
|
|
{
|
||
|
|
return PATH;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgPolygon::type() const
|
||
|
|
{
|
||
|
|
return POLYGON;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgPolyline::type() const
|
||
|
|
{
|
||
|
|
return POLYLINE;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgRect::type() const
|
||
|
|
{
|
||
|
|
return RECT;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgText::type() const
|
||
|
|
{
|
||
|
|
return m_type;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgUse::type() const
|
||
|
|
{
|
||
|
|
return USE;
|
||
|
|
}
|
||
|
|
|
||
|
|
QSvgNode::Type QSvgVideo::type() const
|
||
|
|
{
|
||
|
|
return VIDEO;
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF QSvgUse::bounds(QPainter *p, QSvgExtraStates &states) const
|
||
|
|
{
|
||
|
|
QRectF bounds;
|
||
|
|
if (Q_LIKELY(m_link && !isDescendantOf(m_link) && !m_recursing)) {
|
||
|
|
QScopedValueRollback<bool> guard(m_recursing, true);
|
||
|
|
p->translate(m_start);
|
||
|
|
bounds = m_link->transformedBounds(p, states);
|
||
|
|
p->translate(-m_start);
|
||
|
|
}
|
||
|
|
return bounds;
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF QSvgPolyline::bounds(QPainter *p, QSvgExtraStates &) const
|
||
|
|
{
|
||
|
|
qreal sw = strokeWidth(p);
|
||
|
|
if (qFuzzyIsNull(sw)) {
|
||
|
|
return p->transform().map(m_poly).boundingRect();
|
||
|
|
} else {
|
||
|
|
QPainterPath path;
|
||
|
|
path.addPolygon(m_poly);
|
||
|
|
return boundsOnStroke(p, path, sw);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF QSvgArc::bounds(QPainter *p, QSvgExtraStates &) const
|
||
|
|
{
|
||
|
|
qreal sw = strokeWidth(p);
|
||
|
|
return qFuzzyIsNull(sw) ? p->transform().map(m_path).boundingRect()
|
||
|
|
: boundsOnStroke(p, m_path, sw);
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF QSvgImage::bounds(QPainter *p, QSvgExtraStates &) const
|
||
|
|
{
|
||
|
|
return p->transform().mapRect(m_bounds);
|
||
|
|
}
|
||
|
|
|
||
|
|
QRectF QSvgLine::bounds(QPainter *p, QSvgExtraStates &) 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);
|
||
|
|
} else {
|
||
|
|
QPainterPath path;
|
||
|
|
path.moveTo(m_line.p1());
|
||
|
|
path.lineTo(m_line.p2());
|
||
|
|
return boundsOnStroke(p, path, sw);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
QT_END_NAMESPACE
|