Plasma

svgitem.cpp
1 /*
2  SPDX-FileCopyrightText: 2010 Marco Martin <[email protected]>
3  SPDX-FileCopyrightText: 2014 David Edmundson <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "svgitem.h"
9 
10 #include <QQuickWindow>
11 #include <QSGTexture>
12 #include <QRectF>
13 #include <QDebug>
14 
15 #include "plasma/svg.h"
16 
17 #include <QuickAddons/ManagedTextureNode>
18 
19 #include <cmath> //floor()
20 
21 namespace Plasma
22 {
23 
24 SvgItem::SvgItem(QQuickItem *parent)
25  : QQuickItem(parent),
26  m_textureChanged(false)
27 {
28  setFlag(QQuickItem::ItemHasContents, true);
29  connect(&Units::instance(), &Units::devicePixelRatioChanged, this, &SvgItem::updateDevicePixelRatio);
30 }
31 
32 SvgItem::~SvgItem()
33 {
34 }
35 
36 void SvgItem::setElementId(const QString &elementID)
37 {
38  if (elementID == m_elementID) {
39  return;
40  }
41 
42  if (implicitWidth() <= 0) {
43  setImplicitWidth(naturalSize().width());
44  }
45  if (implicitHeight() <= 0) {
46  setImplicitHeight(naturalSize().height());
47  }
48 
49  m_elementID = elementID;
50  emit elementIdChanged();
51  emit naturalSizeChanged();
52 
53  scheduleImageUpdate();
54 }
55 
57 {
58  return m_elementID;
59 }
60 
62 {
63  if (!m_svg) {
64  return QSizeF();
65  } else if (!m_elementID.isEmpty()) {
66  return m_svg.data()->elementSize(m_elementID);
67  }
68 
69  return m_svg.data()->size();
70 }
71 
72 void SvgItem::setSvg(Plasma::Svg *svg)
73 {
74  if (m_svg) {
75  disconnect(m_svg.data(), nullptr, this, nullptr);
76  }
77  m_svg = svg;
78  updateDevicePixelRatio();
79 
80  if (svg) {
81  connect(svg, &Svg::repaintNeeded, this, &SvgItem::updateNeeded);
82  connect(svg, &Svg::repaintNeeded, this, &SvgItem::naturalSizeChanged);
83  connect(svg, &Svg::sizeChanged, this, &SvgItem::naturalSizeChanged);
84  }
85 
86  if (implicitWidth() <= 0) {
87  setImplicitWidth(naturalSize().width());
88  }
89  if (implicitHeight() <= 0) {
90  setImplicitHeight(naturalSize().height());
91  }
92 
93  scheduleImageUpdate();
94 
95  emit svgChanged();
96  emit naturalSizeChanged();
97 }
98 
100 {
101  return m_svg.data();
102 }
103 
104 QSGNode *SvgItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
105 {
106  Q_UNUSED(updatePaintNodeData);
107  if (!window() || !m_svg) {
108  delete oldNode;
109  return nullptr;
110  }
111 
112  //this is more than just an optimization, uploading a null image to QSGAtlasTexture causes a crash
113  if (width() == 0.0 || height() == 0.0) {
114  delete oldNode;
115  return nullptr;
116  }
117 
118  ManagedTextureNode *textureNode = static_cast<ManagedTextureNode *>(oldNode);
119  if (!textureNode) {
120  textureNode = new ManagedTextureNode;
121  m_textureChanged = true;
122  }
123 
124  //TODO use a heuristic to work out when to redraw
125  //if !m_smooth and size is approximate simply change the textureNode.rect without
126  //updating the material
127 
128  if (m_textureChanged || textureNode->texture()->textureSize() != QSize(width(), height())) {
129  //despite having a valid size sometimes we still get a null QImage from Plasma::Svg
130  //loading a null texture to an atlas fatals
131  //Dave E fixed this in Qt in 5.3.something onwards but we need this for now
132  if (m_image.isNull()) {
133  delete textureNode;
134  return nullptr;
135  }
136 
137  QSharedPointer<QSGTexture> texture(window()->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas));
138  textureNode->setTexture(texture);
139  m_textureChanged = false;
140 
141  textureNode->setRect(0, 0, width(), height());
142  }
143 
144  textureNode->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
145 
146  return textureNode;
147 }
148 
149 void SvgItem::updateNeeded()
150 {
151  if (implicitWidth() <= 0) {
152  setImplicitWidth(naturalSize().width());
153  }
154  if (implicitHeight() <= 0) {
155  setImplicitHeight(naturalSize().height());
156  }
157  scheduleImageUpdate();
158 }
159 
160 void SvgItem::updateDevicePixelRatio()
161 {
162  if (m_svg) {
163  //devicepixelratio is always set integer in the svg, so needs at least 192dpi to double up.
164  //(it needs to be integer to have lines contained inside a svg piece to keep being pixel aligned)
165  if (window()) {
166  m_svg.data()->setDevicePixelRatio(qMax<qreal>(1.0, floor(window()->devicePixelRatio())));
167  } else {
168  m_svg.data()->setDevicePixelRatio(qMax<qreal>(1.0, floor(qApp->devicePixelRatio())));
169  }
170  m_svg.data()->setScaleFactor(qMax<qreal>(1.0, floor(Units::instance().devicePixelRatio())));
171  }
172 }
173 
174 void SvgItem::scheduleImageUpdate()
175 {
176  polish();
177  update();
178 }
179 
180 void SvgItem::updatePolish()
181 {
183 
184  if (m_svg) {
185  //setContainsMultipleImages has to be done there since m_frameSvg can be shared with somebody else
186  m_textureChanged = true;
187  m_svg.data()->setContainsMultipleImages(!m_elementID.isEmpty());
188  m_image = m_svg.data()->image(QSize(width(), height()), m_elementID);
189  }
190 }
191 
192 void SvgItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
193 {
194  if (newGeometry.size() != oldGeometry.size() && newGeometry.isValid()) {
195  scheduleImageUpdate();
196  }
197 
198  QQuickItem::geometryChanged(newGeometry, oldGeometry);
199 }
200 
201 } // Plasma namespace
202 
Plasma::Svg svg
Svg class that is the source of the image, use it like that:
Definition: svgitem.h:43
void repaintNeeded()
Emitted whenever the SVG data has changed in such a way that a repaint is required.
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
void setRect(const QRectF &r)
void setFiltering(QSGTexture::Filtering filtering)
QSizeF size() const const
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
QSizeF naturalSize
The natural, unscaled size of the svg document or the element.
Definition: svgitem.h:48
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual QSize textureSize() const const =0
Namespace for everything in libplasma.
Definition: datamodel.cpp:14
void sizeChanged()
Emitted whenever the size of the Svg is changed.
QString elementId
The sub element of the svg we want to render.
Definition: svgitem.h:31
virtual void updatePolish()
virtual QSGNode * updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData)
bool isValid() const const
QSGTexture * texture() const const
qreal devicePixelRatio()
Definition: svg.cpp:718
void update(Part *part, const QByteArray &data, qint64 dataSize)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
A theme aware image-centric SVG class.
Definition: svg.h:43
void setTexture(QSGTexture *texture)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Aug 13 2020 22:41:20 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.