Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 4f591124 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Fix a crash while accessing shape's RTTI info during its destruction

Thanks TestSvgParser unittest for pointing out this problem. In real
life it happened randomly without any easy way to reproduce.
parent a545a24b
......@@ -75,6 +75,12 @@ public:
*/
virtual void insert(const QRectF& bb, const T& data);
/**
* @brief Show if a shape is a part of the tree
* @param data
*/
bool contains(const T &data);
/**
* @brief Remove a data item from the tree
*
......@@ -435,6 +441,13 @@ void KoRTree<T>::insert(Node * node)
}
}
template <typename T>
bool KoRTree<T>::contains(const T &data)
{
return m_leafMap[data];
}
template <typename T>
void KoRTree<T>::remove(const T&data)
{
......
......@@ -157,11 +157,14 @@ KoShapePrivate::KoShapePrivate(const KoShapePrivate &rhs, KoShape *q)
KoShapePrivate::~KoShapePrivate()
{
Q_Q(KoShape);
if (parent)
if (parent) {
parent->removeShape(q);
}
Q_FOREACH (KoShapeManager *manager, shapeManagers) {
manager->remove(q);
manager->shapeInterface()->notifyShapeDestructed(q);
}
shapeManagers.clear();
if (shadow && !shadow->deref())
delete shadow;
......
......@@ -138,7 +138,6 @@ KoShapeManager::~KoShapeManager()
delete d;
}
void KoShapeManager::setShapes(const QList<KoShape *> &shapes, Repaint repaint)
{
//clear selection
......@@ -149,6 +148,7 @@ void KoShapeManager::setShapes(const QList<KoShape *> &shapes, Repaint repaint)
d->aggregate4update.clear();
d->tree.clear();
d->shapes.clear();
Q_FOREACH (KoShape *shape, shapes) {
addShape(shape, repaint);
}
......@@ -160,10 +160,12 @@ void KoShapeManager::addShape(KoShape *shape, Repaint repaint)
return;
shape->priv()->addShapeManager(this);
d->shapes.append(shape);
if (d->shapeUsedInRenderingTree(shape)) {
QRectF br(shape->boundingRect());
d->tree.insert(br, shape);
}
if (repaint == PaintShapeOnAdd) {
shape->update();
}
......@@ -192,6 +194,7 @@ void KoShapeManager::remove(KoShape *shape)
shape->priv()->removeShapeManager(this);
d->selection->deselect(shape);
d->aggregate4update.remove(shape);
if (d->shapeUsedInRenderingTree(shape)) {
d->tree.remove(shape);
}
......@@ -204,12 +207,34 @@ void KoShapeManager::remove(KoShape *shape)
remove(containerShape);
}
}
}
KoShapeManager::ShapeInterface::ShapeInterface(KoShapeManager *_q)
: q(_q)
{
}
void KoShapeManager::ShapeInterface::notifyShapeDestructed(KoShape *shape)
{
q->d->selection->deselect(shape);
q->d->aggregate4update.remove(shape);
// we cannot access RTTI of the semi-destructed shape, so just
// unlink it lazily
if (q->d->tree.contains(shape)) {
q->d->tree.remove(shape);
}
// This signal is used in the annotation shape.
// FIXME: Is this really what we want? (and shouldn't it be called shapeDeleted()?)
shapeRemoved(shape);
q->d->shapes.removeAll(shape);
}
KoShapeManager::ShapeInterface *KoShapeManager::shapeInterface()
{
return &d->shapeInterface;
}
void KoShapeManager::paint(QPainter &painter, const KoViewConverter &converter, bool forPrint)
{
d->updateTree();
......
......@@ -173,6 +173,26 @@ public:
*/
static void renderSingleShape(KoShape *shape, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext);
/**
* A special interface for KoShape to use during shape destruction. Don't use this
* interface directly unless you are KoShape.
*/
struct ShapeInterface {
ShapeInterface(KoShapeManager *_q);
/**
* Called by a shape when it is destructed. Please note that you cannot access
* any shape's method type or information during this call because the shape might be
* semi-destroyed.
*/
void notifyShapeDestructed(KoShape *shape);
protected:
KoShapeManager *q;
};
ShapeInterface* shapeInterface();
Q_SIGNALS:
/// emitted when the selection is changed
void selectionChanged();
......@@ -180,8 +200,6 @@ Q_SIGNALS:
void selectionContentChanged();
/// emitted when any object changed (moved/rotated etc)
void contentChanged();
/// emitted when a shape is removed.
void shapeRemoved(KoShape *);
/// emitted when any shape changed.
void shapeChanged(KoShape *);
......
......@@ -26,9 +26,9 @@
#include "KoShape.h"
#include "KoShape_p.h"
#include "KoShapeContainer.h"
#include "KoShapeManager.h"
#include <KoRTree.h>
class KoShapeManager;
class KoCanvasBase;
class KoShapeGroup;
class KoShapePaintingContext;
......@@ -41,7 +41,8 @@ public:
: selection(new KoSelection()),
canvas(c),
tree(4, 2),
q(shapeManager)
q(shapeManager),
shapeInterface(shapeManager)
{
}
......@@ -108,6 +109,7 @@ public:
QSet<KoShape *> aggregate4update;
QHash<KoShape*, int> shapeIndexesBeforeUpdate;
KoShapeManager *q;
KoShapeManager::ShapeInterface shapeInterface;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment