summaryrefslogtreecommitdiffstats
path: root/src/svg
diff options
context:
space:
mode:
Diffstat (limited to 'src/svg')
-rw-r--r--src/svg/qsvggraphics.cpp286
-rw-r--r--src/svg/qsvggraphics_p.h51
-rw-r--r--src/svg/qsvghandler.cpp594
-rw-r--r--src/svg/qsvgnode_p.h1
-rw-r--r--src/svg/qsvgstyle.cpp126
-rw-r--r--src/svg/qsvgstyle_p.h80
6 files changed, 490 insertions, 648 deletions
diff --git a/src/svg/qsvggraphics.cpp b/src/svg/qsvggraphics.cpp
index e09f382..2be7559 100644
--- a/src/svg/qsvggraphics.cpp
+++ b/src/svg/qsvggraphics.cpp
@@ -266,21 +266,23 @@ void QSvgRect::draw(QPainter *p, QSvgExtraStates &states)
}
}
+QSvgTspan * const QSvgText::LINEBREAK = 0;
+
QSvgText::QSvgText(QSvgNode *parent, const QPointF &coord)
: QSvgNode(parent)
, m_coord(coord)
- , m_textAlignment(Qt::AlignLeft)
- , m_scale(1)
- , m_appendSpace(false)
, m_type(TEXT)
, m_size(0, 0)
+ , m_mode(Default)
{
- m_paragraphs.push_back(QString());
- m_formatRanges.push_back(QList<QTextLayout::FormatRange>());
}
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)
@@ -295,175 +297,173 @@ void QSvgText::draw(QPainter *p, QSvgExtraStates &states)
{
applyStyle(p, states);
- QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
- styleProperty(QSvgStyleProperty::FONT));
- if (fontStyle && fontStyle->svgFont()) {
- // SVG fonts not fully supported...
- QString text = m_paragraphs.front();
- for (int i = 1; i < m_paragraphs.size(); ++i) {
- text.append(QLatin1Char('\n'));
- text.append(m_paragraphs[i]);
- }
- fontStyle->svgFont()->draw(p, m_coord, text, fontStyle->pointSize(), m_textAlignment);
- revertStyle(p, states);
- return;
- }
+ // 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;
- // Scale the font to its correct size.
QTransform oldTransform = p->worldTransform();
- p->scale(1 / m_scale, 1 / m_scale);
+ p->scale(1 / scale, 1 / scale);
qreal y = 0;
bool initial = true;
- qreal px = m_coord.x() * m_scale;
- qreal py = m_coord.y() * m_scale;
- QSizeF scaledSize = m_size * m_scale;
+ qreal px = m_coord.x() * scale;
+ qreal py = m_coord.y() * scale;
+ QSizeF scaledSize = m_size * scale;
if (m_type == TEXTAREA) {
- if (m_textAlignment == Qt::AlignHCenter)
+ if (alignment == Qt::AlignHCenter)
px += scaledSize.width() / 2;
- else if (m_textAlignment == Qt::AlignRight)
+ else if (alignment == Qt::AlignRight)
px += scaledSize.width();
}
QRectF bounds;
if (m_size.height() != 0)
- bounds = QRectF(0, 0, 1, scaledSize.height());
-
- for (int i = 0; i < m_paragraphs.size(); ++i) {
- QTextLayout tl(m_paragraphs[i]);
- QTextOption op = tl.textOption();
- op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- tl.setTextOption(op);
- tl.setAdditionalFormats(m_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 (m_textAlignment == Qt::AlignHCenter)
- x -= line.naturalTextWidth() / 2;
- else if (m_textAlignment == Qt::AlignRight)
- x -= line.naturalTextWidth();
-
- if (initial && m_type == TEXT)
- y -= line.ascent();
- initial = false;
-
- line.setPosition(QPointF(x, y));
- if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
- || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
- bounds.setHeight(y);
- endOfBoundsReached = true;
- break;
+ bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used.
+
+ 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);
- y += 1.1 * line.height();
- }
- tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
+ QFont font = p->font();
+ font.setPixelSize(font.pointSizeF() * scale);
- if (endOfBoundsReached)
- break;
- }
+ QString newText(m_tspans[i]->text());
+ newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
+ newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
- p->setWorldTransform(oldTransform, false);
- revertStyle(p, states);
-}
+ bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
+ if (appendSpace || prependSpace)
+ paragraphs.back().append(QLatin1Char(' '));
-void QSvgText::insertText(const QString &text, WhitespaceMode mode)
-{
- bool isTSpan = (m_formats.count() == 2);
- QString newText(text);
- newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
- newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
+ bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
- bool prependSpace = !m_appendSpace && !isTSpan && (mode == Default) && !m_paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
- if (m_appendSpace || prependSpace)
- m_paragraphs.back().append(QLatin1Char(' '));
+ if (mode == Default) {
+ newText = newText.simplified();
+ if (newText.isEmpty())
+ appendSpaceNext = false;
+ }
- bool appendSpaceNext = (!isTSpan && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
+ 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);
- if (mode == Default) {
- newText = newText.simplified();
- if (newText.isEmpty())
- appendSpaceNext = false;
- }
+ appendSpace = appendSpaceNext;
+ paragraphs.back() += newText;
- if (!m_formats.isEmpty()) {
- QTextLayout::FormatRange range;
- range.start = m_paragraphs.back().length();
- range.length = newText.length();
- range.format = m_formats.top();
- if (m_appendSpace) {
- Q_ASSERT(!m_formatRanges.back().isEmpty());
- ++m_formatRanges.back().back().length;
- } else if (prependSpace) {
- --range.start;
- ++range.length;
+ m_tspans[i]->revertStyle(p, states);
}
- m_formatRanges.back().append(range);
}
- m_appendSpace = appendSpaceNext;
- m_paragraphs.back() += newText;
-}
-
-void QSvgText::insertFormat(const QTextCharFormat &format)
-{
- QTextCharFormat mergedFormat = format;
- if (!m_formats.isEmpty()) {
- mergedFormat = m_formats.top();
- mergedFormat.merge(format);
- }
- m_formats.push(mergedFormat);
-}
+ 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, 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.setAdditionalFormats(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);
-void QSvgText::insertLineBreak()
-{
- if (m_type == TEXTAREA) {
- if (m_paragraphs.back().isEmpty())
- insertText(QLatin1String(" "), Preserve);
- m_appendSpace = false;
- m_paragraphs.push_back(QString());
- m_formatRanges.push_back(QList<QTextLayout::FormatRange>());
+ if (endOfBoundsReached)
+ break;
+ }
}
-}
-void QSvgText::popFormat()
-{
- if (m_formats.count() > 1)
- m_formats.pop();
-}
-
-qreal QSvgText::scale() const
-{
- return m_scale;
-}
-
-void QSvgText::setScale(qreal scale)
-{
- m_scale = scale;
-}
-
-const QTextCharFormat &QSvgText::topFormat() const
-{
- return m_formats.top();
+ p->setWorldTransform(oldTransform, false);
+ revertStyle(p, states);
}
-void QSvgText::setTextAlignment(const Qt::Alignment &alignment)
+void QSvgText::addText(const QString &text)
{
- m_textAlignment = alignment;
+ 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)
diff --git a/src/svg/qsvggraphics_p.h b/src/svg/qsvggraphics_p.h
index 4a19c7e..345b90b 100644
--- a/src/svg/qsvggraphics_p.h
+++ b/src/svg/qsvggraphics_p.h
@@ -187,6 +187,8 @@ private:
int m_rx, m_ry;
};
+class QSvgTspan;
+
class QSvgText : public QSvgNode
{
public:
@@ -202,26 +204,47 @@ public:
virtual void draw(QPainter *p, QSvgExtraStates &states);
virtual Type type() const;
- void insertText(const QString &text, WhitespaceMode mode);
- void insertFormat(const QTextCharFormat &format);
- void insertLineBreak();
- void popFormat();
- void setTextAlignment(const Qt::Alignment &alignment);
- const QTextCharFormat &topFormat() const;
- qreal scale() const;
- void setScale(qreal scale);
+
+ void addTspan(QSvgTspan *tspan) {m_tspans.append(tspan);}
+ void addText(const QString &text);
+ void addLineBreak() {m_tspans.append(LINEBREAK);}
+ void setWhitespaceMode(WhitespaceMode mode) {m_mode = mode;}
+
//virtual QRectF bounds() const;
private:
+ static QSvgTspan * const LINEBREAK;
+
QPointF m_coord;
- QVector<QString> m_paragraphs;
- QStack<QTextCharFormat> m_formats;
- Qt::Alignment m_textAlignment;
- QVector<QList<QTextLayout::FormatRange> > m_formatRanges;
- qreal m_scale;
- bool m_appendSpace;
+ // 'm_tspans' is also used to store characters outside tspans and line breaks.
+ // If a 'm_tspan' item is null, it indicates a line break.
+ QVector<QSvgTspan *> m_tspans;
+
Type m_type;
QSizeF m_size;
+ WhitespaceMode m_mode;
+};
+
+class QSvgTspan : public QSvgNode
+{
+public:
+ // tspans are also used to store normal text, so the 'isProperTspan' is used to separate text from tspan.
+ QSvgTspan(QSvgNode *parent, bool isProperTspan = true)
+ : QSvgNode(parent), m_mode(QSvgText::Default), m_isTspan(isProperTspan)
+ {
+ }
+ ~QSvgTspan() { };
+ virtual Type type() const {return TSPAN;}
+ virtual void draw(QPainter *, QSvgExtraStates &) {Q_ASSERT(!"Tspans should be drawn through QSvgText::draw().");}
+ void addText(const QString &text) {m_text += text;}
+ const QString &text() const {return m_text;}
+ bool isTspan() const {return m_isTspan;}
+ void setWhitespaceMode(QSvgText::WhitespaceMode mode) {m_mode = mode;}
+ QSvgText::WhitespaceMode whitespaceMode() const {return m_mode;}
+private:
+ QString m_text;
+ QSvgText::WhitespaceMode m_mode;
+ bool m_isTspan;
};
class QSvgUse : public QSvgNode
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index 5857e1c..73c8b01 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -39,6 +39,8 @@
**
****************************************************************************/
+#include "qplatformdefs.h"
+
#include "qsvghandler_p.h"
#ifndef QT_NO_SVG
@@ -68,6 +70,8 @@
QT_BEGIN_NAMESPACE
+static const char *qt_inherit_text = "inherit";
+#define QT_INHERIT QLatin1String(qt_inherit_text)
double qstrtod(const char *s00, char const **se, bool *ok);
@@ -354,7 +358,7 @@ static qreal toDouble(const QChar *&str)
if (neg)
val = -val;
} else {
-#ifdef Q_WS_QWS
+#if defined(Q_WS_QWS) && !defined(Q_OS_VXWORKS)
if(sizeof(qreal) == sizeof(float))
val = strtof(temp, 0);
else
@@ -490,7 +494,7 @@ static bool resolveColor(const QString &colorStr, QColor &color, QSvgHandler *ha
int(compo[2]));
return true;
} else if (colorStr == QLatin1String("inherited") ||
- colorStr == QLatin1String("inherit")) {
+ colorStr == QT_INHERIT) {
return false;
} else if (colorStr == QLatin1String("currentColor")) {
color = handler->currentColor();
@@ -644,138 +648,48 @@ static void parseBrush(QSvgNode *node,
QString opacity = attributes.value(QLatin1String("fill-opacity")).toString();
QString myId = someId(attributes);
- QSvgFillStyle *prop = new QSvgFillStyle(0);
-
- //fill-rule attribute handling
- if (!fillRule.isEmpty() && fillRule != QLatin1String("inherit")) {
- if (fillRule == QLatin1String("evenodd"))
- prop->setFillRule(Qt::OddEvenFill);
- else if (fillRule == QLatin1String("nonzero"))
- prop->setFillRule(Qt::WindingFill);
- }
-
- //fill-opacity atttribute handling
- if (!opacity.isEmpty() && opacity != QLatin1String("inherit")) {
- prop->setFillOpacity(qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))));
- }
+ if (!value.isEmpty() || !fillRule.isEmpty() || !opacity.isEmpty()) {
+ QSvgFillStyle *prop = new QSvgFillStyle(0);
- //fill attribute handling
- if ((!value.isEmpty()) && (value != QLatin1String("inherit")) ) {
- if (value.startsWith(QLatin1String("url"))) {
- value = value.remove(0, 3);
- QSvgStyleProperty *style = styleFromUrl(node, value);
- if (style) {
- prop->setFillStyle(style);
- } else {
- QString id = idFromUrl(value);
- prop->setGradientId(id);
- prop->setGradientResolved(false);
- }
- } else if (value != QLatin1String("none")) {
- QColor color;
- if (resolveColor(value, color, handler))
- prop->setBrush(QBrush(color));
- } else {
- prop->setBrush(QBrush(Qt::NoBrush));
+ //fill-rule attribute handling
+ if (!fillRule.isEmpty() && fillRule != QT_INHERIT) {
+ if (fillRule == QLatin1String("evenodd"))
+ prop->setFillRule(Qt::OddEvenFill);
+ else if (fillRule == QLatin1String("nonzero"))
+ prop->setFillRule(Qt::WindingFill);
}
- }
- node->appendStyleProperty(prop,myId);
-}
+ //fill-opacity atttribute handling
+ if (!opacity.isEmpty() && opacity != QT_INHERIT) {
+ prop->setFillOpacity(qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))));
+ }
-static void parseQPen(QPen &pen, QSvgNode *node,
- const QSvgAttributes &attributes,
- QSvgHandler *handler)
-{
- QString value = attributes.value(QLatin1String("stroke")).toString();
- QString dashArray = attributes.value(QLatin1String("stroke-dasharray")).toString();
- QString dashOffset = attributes.value(QLatin1String("stroke-dashoffset")).toString();
- QString linecap = attributes.value(QLatin1String("stroke-linecap")).toString();
- QString linejoin = attributes.value(QLatin1String("stroke-linejoin")).toString();
- QString miterlimit = attributes.value(QLatin1String("stroke-miterlimit")).toString();
- QString opacity = attributes.value(QLatin1String("stroke-opacity")).toString();
- QString width = attributes.value(QLatin1String("stroke-width")).toString();
- QString myId = someId(attributes);
-
- if (!value.isEmpty() || !width.isEmpty()) {
- if (value != QLatin1String("none")) {
- if (!value.isEmpty()) {
- if (node && value.startsWith(QLatin1String("url"))) {
- value = value.remove(0, 3);
- QSvgStyleProperty *style = styleFromUrl(node, value);
- if (style) {
- if (style->type() == QSvgStyleProperty::GRADIENT) {
- QBrush b(*((QSvgGradientStyle*)style)->qgradient());
- pen.setBrush(b);
- } else if (style->type() == QSvgStyleProperty::SOLID_COLOR) {
- pen.setColor(
- ((QSvgSolidColorStyle*)style)->qcolor());
- }
- } else {
- qWarning()<<"QSvgHandler::parsePen could not resolve property" << idFromUrl(value);
- }
+ //fill attribute handling
+ if ((!value.isEmpty()) && (value != QT_INHERIT) ) {
+ if (value.startsWith(QLatin1String("url"))) {
+ value = value.remove(0, 3);
+ QSvgStyleProperty *style = styleFromUrl(node, value);
+ if (style) {
+ prop->setFillStyle(style);
} else {
- QColor color;
- if (constructColor(value, opacity, color, handler))
- pen.setColor(color);
+ QString id = idFromUrl(value);
+ prop->setGradientId(id);
+ prop->setGradientResolved(false);
}
- //since we could inherit stroke="none"
- //we need to reset the style of our stroke to something
- pen.setStyle(Qt::SolidLine);
- }
- if (!width.isEmpty()) {
- QSvgHandler::LengthType lt;
- qreal widthF = parseLength(width, lt, handler);
- //### fixme
- if (!widthF) {
- pen.setStyle(Qt::NoPen);
- return;
- }
- pen.setWidthF(widthF);
- }
- qreal penw = pen.widthF();
-
- if (!linejoin.isEmpty()) {
- if (linejoin == QLatin1String("miter"))
- pen.setJoinStyle(Qt::SvgMiterJoin);
- else if (linejoin == QLatin1String("round"))
- pen.setJoinStyle(Qt::RoundJoin);
- else if (linejoin == QLatin1String("bevel"))
- pen.setJoinStyle(Qt::BevelJoin);
- }
- if (!miterlimit.isEmpty())
- pen.setMiterLimit(toDouble(miterlimit));
-
- if (!linecap.isEmpty()) {
- if (linecap == QLatin1String("butt"))
- pen.setCapStyle(Qt::FlatCap);
- else if (linecap == QLatin1String("round"))
- pen.setCapStyle(Qt::RoundCap);
- else if (linecap == QLatin1String("square"))
- pen.setCapStyle(Qt::SquareCap);
- }
-
- if (!dashArray.isEmpty()) {
- const QChar *s = dashArray.constData();
- QVector<qreal> dashes = parseNumbersList(s);
- qreal *d = dashes.data();
- if (penw != 0)
- for (int i = 0; i < dashes.size(); ++i) {
- *d /= penw;
- ++d;
- }
- pen.setDashPattern(dashes);
- }
- if (!dashOffset.isEmpty()) {
- pen.setDashOffset(toDouble(dashOffset));
+ } else if (value != QLatin1String("none")) {
+ QColor color;
+ if (resolveColor(value, color, handler))
+ prop->setBrush(QBrush(color));
+ } else {
+ prop->setBrush(QBrush(Qt::NoBrush));
}
-
- } else {
- pen.setStyle(Qt::NoPen);
}
+ node->appendStyleProperty(prop, myId);
}
}
+
+
static QMatrix parseTransformationMatrix(const QString &value)
{
QMatrix matrix;
@@ -915,18 +829,15 @@ static void parsePen(QSvgNode *node,
QString miterlimit = attributes.value(QLatin1String("stroke-miterlimit")).toString();
QString opacity = attributes.value(QLatin1String("stroke-opacity")).toString();
QString width = attributes.value(QLatin1String("stroke-width")).toString();
+ QString vectorEffect = attributes.value(QLatin1String("vector-effect")).toString();
QString myId = someId(attributes);
//qDebug()<<"Node "<<node->type()<<", attrs are "<<value<<width;
- /* All the below checks needed because g (or any container element) can have only one of these attributes.
- * If it doesn't has any one of these, then processing below not needed */
-
if (!value.isEmpty() || !width.isEmpty() || !dashArray.isEmpty() || !linecap.isEmpty() ||
- !linejoin.isEmpty() || !miterlimit.isEmpty() || !opacity.isEmpty() || !dashOffset.isEmpty() ) {
- //if (value != QLatin1String("none")) {
- /* If stroke = "none" then also, we need to parse below, because elements like 'g' may
- have other defined stroke attributes, which will be inherited by its children */
+ !linejoin.isEmpty() || !miterlimit.isEmpty() || !opacity.isEmpty() ||
+ !dashOffset.isEmpty() || !vectorEffect.isEmpty()) {
+
QSvgStrokeStyle *inherited =
static_cast<QSvgStrokeStyle*>(node->parent()->styleProperty(
QSvgStyleProperty::STROKE));
@@ -940,14 +851,14 @@ static void parsePen(QSvgNode *node,
// stroke-opacity attribute handling
qreal strokeAlpha;
- if (!opacity.isEmpty() && opacity != QLatin1String("inherit")) {
+ if (!opacity.isEmpty() && opacity != QT_INHERIT) {
strokeAlpha = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity)));
} else {
strokeAlpha = pen.color().alphaF();
}
//stroke attribute handling
- if (!value.isEmpty() && value != QLatin1String("inherit")) {
+ if (!value.isEmpty() && value != QT_INHERIT) {
if (value.startsWith(QLatin1String("url"))) {
value = value.remove(0, 3);
QSvgStyleProperty *style = styleFromUrl(node, value);
@@ -959,8 +870,7 @@ static void parsePen(QSvgNode *node,
pen.setColor(
((QSvgSolidColorStyle*)style)->qcolor());
}
- pen.setStyle(Qt::SolidLine);
- stroke = true;
+ stroke = true;
} else {
qWarning() << "QSvgHandler::parsePen could not resolve property" << idFromUrl(value);
}
@@ -984,14 +894,11 @@ static void parsePen(QSvgNode *node,
}
//stroke-width handling
- if (!width.isEmpty() && width != QLatin1String("inherit")) {
+ if (!width.isEmpty() && width != QT_INHERIT) {
qreal widthF;
QSvgHandler::LengthType lt;
widthF = parseLength(width, lt, handler);
pen.setWidthF(widthF);
- } else if (inherited){
- qreal widthF = inherited->qpen().widthF();
- pen.setWidthF(widthF);
}
//stroke-linejoin attribute handling
@@ -1016,7 +923,7 @@ static void parsePen(QSvgNode *node,
//strok-dasharray attribute handling
qreal penw = pen.widthF();
- if (!dashArray.isEmpty() && dashArray != QLatin1String("inherit")) {
+ if (!dashArray.isEmpty() && dashArray != QT_INHERIT) {
const QChar *s = dashArray.constData();
QVector<qreal> dashes = parseNumbersList(s);
qreal *d = dashes.data();
@@ -1046,7 +953,7 @@ static void parsePen(QSvgNode *node,
//stroke-dashoffset attribute handling
- if (!dashOffset.isEmpty() && dashOffset != QLatin1String("inherit")) {
+ if (!dashOffset.isEmpty() && dashOffset != QT_INHERIT) {
qreal doffset = toDouble(dashOffset);
if (penw != 0)
doffset /= penw;
@@ -1062,7 +969,15 @@ static void parsePen(QSvgNode *node,
pen.setDashOffset(doffset);
}
- if (!miterlimit.isEmpty() && miterlimit != QLatin1String("inherit"))
+ //vector-effect attribute handling
+ if (!vectorEffect.isEmpty()) {
+ if (vectorEffect == QLatin1String("non-scaling-stroke"))
+ pen.setCosmetic(true);
+ else if (vectorEffect == QLatin1String("none"))
+ pen.setCosmetic(false);
+ }
+
+ if (!miterlimit.isEmpty() && miterlimit != QT_INHERIT)
pen.setMiterLimit(toDouble(miterlimit));
QSvgStrokeStyle *prop = new QSvgStrokeStyle(pen);
@@ -1071,182 +986,84 @@ static void parsePen(QSvgNode *node,
}
}
-
-static bool parseQBrush(const QSvgAttributes &attributes, QSvgNode *node,
- QBrush &brush, QSvgHandler *handler)
-{
- QString value = attributes.value(QLatin1String("fill")).toString();
- QString opacity = attributes.value(QLatin1String("fill-opacity")).toString();
-
- QColor color;
- if (!value.isEmpty() || !opacity.isEmpty()) {
- if (value.startsWith(QLatin1String("url"))) {
- value = value.remove(0, 3);
- QSvgStyleProperty *style = styleFromUrl(node, value);
- if (style) {
- switch (style->type()) {
- case QSvgStyleProperty::FILL:
- {
- brush = static_cast<QSvgFillStyle*>(style)->qbrush();
- break;
- }
- case QSvgStyleProperty::SOLID_COLOR:
- {
- brush = QBrush(static_cast<QSvgSolidColorStyle*>(style)->qcolor());
- break;
- }
- case QSvgStyleProperty::GRADIENT:
- {
- brush = QBrush(*static_cast<QSvgGradientStyle*>(style)->qgradient());
- break;
- }
- default:
- qWarning("Cannot use property \"%s\" as brush.", qPrintable(idFromUrl(value)));
- }
- } else {
- qWarning("Couldn't resolve property: %s", qPrintable(idFromUrl(value)));
- }
- } else if (value != QLatin1String("none")) {
- if (constructColor(value, opacity, color, handler)) {
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(color);
- }
- } else {
- brush = QBrush(Qt::NoBrush);
- }
- return true;
- }
- return false;
-}
-
-static bool parseQFont(const QSvgAttributes &attributes,
- QFont &font, qreal &fontSize, QSvgHandler *handler)
+static void parseFont(QSvgNode *node,
+ const QSvgAttributes &attributes,
+ QSvgHandler *handler)
{
QString family = attributes.value(QLatin1String("font-family")).toString();
QString size = attributes.value(QLatin1String("font-size")).toString();
QString style = attributes.value(QLatin1String("font-style")).toString();
QString weight = attributes.value(QLatin1String("font-weight")).toString();
+ QString variant = attributes.value(QLatin1String("font-variant")).toString();
+ QString anchor = attributes.value(QLatin1String("text-anchor")).toString();
- if (!family.isEmpty() || !size.isEmpty() ||
- !style.isEmpty() || !weight.isEmpty()) {
+ if (family.isEmpty() && size.isEmpty() && style.isEmpty() && weight.isEmpty() && variant.isEmpty() && anchor.isEmpty())
+ return;
- if (!family.isEmpty()) {
- font.setFamily(family.trimmed());
- }
- if (!size.isEmpty()) {
- if (size == QLatin1String("inherit")) {
- //inherited already
- } else {
- QSvgHandler::LengthType dummy; // should always be pixel size
- fontSize = parseLength(size, dummy, handler);
- if (fontSize <= 0)
- fontSize = 1;
- }
- font.setPixelSize(qMax(1, int(fontSize)));
- }
- if (!style.isEmpty()) {
- if (style == QLatin1String("normal")) {
- font.setStyle(QFont::StyleNormal);
- } else if (style == QLatin1String("italic")) {
- font.setStyle(QFont::StyleItalic);
- } else if (style == QLatin1String("oblique")) {
- font.setStyle(QFont::StyleOblique);
- } else if (style == QLatin1String("inherit")) {
- //inherited already
- }
- }
- if (!weight.isEmpty()) {
- bool ok = false;
- int weightNum = weight.toInt(&ok);
- if (ok) {
- switch (weightNum) {
- case 100:
- case 200:
- font.setWeight(QFont::Light);
- break;
- case 300:
- case 400:
- font.setWeight(QFont::Normal);
- break;
- case 500:
- case 600:
- font.setWeight(QFont::DemiBold);
- break;
- case 700:
- case 800:
- font.setWeight(QFont::Bold);
- break;
- case 900:
- font.setWeight(QFont::Black);
- break;
- default:
- break;
- }
- } else {
- if (weight == QLatin1String("normal")) {
- font.setWeight(QFont::Normal);
- } else if (weight == QLatin1String("bold")) {
- font.setWeight(QFont::Bold);
- } else if (weight == QLatin1String("bolder")) {
- font.setWeight(QFont::DemiBold);
- } else if (weight == QLatin1String("lighter")) {
- font.setWeight(QFont::Light);
- }
- }
- }
- // QFontInfo fi(font);
- // font.setPointSize(fi.pointSize());
- return true;
+ QString id = someId(attributes);
+ QSvgTinyDocument *doc = node->document();
+ QSvgFontStyle *fontStyle = 0;
+ if (!family.isEmpty()) {
+ QSvgFont *svgFont = doc->svgFont(family);
+ if (svgFont)
+ fontStyle = new QSvgFontStyle(svgFont, doc);
}
+ if (!fontStyle)
+ fontStyle = new QSvgFontStyle;
- return false;
-}
+ if (!family.isEmpty() && family != QT_INHERIT)
+ fontStyle->setFamily(family.trimmed());
-static void parseFont(QSvgNode *node,
- const QSvgAttributes &attributes,
- QSvgHandler *handler)
-{
- QFont font;
- font.setPixelSize(12);
- qreal fontSize = font.pixelSize();
-
- QSvgFontStyle *inherited =
- static_cast<QSvgFontStyle*>(node->styleProperty(
- QSvgStyleProperty::FONT));
- if (!inherited)
- inherited =
- static_cast<QSvgFontStyle*>(node->parent()->styleProperty(
- QSvgStyleProperty::FONT));
- if (inherited) {
- font = inherited->qfont();
- fontSize = inherited->pointSize();
- }
- // group or any container element can have only text-anchor and should
- // be processed, because its children can inherit from it.
- // So checking for text-anchor before parseQfont()
- QString anchor = attributes.value(QLatin1String("text-anchor")).toString();
- if (parseQFont(attributes, font, fontSize, handler) || (!anchor.isEmpty())) {
- QString myId = someId(attributes);
- //QString anchor = attributes.value(QLatin1String("text-anchor")).toString();
- QSvgTinyDocument *doc = node->document();
- QSvgFontStyle *fontStyle = 0;
- QString family = (font.family().isEmpty())?myId:font.family();
- if (!family.isEmpty()) {
- QSvgFont *svgFont = doc->svgFont(family);
- if (svgFont) {
- fontStyle = new QSvgFontStyle(svgFont, doc);
- fontStyle->setPointSize(fontSize);
- }
+ if (!size.isEmpty() && size != QT_INHERIT) {
+ QSvgHandler::LengthType dummy; // should always be pixel size
+ fontStyle->setSize(parseLength(size, dummy, handler));
+ }
+
+ if (!style.isEmpty() && style != QT_INHERIT) {
+ if (style == QLatin1String("normal")) {
+ fontStyle->setStyle(QFont::StyleNormal);
+ } else if (style == QLatin1String("italic")) {
+ fontStyle->setStyle(QFont::StyleItalic);
+ } else if (style == QLatin1String("oblique")) {
+ fontStyle->setStyle(QFont::StyleOblique);
}
- if (!fontStyle) {
- fontStyle = new QSvgFontStyle(font, node->document());
- fontStyle->setPointSize(fontSize);
+ }
+
+ if (!weight.isEmpty() && weight != QT_INHERIT) {
+ bool ok = false;
+ int weightNum = weight.toInt(&ok);
+ if (ok) {
+ fontStyle->setWeight(weightNum);
+ } else {
+ if (weight == QLatin1String("normal")) {
+ fontStyle->setWeight(400);
+ } else if (weight == QLatin1String("bold")) {
+ fontStyle->setWeight(700);
+ } else if (weight == QLatin1String("bolder")) {
+ fontStyle->setWeight(QSvgFontStyle::BOLDER);
+ } else if (weight == QLatin1String("lighter")) {
+ fontStyle->setWeight(QSvgFontStyle::LIGHTER);
+ }
}
- if (!anchor.isEmpty())
- fontStyle->setTextAnchor(anchor);
+ }
- node->appendStyleProperty(fontStyle, myId);
+ if (!variant.isEmpty() && variant != QT_INHERIT) {
+ if (variant == QLatin1String("normal"))
+ fontStyle->setVariant(QFont::MixedCase);
+ else if (variant == QLatin1String("small-caps"))
+ fontStyle->setVariant(QFont::SmallCaps);
}
+
+ if (!anchor.isEmpty() && anchor != QT_INHERIT) {
+ if (anchor == QLatin1String("start"))
+ fontStyle->setTextAnchor(Qt::AlignLeft);
+ if (anchor == QLatin1String("middle"))
+ fontStyle->setTextAnchor(Qt::AlignHCenter);
+ else if (anchor == QLatin1String("end"))
+ fontStyle->setTextAnchor(Qt::AlignRight);
+ }
+
+ node->appendStyleProperty(fontStyle, id);
}
static void parseTransform(QSvgNode *node,
@@ -1273,7 +1090,7 @@ static void parseVisibility(QSvgNode *node,
QString value = attributes.value(QLatin1String("visibility")).toString();
QSvgNode *parent = node->parent();
- if (parent && (value.isEmpty() || value == QLatin1String("inherit")))
+ if (parent && (value.isEmpty() || value == QT_INHERIT))
node->setVisible(parent->isVisible());
else if (value == QLatin1String("hidden") || value == QLatin1String("collapse")) {
node->setVisible(false);
@@ -1884,105 +1701,6 @@ static void cssStyleLookup(QSvgNode *node,
parseStyle(node, attributes, handler);
}
-static bool parseDefaultTextStyle(QSvgNode *node,
- const QXmlStreamAttributes &attributes,
- bool initial,
- QSvgHandler *handler)
-{
- Q_ASSERT(node->type() == QSvgText::TEXT || node->type() == QSvgNode::TEXTAREA);
- QSvgText *textNode = static_cast<QSvgText*>(node);
-
- QSvgAttributes attrs(attributes, handler);
-
- QString fontFamily = attrs.value(QString(), QLatin1String("font-family")).toString();
-
- QString anchor = attrs.value(QString(), QLatin1String("text-anchor")).toString();
-
- QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
- node->styleProperty(QSvgStyleProperty::FONT));
- if (fontStyle) {
- QSvgTinyDocument *doc = fontStyle->doc();
- if (doc && fontStyle->svgFont()) {
- cssStyleLookup(node, handler, handler->selector());
- parseStyle(node, attrs, handler);
- return true;
- }
- } else if (!fontFamily.isEmpty()) {
- QSvgTinyDocument *doc = node->document();
- QSvgFont *svgFont = doc->svgFont(fontFamily);
- if (svgFont) {
- cssStyleLookup(node, handler, handler->selector());
- parseStyle(node, attrs, handler);
- return true;
- }
- }
-
- QTextCharFormat format;
- QBrush brush(QColor(0, 0, 0));
- QFont font;
- font.setPixelSize(12);
- qreal fontSize = font.pixelSize();
-
- if (!initial) {
- font = textNode->topFormat().font();
- fontSize = font.pixelSize() / textNode->scale();
- brush = textNode->topFormat().foreground();
- } else {
- QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
- node->styleProperty(QSvgStyleProperty::FONT));
- if (!fontStyle)
- fontStyle = static_cast<QSvgFontStyle*>(
- node->parent()->styleProperty(QSvgStyleProperty::FONT));
- if (fontStyle) {
- font = fontStyle->qfont();
- fontSize = fontStyle->pointSize();
- if (anchor.isEmpty() || anchor == QLatin1String("inherit"))
- anchor = fontStyle->textAnchor();
- }
-
- Qt::Alignment align = Qt::AlignLeft;
- if (anchor == QLatin1String("middle"))
- align = Qt::AlignHCenter;
- else if (anchor == QLatin1String("end"))
- align = Qt::AlignRight;
- textNode->setTextAlignment(align);
-
- QSvgFillStyle *fillStyle = static_cast<QSvgFillStyle*>(
- node->styleProperty(QSvgStyleProperty::FILL));
- if (fillStyle)
- brush = fillStyle->qbrush();
- }
-
- if (parseQFont(attrs, font, fontSize, handler) || initial) {
- if (initial)
- textNode->setScale(100 / fontSize);
- font.setPixelSize(qMax(1, int(fontSize * textNode->scale())));
- format.setFont(font);
- }
-
- if (parseQBrush(attrs, node, brush, handler) || initial) {
- if (brush.style() != Qt::NoBrush || initial)
- format.setForeground(brush);
- }
-
- QPen pen(Qt::NoPen);
-// QSvgStrokeStyle *inherited =
-// static_cast<QSvgStrokeStyle*>(node->parent()->styleProperty(
-// QSvgStyleProperty::STROKE));
-// if (inherited)
-// pen = inherited->qpen();
- parseQPen(pen, node, attrs, handler);
- if (pen.style() != Qt::NoPen) {
- format.setTextOutline(pen);
- }
-
- parseTransform(node, attrs, handler);
-
- textNode->insertFormat(format);
-
- return true;
-}
-
static inline QStringList stringToList(const QString &str)
{
QStringList lst = str.split(QLatin1Char(','), QString::SkipEmptyParts);
@@ -2141,7 +1859,7 @@ static inline QSvgNode::DisplayMode displayStringToEnum(const QString &str)
return QSvgNode::TableCaptionMode;
} else if (str == QLatin1String("none")) {
return QSvgNode::NoneMode;
- } else if (str == QLatin1String("inherit")) {
+ } else if (str == QT_INHERIT) {
return QSvgNode::InheritMode;
}
return QSvgNode::BlockMode;
@@ -3105,7 +2823,6 @@ static QSvgNode *createSvgNode(QSvgNode *parent,
node->setHeight(int(height), type == QSvgHandler::LT_PERCENT);
}
-
if (!viewBoxStr.isEmpty()) {
QStringList lst = viewBoxStr.split(QLatin1Char(' '), QString::SkipEmptyParts);
if (lst.count() != 4)
@@ -3155,7 +2872,7 @@ static bool parseTbreakNode(QSvgNode *parent,
{
if (parent->type() != QSvgNode::TEXTAREA)
return false;
- static_cast<QSvgText*>(parent)->insertLineBreak();
+ static_cast<QSvgText*>(parent)->addLineBreak();
return true;
}
@@ -3170,12 +2887,6 @@ static QSvgNode *createTextNode(QSvgNode *parent,
qreal nx = parseLength(x, type, handler);
qreal ny = parseLength(y, type, handler);
- //### not to pixels but to the default coordinate system
- // and text should be already in the correct coordinate
- // system here
- //nx = convertToPixels(nx, true, type);
- //ny = convertToPixels(ny, true, type);
-
QSvgNode *text = new QSvgText(parent, QPointF(nx, ny));
return text;
}
@@ -3194,6 +2905,13 @@ static QSvgNode *createTextAreaNode(QSvgNode *parent,
return node;
}
+static QSvgNode *createTspanNode(QSvgNode *parent,
+ const QXmlStreamAttributes &,
+ QSvgHandler *)
+{
+ return new QSvgTspan(parent);
+}
+
static bool parseTitleNode(QSvgNode *parent,
const QXmlStreamAttributes &attributes,
QSvgHandler *)
@@ -3202,15 +2920,6 @@ static bool parseTitleNode(QSvgNode *parent,
return true;
}
-static bool parseTspanNode(QSvgNode *parent,
- const QXmlStreamAttributes &attributes,
- QSvgHandler *handler)
-{
-
- cssStyleLookup(parent, handler, handler->selector());
- return parseDefaultTextStyle(parent, attributes, false, handler);
-}
-
static QSvgNode *createUseNode(QSvgNode *parent,
const QXmlStreamAttributes &attributes,
QSvgHandler *handler)
@@ -3324,6 +3033,7 @@ static FactoryMethod findGraphicsFactory(const QString &name)
case 't':
if (ref == QLatin1String("ext")) return createTextNode;
if (ref == QLatin1String("extArea")) return createTextAreaNode;
+ if (ref == QLatin1String("span")) return createTspanNode;
break;
case 'u':
if (ref == QLatin1String("se")) return createUseNode;
@@ -3380,7 +3090,6 @@ static ParseMethod findUtilFactory(const QString &name)
case 't':
if (ref == QLatin1String("break")) return parseTbreakNode;
if (ref == QLatin1String("itle")) return parseTitleNode;
- if (ref == QLatin1String("span")) return parseTspanNode;
break;
default:
break;
@@ -3589,16 +3298,33 @@ bool QSvgHandler::startElement(const QString &localName,
group->addChild(node, someId(attributes));
}
break;
+ case QSvgNode::TEXT:
+ case QSvgNode::TEXTAREA:
+ if (node->type() == QSvgNode::TSPAN) {
+ static_cast<QSvgText *>(m_nodes.top())->addTspan(static_cast<QSvgTspan *>(node));
+ } else {
+ qWarning("\'text\' or \'textArea\' element contains invalid element type.");
+ delete node;
+ node = 0;
+ }
+ break;
default:
- Q_ASSERT(!"not a grouping element is the parent");
+ qWarning("Could not add child element to parent element because the types are incorrect.");
+ delete node;
+ node = 0;
+ break;
}
- parseCoreNode(node, attributes);
- cssStyleLookup(node, this, m_selector);
- if (node->type() != QSvgNode::TEXT && node->type() != QSvgNode::TEXTAREA)
+ if (node) {
+ parseCoreNode(node, attributes);
+ cssStyleLookup(node, this, m_selector);
parseStyle(node, attributes, this);
- else
- parseDefaultTextStyle(node, attributes, true, this);
+ if (node->type() == QSvgNode::TEXT || node->type() == QSvgNode::TEXTAREA) {
+ static_cast<QSvgText *>(node)->setWhitespaceMode(m_whitespaceMode.top());
+ } else if (node->type() == QSvgNode::TSPAN) {
+ static_cast<QSvgTspan *>(node)->setWhitespaceMode(m_whitespaceMode.top());
+ }
+ }
}
} else if (ParseMethod method = findUtilFactory(localName)) {
Q_ASSERT(!m_nodes.isEmpty());
@@ -3655,13 +3381,8 @@ bool QSvgHandler::endElement(const QStringRef &localName)
return true;
}
- if (m_inStyle && localName == QLatin1String("style")) {
+ if (m_inStyle && localName == QLatin1String("style"))
m_inStyle = false;
- } else if (m_nodes.top()->type() == QSvgNode::TEXT || m_nodes.top()->type() == QSvgNode::TEXTAREA) {
- QSvgText *node = static_cast<QSvgText*>(m_nodes.top());
- if (localName == QLatin1String("tspan"))
- node->popFormat();
- }
if (node == Graphics) {
// Iterate through the m_renderers to resolve any unresolved gradients.
@@ -3709,8 +3430,9 @@ bool QSvgHandler::characters(const QStringRef &str)
return true;
if (m_nodes.top()->type() == QSvgNode::TEXT || m_nodes.top()->type() == QSvgNode::TEXTAREA) {
- QSvgText *node = static_cast<QSvgText*>(m_nodes.top());
- node->insertText(str.toString(), m_whitespaceMode.top());
+ static_cast<QSvgText*>(m_nodes.top())->addText(str.toString());
+ } else if (m_nodes.top()->type() == QSvgNode::TSPAN) {
+ static_cast<QSvgTspan*>(m_nodes.top())->addText(str.toString());
}
return true;
diff --git a/src/svg/qsvgnode_p.h b/src/svg/qsvgnode_p.h
index f203ea7..315f228 100644
--- a/src/svg/qsvgnode_p.h
+++ b/src/svg/qsvgnode_p.h
@@ -86,6 +86,7 @@ public:
RECT,
TEXT,
TEXTAREA,
+ TSPAN,
USE,
VIDEO
};
diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp
index c3c0a68..6ed3dc2 100644
--- a/src/svg/qsvgstyle.cpp
+++ b/src/svg/qsvgstyle.cpp
@@ -59,6 +59,9 @@ QT_BEGIN_NAMESPACE
QSvgExtraStates::QSvgExtraStates()
: fillOpacity(1.0)
+ , svgFont(0)
+ , textAnchor(Qt::AlignLeft)
+ , fontWeight(400)
{
}
@@ -191,39 +194,94 @@ void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
}
QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc)
- : m_font(font), m_pointSize(24), m_doc(doc)
-{
-}
-
-QSvgFontStyle::QSvgFontStyle(const QFont &font, QSvgTinyDocument *doc)
- : m_font(0), m_pointSize(24), m_doc(doc), m_qfont(font)
-{
-}
-
-
-void QSvgFontStyle::setPointSize(qreal size)
-{
- m_pointSize = size;
-}
-
-qreal QSvgFontStyle::pointSize() const
-{
- return m_pointSize;
-}
-
-void QSvgFontStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
-{
- if (!m_font) {
- m_oldFont = p->font();
- p->setFont(m_qfont);
+ : m_svgFont(font)
+ , m_doc(doc)
+ , m_familySet(0)
+ , m_sizeSet(0)
+ , m_styleSet(0)
+ , m_variantSet(0)
+ , m_weightSet(0)
+ , m_textAnchorSet(0)
+{
+}
+
+QSvgFontStyle::QSvgFontStyle()
+ : m_svgFont(0)
+ , m_doc(0)
+ , m_familySet(0)
+ , m_sizeSet(0)
+ , m_styleSet(0)
+ , m_variantSet(0)
+ , m_weightSet(0)
+ , m_textAnchorSet(0)
+{
+}
+
+int QSvgFontStyle::SVGToQtWeight(int weight) {
+ switch (weight) {
+ case 100:
+ case 200:
+ return QFont::Light;
+ case 300:
+ case 400:
+ return QFont::Normal;
+ case 500:
+ case 600:
+ return QFont::DemiBold;
+ case 700:
+ case 800:
+ return QFont::Bold;
+ case 900:
+ return QFont::Black;
+ }
+ return QFont::Normal;
+}
+
+void QSvgFontStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states)
+{
+ m_oldQFont = p->font();
+ m_oldSvgFont = states.svgFont;
+ m_oldTextAnchor = states.textAnchor;
+ m_oldWeight = states.fontWeight;
+
+ if (m_textAnchorSet)
+ states.textAnchor = m_textAnchor;
+
+ QFont font = m_oldQFont;
+ if (m_familySet) {
+ states.svgFont = m_svgFont;
+ font.setFamily(m_qfont.family());
+ }
+
+ if (m_sizeSet)
+ font.setPointSize(m_qfont.pointSizeF());
+
+ if (m_styleSet)
+ font.setStyle(m_qfont.style());
+
+ if (m_variantSet)
+ font.setCapitalization(m_qfont.capitalization());
+
+ if (m_weightSet) {
+ if (m_weight == BOLDER) {
+ states.fontWeight = qMin(states.fontWeight + 100, 900);
+ } else if (m_weight == LIGHTER) {
+ states.fontWeight = qMax(states.fontWeight - 100, 100);
+ } else {
+ states.fontWeight = m_weight;
+ }
+ font.setWeight(SVGToQtWeight(states.fontWeight));
}
+
+ p->setFont(font);
}
-void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &)
+void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
{
- if (!m_font) {
- p->setFont(m_oldFont);
- }
+ p->setFont(m_oldQFont);
+ states.svgFont = m_oldSvgFont;
+ states.textAnchor = m_oldTextAnchor;
+ states.fontWeight = m_oldWeight;
}
QSvgStrokeStyle::QSvgStrokeStyle(const QPen &pen)
@@ -799,16 +857,6 @@ QSvgStyleProperty::Type QSvgAnimateColor::type() const
return ANIMATE_COLOR;
}
-QString QSvgFontStyle::textAnchor() const
-{
- return m_textAnchor;
-}
-
-void QSvgFontStyle::setTextAnchor(const QString &anchor)
-{
- m_textAnchor = anchor;
-}
-
QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
: m_opacity(opacity)
{
diff --git a/src/svg/qsvgstyle_p.h b/src/svg/qsvgstyle_p.h
index 70ecf5b..bd28bb6 100644
--- a/src/svg/qsvgstyle_p.h
+++ b/src/svg/qsvgstyle_p.h
@@ -141,7 +141,11 @@ private:
struct QSvgExtraStates
{
QSvgExtraStates();
+
qreal fillOpacity;
+ QSvgFont *svgFont;
+ Qt::Alignment textAnchor;
+ int fontWeight;
};
class QSvgStyleProperty : public QSvgRefCounted
@@ -307,41 +311,85 @@ private:
class QSvgFontStyle : public QSvgStyleProperty
{
public:
+ static const int LIGHTER = -1;
+ static const int BOLDER = 1;
+
QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc);
- QSvgFontStyle(const QFont &font, QSvgTinyDocument *doc);
+ QSvgFontStyle();
virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
virtual void revert(QPainter *p, QSvgExtraStates &states);
virtual Type type() const;
- void setPointSize(qreal size);
- qreal pointSize() const;
+ void setSize(qreal size)
+ {
+ // Store the _pixel_ size in the font. Since QFont::setPixelSize() only takes an int, call
+ // QFont::SetPointSize() instead. Set proper font size just before rendering.
+ m_qfont.setPointSize(size);
+ m_sizeSet = 1;
+ }
- //### hack to avoid having a separate style element for text-anchor
- QString textAnchor() const;
- void setTextAnchor(const QString &anchor);
+ void setTextAnchor(Qt::Alignment anchor)
+ {
+ m_textAnchor = anchor;
+ m_textAnchorSet = 1;
+ }
- QSvgFont * svgFont() const
+ void setFamily(const QString &family)
{
- return m_font;
+ m_qfont.setFamily(family);
+ m_familySet = 1;
+ }
+
+ void setStyle(QFont::Style fontStyle) {
+ m_qfont.setStyle(fontStyle);
+ m_styleSet = 1;
}
- QSvgTinyDocument *doc() const
+
+ void setVariant(QFont::Capitalization fontVariant)
{
- return m_doc;
+ m_qfont.setCapitalization(fontVariant);
+ m_variantSet = 1;
}
- const QFont & qfont() const
+ static int SVGToQtWeight(int weight);
+
+ void setWeight(int weight)
+ {
+ m_weight = weight;
+ m_weightSet = 1;
+ }
+
+ QSvgFont * svgFont() const
+ {
+ return m_svgFont;
+ }
+
+ const QFont &qfont() const
{
return m_qfont;
}
+
+ QSvgTinyDocument *doc() const {return m_doc;}
+
private:
- QSvgFont *m_font;
- qreal m_pointSize;
+ QSvgFont *m_svgFont;
QSvgTinyDocument *m_doc;
+ QFont m_qfont;
- QString m_textAnchor;
+ int m_weight;
+ Qt::Alignment m_textAnchor;
- QFont m_qfont;
- QFont m_oldFont;
+ QSvgFont *m_oldSvgFont;
+ QFont m_oldQFont;
+ Qt::Alignment m_oldTextAnchor;
+ int m_oldWeight;
+
+ unsigned m_familySet : 1;
+ unsigned m_sizeSet : 1;
+ unsigned m_styleSet : 1;
+ unsigned m_variantSet : 1;
+ unsigned m_weightSet : 1;
+ unsigned m_textAnchorSet : 1;
};
class QSvgStrokeStyle : public QSvgStyleProperty