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)
}
}
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)
{
shapeManagers.insert(manager);
......@@ -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()) {
......@@ -715,9 +693,8 @@ void KoShape::update(const QRectF &rect) const
Q_D(const KoShape);
if (!d->shapeManagers.empty() && isVisible()) {
QRectF rc(absoluteTransformation(0).mapRect(rect));
Q_FOREACH (KoShapeManager * manager, d->shapeManagers) {
manager->update(rc);
manager->update(rect);
}
}
}
......@@ -1248,12 +1225,7 @@ void KoShape::setStroke(KoShapeStrokeModelSP stroke)
{
Q_D(KoShape);
// TODO: check if it really updates stuff
d->updateStroke();
d->stroke = stroke;
d->updateStroke();
d->shapeChanged(StrokeChanged);
notifyChanged();
}
......
......@@ -703,13 +703,13 @@ public:
/**
* Request a repaint to be queued.
* 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.
* <p>This method will return immediately and only request a repaint. Successive calls
* will be merged into an appropriate repaint action.
* @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
enum ChildZOrderPolicy {
......
......@@ -547,7 +547,7 @@ QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenSha
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);
if (selectionHandles && d->selection->isSelected(shape)) {
......
......@@ -147,7 +147,7 @@ public:
* @param selectionHandles if true; find out if the shape is selected and repaint its
* 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.
......
......@@ -61,9 +61,6 @@ public:
// Loads the border style.
KoBorder *loadOdfBorder(KoShapeLoadingContext &context) const;
/// calls update on the shape where the stroke is.
void updateStroke();
public:
// Members
......
......@@ -67,10 +67,13 @@ KoShapeMoveCommand::~KoShapeMoveCommand()
void KoShapeMoveCommand::redo()
{
KUndo2Command::redo();
for (int i = 0; i < d->shapes.count(); i++) {
d->shapes.at(i)->update();
d->shapes.at(i)->setAbsolutePosition(d->newPositions.at(i), d->anchor);
d->shapes.at(i)->update();
KoShape *shape = d->shapes.at(i);
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()
{
KUndo2Command::undo();
for (int i = 0; i < d->shapes.count(); i++) {
d->shapes.at(i)->update();
d->shapes.at(i)->setAbsolutePosition(d->previousPositions.at(i), d->anchor);
d->shapes.at(i)->update();
KoShape *shape = d->shapes.at(i);
const QRectF oldDirtyRect = shape->boundingRect();
shape->setAbsolutePosition(d->previousPositions.at(i), d->anchor);
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
}
......
......@@ -68,7 +68,7 @@ KoShapeResizeCommand::~KoShapeResizeCommand()
void KoShapeResizeCommand::redoImpl()
{
Q_FOREACH (KoShape *shape, m_d->shapes) {
shape->update();
const QRectF oldDirtyRect = shape->boundingRect();
KoFlake::resizeShape(shape,
m_d->scaleX, m_d->scaleY,
......@@ -77,7 +77,7 @@ void KoShapeResizeCommand::redoImpl()
m_d->usePostScaling,
m_d->postScalingCoveringTransform);
shape->update();
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
}
......@@ -86,10 +86,10 @@ void KoShapeResizeCommand::undoImpl()
for (int i = 0; i < m_d->shapes.size(); i++) {
KoShape *shape = m_d->shapes[i];
shape->update();
const QRectF oldDirtyRect = shape->boundingRect();
shape->setSize(m_d->oldSizes[i]);
shape->setTransformation(m_d->oldTransforms[i]);
shape->update();
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
}
......
......@@ -59,9 +59,9 @@ void KoShapeTransformCommand::redo()
const int shapeCount = d->shapes.count();
for (int i = 0; i < shapeCount; ++i) {
KoShape * shape = d->shapes[i];
shape->update();
const QRectF oldDirtyRect = shape->boundingRect();
shape->setTransformation(d->newState[i]);
shape->update();
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
}
......@@ -72,9 +72,9 @@ void KoShapeTransformCommand::undo()
const int shapeCount = d->shapes.count();
for (int i = 0; i < shapeCount; ++i) {
KoShape * shape = d->shapes[i];
shape->update();
const QRectF oldDirtyRect = shape->boundingRect();
shape->setTransformation(d->oldState[i]);
shape->update();
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
}
......
......@@ -60,7 +60,7 @@ void SimpleRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool i
{
Q_UNUSED(isNewRootArea);
m_textShape->update(m_textShape->outlineRect());
m_textShape->update();
QSizeF newSize = m_textShape->size()
- QSizeF(m_textShapeData->leftPadding() + m_textShapeData->rightPadding(),
......@@ -136,7 +136,7 @@ void SimpleRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool i
m_textShape->setSize(newSize);
}
m_textShape->update(m_textShape->outlineRect());
m_textShape->update();
}
void SimpleRootAreaProvider::updateAll()
......
......@@ -397,12 +397,15 @@ void TextShape::update() const
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.
if (!m_paintRegion.contains(shape.toRect())) {
KoShape::update(shape);
}
//if (!m_paintRegion.contains(shape.toRect())) {
//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
......
......@@ -109,7 +109,7 @@ public:
void updateDocumentData();
void update() const override;
void update(const QRectF &shape) const override;
void updateAbsolute(const QRectF &shape) const override;
// required for kpresenter hack
void setPageProvider(KoPageProvider *provider)
......
......@@ -57,7 +57,7 @@ void AddConnectionPointCommand::undo()
void AddConnectionPointCommand::updateRoi()
{
// TODO: is there a way we can get at the correct update size?
QRectF roi(0, 0, 10, 10);
roi.moveCenter(m_connectionPoint);
m_shape->update(roi);
//QRectF roi(0, 0, 10, 10);
//roi.moveCenter(m_connectionPoint);
//m_shape->update(roi);
}
......@@ -56,7 +56,7 @@ void ChangeConnectionPointCommand::undo()
void ChangeConnectionPointCommand::updateRoi(const QPointF &position)
{
// TODO: is there a way we can get at the correct update size?
QRectF roi(0, 0, 10, 10);
roi.moveCenter(position);
m_shape->update(roi);
//QRectF roi(0, 0, 10, 10);
//roi.moveCenter(position);
//m_shape->update(roi);
}
......@@ -55,7 +55,7 @@ void RemoveConnectionPointCommand::undo()
void RemoveConnectionPointCommand::updateRoi()
{
// TODO: is there a way we can get at the correct update size?
QRectF roi(0, 0, 10, 10);
roi.moveCenter(m_connectionPoint.position);
m_shape->update(roi);
//QRectF roi(0, 0, 10, 10);
//roi.moveCenter(m_connectionPoint.position);
//m_shape->update(roi);
}
......@@ -98,9 +98,10 @@ void ShapeMoveStrategy::moveSelection(const QPointF &diff)
tool()->canvas()->clipToDocument(shape, delta);
QPointF newPos(shape->absolutePosition(KoFlake::Center) + delta);
m_newPositions[i] = newPos;
shape->update();
const QRectF oldDirtyRect = shape->boundingRect();
shape->setAbsolutePosition(newPos, KoFlake::Center);
shape->update();
shape->updateAbsolute(oldDirtyRect | oldDirtyRect.translated(delta));
i++;
}
}
......
......@@ -81,9 +81,9 @@ void ShapeRotateStrategy::rotateBy(qreal angle)
QTransform applyMatrix = matrix * m_rotationMatrix.inverted();
m_rotationMatrix = matrix;
Q_FOREACH (KoShape *shape, m_selectedShapes) {
shape->update();
const QRectF oldDirtyRect = shape->boundingRect();
shape->applyAbsoluteTransformation(applyMatrix);
shape->update();
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
}
......
......@@ -146,9 +146,9 @@ void ShapeShearStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModif
QTransform applyMatrix = matrix * m_shearMatrix.inverted();
Q_FOREACH (KoShape *shape, m_selectedShapes) {
shape->update();
const QRectF oldDirtyRect = shape->boundingRect();
shape->applyAbsoluteTransformation(applyMatrix);
shape->update();
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
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