Commit 6f51599f authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement KoShape::updateAbsolute() for complex transformation updates

Historically, transformation code uses extremely weird method of shape
updates that rely on the event loop. This patch implements a framework
for moving away from this strategy.

The problem:

When one transforms a shape he needs to update both areas: bounding
rect of the shape *before* the transform and a bounding rect of the shape
*after* the transform. Before the patch, the transformation code used the
system like that:

shape->update();
shape->setTransformation(newTransform);
shape->update();

That works only with assumption that the first update() call will *not*
be executed before setTransform() call. That should be true atm, but it
is not guaranteed to be so in the future. Therefore, now the update happens
like that:

const QRectF oldDirtyRect = shape->boundingRect();
shape->setTransformation(newTransform);
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
parent cb6516b8
...@@ -189,28 +189,6 @@ void KoShapePrivate::shapeChanged(KoShape::ChangeType type) ...@@ -189,28 +189,6 @@ void KoShapePrivate::shapeChanged(KoShape::ChangeType type)
} }
} }
void KoShapePrivate::updateStroke()
{
Q_Q(KoShape);
if (!stroke) return;
KoInsets insets;
stroke->strokeInsets(q, insets);
QSizeF inner = q->size();
// update left
q->update(QRectF(-insets.left, -insets.top, insets.left,
inner.height() + insets.top + insets.bottom));
// update top
q->update(QRectF(-insets.left, -insets.top,
inner.width() + insets.left + insets.right, insets.top));
// update right
q->update(QRectF(inner.width(), -insets.top, insets.right,
inner.height() + insets.top + insets.bottom));
// update bottom
q->update(QRectF(-insets.left, inner.height(),
inner.width() + insets.left + insets.right, insets.bottom));
}
void KoShapePrivate::addShapeManager(KoShapeManager *manager) void KoShapePrivate::addShapeManager(KoShapeManager *manager)
{ {
shapeManagers.insert(manager); shapeManagers.insert(manager);
...@@ -705,7 +683,7 @@ void KoShape::update() const ...@@ -705,7 +683,7 @@ void KoShape::update() const
} }
} }
void KoShape::update(const QRectF &rect) const void KoShape::updateAbsolute(const QRectF &rect) const
{ {
if (rect.isEmpty() && !rect.isNull()) { if (rect.isEmpty() && !rect.isNull()) {
...@@ -715,9 +693,8 @@ void KoShape::update(const QRectF &rect) const ...@@ -715,9 +693,8 @@ void KoShape::update(const QRectF &rect) const
Q_D(const KoShape); Q_D(const KoShape);
if (!d->shapeManagers.empty() && isVisible()) { if (!d->shapeManagers.empty() && isVisible()) {
QRectF rc(absoluteTransformation(0).mapRect(rect));
Q_FOREACH (KoShapeManager * manager, d->shapeManagers) { Q_FOREACH (KoShapeManager * manager, d->shapeManagers) {
manager->update(rc); manager->update(rect);
} }
} }
} }
...@@ -1248,12 +1225,7 @@ void KoShape::setStroke(KoShapeStrokeModelSP stroke) ...@@ -1248,12 +1225,7 @@ void KoShape::setStroke(KoShapeStrokeModelSP stroke)
{ {
Q_D(KoShape); Q_D(KoShape);
// TODO: check if it really updates stuff
d->updateStroke();
d->stroke = stroke; d->stroke = stroke;
d->updateStroke();
d->shapeChanged(StrokeChanged); d->shapeChanged(StrokeChanged);
notifyChanged(); notifyChanged();
} }
......
...@@ -703,13 +703,13 @@ public: ...@@ -703,13 +703,13 @@ public:
/** /**
* Request a repaint to be queued. * Request a repaint to be queued.
* The repaint will be restricted to the parameters rectangle, which is expected to be * The repaint will be restricted to the parameters rectangle, which is expected to be
* in points (the internal coordinates system of KoShape) and it is expected to be * in absolute coordinates of the canvas and it is expected to be
* normalized. * normalized.
* <p>This method will return immediately and only request a repaint. Successive calls * <p>This method will return immediately and only request a repaint. Successive calls
* will be merged into an appropriate repaint action. * will be merged into an appropriate repaint action.
* @param rect the rectangle (in pt) to queue for repaint. * @param rect the rectangle (in pt) to queue for repaint.
*/ */
virtual void update(const QRectF &rect) const; virtual void updateAbsolute(const QRectF &rect) const;
/// Used by compareShapeZIndex() to order shapes /// Used by compareShapeZIndex() to order shapes
enum ChildZOrderPolicy { enum ChildZOrderPolicy {
......
...@@ -547,7 +547,7 @@ QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenSha ...@@ -547,7 +547,7 @@ QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenSha
return shapes; return shapes;
} }
void KoShapeManager::update(QRectF &rect, const KoShape *shape, bool selectionHandles) void KoShapeManager::update(const QRectF &rect, const KoShape *shape, bool selectionHandles)
{ {
d->canvas->updateCanvas(rect); d->canvas->updateCanvas(rect);
if (selectionHandles && d->selection->isSelected(shape)) { if (selectionHandles && d->selection->isSelected(shape)) {
......
...@@ -147,7 +147,7 @@ public: ...@@ -147,7 +147,7 @@ public:
* @param selectionHandles if true; find out if the shape is selected and repaint its * @param selectionHandles if true; find out if the shape is selected and repaint its
* selection handles at the same time. * selection handles at the same time.
*/ */
void update(QRectF &rect, const KoShape *shape = 0, bool selectionHandles = false); void update(const QRectF &rect, const KoShape *shape = 0, bool selectionHandles = false);
/** /**
* Update the tree for finding the shapes. * Update the tree for finding the shapes.
......
...@@ -61,9 +61,6 @@ public: ...@@ -61,9 +61,6 @@ public:
// Loads the border style. // Loads the border style.
KoBorder *loadOdfBorder(KoShapeLoadingContext &context) const; KoBorder *loadOdfBorder(KoShapeLoadingContext &context) const;
/// calls update on the shape where the stroke is.
void updateStroke();
public: public:
// Members // Members
......
...@@ -67,10 +67,13 @@ KoShapeMoveCommand::~KoShapeMoveCommand() ...@@ -67,10 +67,13 @@ KoShapeMoveCommand::~KoShapeMoveCommand()
void KoShapeMoveCommand::redo() void KoShapeMoveCommand::redo()
{ {
KUndo2Command::redo(); KUndo2Command::redo();
for (int i = 0; i < d->shapes.count(); i++) { for (int i = 0; i < d->shapes.count(); i++) {
d->shapes.at(i)->update(); KoShape *shape = d->shapes.at(i);
d->shapes.at(i)->setAbsolutePosition(d->newPositions.at(i), d->anchor);
d->shapes.at(i)->update(); const QRectF oldDirtyRect = shape->boundingRect();
shape->setAbsolutePosition(d->newPositions.at(i), d->anchor);
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
} }
} }
...@@ -78,9 +81,11 @@ void KoShapeMoveCommand::undo() ...@@ -78,9 +81,11 @@ void KoShapeMoveCommand::undo()
{ {
KUndo2Command::undo(); KUndo2Command::undo();
for (int i = 0; i < d->shapes.count(); i++) { for (int i = 0; i < d->shapes.count(); i++) {
d->shapes.at(i)->update(); KoShape *shape = d->shapes.at(i);
d->shapes.at(i)->setAbsolutePosition(d->previousPositions.at(i), d->anchor);
d->shapes.at(i)->update(); const QRectF oldDirtyRect = shape->boundingRect();
shape->setAbsolutePosition(d->previousPositions.at(i), d->anchor);
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
} }
} }
......
...@@ -68,7 +68,7 @@ KoShapeResizeCommand::~KoShapeResizeCommand() ...@@ -68,7 +68,7 @@ KoShapeResizeCommand::~KoShapeResizeCommand()
void KoShapeResizeCommand::redoImpl() void KoShapeResizeCommand::redoImpl()
{ {
Q_FOREACH (KoShape *shape, m_d->shapes) { Q_FOREACH (KoShape *shape, m_d->shapes) {
shape->update(); const QRectF oldDirtyRect = shape->boundingRect();
KoFlake::resizeShape(shape, KoFlake::resizeShape(shape,
m_d->scaleX, m_d->scaleY, m_d->scaleX, m_d->scaleY,
...@@ -77,7 +77,7 @@ void KoShapeResizeCommand::redoImpl() ...@@ -77,7 +77,7 @@ void KoShapeResizeCommand::redoImpl()
m_d->usePostScaling, m_d->usePostScaling,
m_d->postScalingCoveringTransform); m_d->postScalingCoveringTransform);
shape->update(); shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
} }
} }
...@@ -86,10 +86,10 @@ void KoShapeResizeCommand::undoImpl() ...@@ -86,10 +86,10 @@ void KoShapeResizeCommand::undoImpl()
for (int i = 0; i < m_d->shapes.size(); i++) { for (int i = 0; i < m_d->shapes.size(); i++) {
KoShape *shape = m_d->shapes[i]; KoShape *shape = m_d->shapes[i];
shape->update(); const QRectF oldDirtyRect = shape->boundingRect();
shape->setSize(m_d->oldSizes[i]); shape->setSize(m_d->oldSizes[i]);
shape->setTransformation(m_d->oldTransforms[i]); shape->setTransformation(m_d->oldTransforms[i]);
shape->update(); shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
} }
} }
......
...@@ -59,9 +59,9 @@ void KoShapeTransformCommand::redo() ...@@ -59,9 +59,9 @@ void KoShapeTransformCommand::redo()
const int shapeCount = d->shapes.count(); const int shapeCount = d->shapes.count();
for (int i = 0; i < shapeCount; ++i) { for (int i = 0; i < shapeCount; ++i) {
KoShape * shape = d->shapes[i]; KoShape * shape = d->shapes[i];
shape->update(); const QRectF oldDirtyRect = shape->boundingRect();
shape->setTransformation(d->newState[i]); shape->setTransformation(d->newState[i]);
shape->update(); shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
} }
} }
...@@ -72,9 +72,9 @@ void KoShapeTransformCommand::undo() ...@@ -72,9 +72,9 @@ void KoShapeTransformCommand::undo()
const int shapeCount = d->shapes.count(); const int shapeCount = d->shapes.count();
for (int i = 0; i < shapeCount; ++i) { for (int i = 0; i < shapeCount; ++i) {
KoShape * shape = d->shapes[i]; KoShape * shape = d->shapes[i];
shape->update(); const QRectF oldDirtyRect = shape->boundingRect();
shape->setTransformation(d->oldState[i]); shape->setTransformation(d->oldState[i]);
shape->update(); shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
} }
} }
......
...@@ -60,7 +60,7 @@ void SimpleRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool i ...@@ -60,7 +60,7 @@ void SimpleRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool i
{ {
Q_UNUSED(isNewRootArea); Q_UNUSED(isNewRootArea);
m_textShape->update(m_textShape->outlineRect()); m_textShape->update();
QSizeF newSize = m_textShape->size() QSizeF newSize = m_textShape->size()
- QSizeF(m_textShapeData->leftPadding() + m_textShapeData->rightPadding(), - QSizeF(m_textShapeData->leftPadding() + m_textShapeData->rightPadding(),
...@@ -136,7 +136,7 @@ void SimpleRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool i ...@@ -136,7 +136,7 @@ void SimpleRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool i
m_textShape->setSize(newSize); m_textShape->setSize(newSize);
} }
m_textShape->update(m_textShape->outlineRect()); m_textShape->update();
} }
void SimpleRootAreaProvider::updateAll() void SimpleRootAreaProvider::updateAll()
......
...@@ -397,12 +397,15 @@ void TextShape::update() const ...@@ -397,12 +397,15 @@ void TextShape::update() const
KoShapeContainer::update(); KoShapeContainer::update();
} }
void TextShape::update(const QRectF &shape) const void TextShape::updateAbsolute(const QRectF &shape) const
{ {
// this is done to avoid updates which are called during the paint event and not needed. // this is done to avoid updates which are called during the paint event and not needed.
if (!m_paintRegion.contains(shape.toRect())) { //if (!m_paintRegion.contains(shape.toRect())) {
KoShape::update(shape); //KoShape::update(shape);
} //}
// FIXME: just a hack to remove outdated call from the deprecated shape
KoShape::updateAbsolute(shape);
} }
void TextShape::waitUntilReady(const KoViewConverter &, bool asynchronous) const void TextShape::waitUntilReady(const KoViewConverter &, bool asynchronous) const
......
...@@ -109,7 +109,7 @@ public: ...@@ -109,7 +109,7 @@ public:
void updateDocumentData(); void updateDocumentData();
void update() const override; void update() const override;
void update(const QRectF &shape) const override; void updateAbsolute(const QRectF &shape) const override;
// required for kpresenter hack // required for kpresenter hack
void setPageProvider(KoPageProvider *provider) void setPageProvider(KoPageProvider *provider)
......
...@@ -57,7 +57,7 @@ void AddConnectionPointCommand::undo() ...@@ -57,7 +57,7 @@ void AddConnectionPointCommand::undo()
void AddConnectionPointCommand::updateRoi() void AddConnectionPointCommand::updateRoi()
{ {
// TODO: is there a way we can get at the correct update size? // TODO: is there a way we can get at the correct update size?
QRectF roi(0, 0, 10, 10); //QRectF roi(0, 0, 10, 10);
roi.moveCenter(m_connectionPoint); //roi.moveCenter(m_connectionPoint);
m_shape->update(roi); //m_shape->update(roi);
} }
...@@ -56,7 +56,7 @@ void ChangeConnectionPointCommand::undo() ...@@ -56,7 +56,7 @@ void ChangeConnectionPointCommand::undo()
void ChangeConnectionPointCommand::updateRoi(const QPointF &position) void ChangeConnectionPointCommand::updateRoi(const QPointF &position)
{ {
// TODO: is there a way we can get at the correct update size? // TODO: is there a way we can get at the correct update size?
QRectF roi(0, 0, 10, 10); //QRectF roi(0, 0, 10, 10);
roi.moveCenter(position); //roi.moveCenter(position);
m_shape->update(roi); //m_shape->update(roi);
} }
...@@ -55,7 +55,7 @@ void RemoveConnectionPointCommand::undo() ...@@ -55,7 +55,7 @@ void RemoveConnectionPointCommand::undo()
void RemoveConnectionPointCommand::updateRoi() void RemoveConnectionPointCommand::updateRoi()
{ {
// TODO: is there a way we can get at the correct update size? // TODO: is there a way we can get at the correct update size?
QRectF roi(0, 0, 10, 10); //QRectF roi(0, 0, 10, 10);
roi.moveCenter(m_connectionPoint.position); //roi.moveCenter(m_connectionPoint.position);
m_shape->update(roi); //m_shape->update(roi);
} }
...@@ -98,9 +98,10 @@ void ShapeMoveStrategy::moveSelection(const QPointF &diff) ...@@ -98,9 +98,10 @@ void ShapeMoveStrategy::moveSelection(const QPointF &diff)
tool()->canvas()->clipToDocument(shape, delta); tool()->canvas()->clipToDocument(shape, delta);
QPointF newPos(shape->absolutePosition(KoFlake::Center) + delta); QPointF newPos(shape->absolutePosition(KoFlake::Center) + delta);
m_newPositions[i] = newPos; m_newPositions[i] = newPos;
shape->update();
const QRectF oldDirtyRect = shape->boundingRect();
shape->setAbsolutePosition(newPos, KoFlake::Center); shape->setAbsolutePosition(newPos, KoFlake::Center);
shape->update(); shape->updateAbsolute(oldDirtyRect | oldDirtyRect.translated(delta));
i++; i++;
} }
} }
......
...@@ -81,9 +81,9 @@ void ShapeRotateStrategy::rotateBy(qreal angle) ...@@ -81,9 +81,9 @@ void ShapeRotateStrategy::rotateBy(qreal angle)
QTransform applyMatrix = matrix * m_rotationMatrix.inverted(); QTransform applyMatrix = matrix * m_rotationMatrix.inverted();
m_rotationMatrix = matrix; m_rotationMatrix = matrix;
Q_FOREACH (KoShape *shape, m_selectedShapes) { Q_FOREACH (KoShape *shape, m_selectedShapes) {
shape->update(); const QRectF oldDirtyRect = shape->boundingRect();
shape->applyAbsoluteTransformation(applyMatrix); shape->applyAbsoluteTransformation(applyMatrix);
shape->update(); shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
} }
} }
......
...@@ -146,9 +146,9 @@ void ShapeShearStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModif ...@@ -146,9 +146,9 @@ void ShapeShearStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModif
QTransform applyMatrix = matrix * m_shearMatrix.inverted(); QTransform applyMatrix = matrix * m_shearMatrix.inverted();
Q_FOREACH (KoShape *shape, m_selectedShapes) { Q_FOREACH (KoShape *shape, m_selectedShapes) {
shape->update(); const QRectF oldDirtyRect = shape->boundingRect();
shape->applyAbsoluteTransformation(applyMatrix); shape->applyAbsoluteTransformation(applyMatrix);
shape->update(); shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
} }
m_shearMatrix = matrix; m_shearMatrix = matrix;
} }
......
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