Commit 18cf0192 authored by Boudewijn Rempt's avatar Boudewijn Rempt

Fix canvas updating when painting with low opacity

Thanks to Silvio who discovered the bug with commit
6b20da503241ef4a68b5d01884d974ad30a1033d. This commit fixes those
issues by implementing the QRegion->QVector<QRect> change in a
less intrusive way.
parent 204bffc4
......@@ -98,6 +98,7 @@ void KisFloodFillBenchmark::benchmarkFlood()
// fill twice
fillPainter.fillColor(1, 1, 0);
fillPainter.deleteTransaction();
}
......
......@@ -40,10 +40,10 @@
void KisGradientBenchmark::initTestCase()
{
m_colorSpace = KoColorSpaceRegistry::instance()->rgb8();
m_colorSpace = KoColorSpaceRegistry::instance()->rgb8();
m_device = new KisPaintDevice(m_colorSpace);
m_color = KoColor(m_colorSpace);
m_color.fromQColor(QColor(0,0,0,0)); // default pixel
m_device->fill( 0,0,GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT,m_color.data() );
}
......@@ -54,7 +54,7 @@ void KisGradientBenchmark::benchmarkGradient()
KoColor bg(m_colorSpace);
fg.fromQColor(Qt::blue);
bg.fromQColor(Qt::black);
QBENCHMARK
{
QLinearGradient grad;
......@@ -73,12 +73,12 @@ void KisGradientBenchmark::benchmarkGradient()
fillPainter.setOpacity(OPACITY_OPAQUE_U8);
// default
fillPainter.setCompositeOp(COMPOSITE_OVER);
fillPainter.paintGradient(QPointF(0,0), QPointF(3000,3000), KisGradientPainter::GradientShapeBiLinear, KisGradientPainter::GradientRepeatNone, true, false, 0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT);
fillPainter.deleteTransaction();
}
// uncomment this to see the output
QImage out = m_device->convertToQImage(m_colorSpace->profile(),0,0,GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT);
out.save("fill_output.png");
......
......@@ -109,7 +109,7 @@ bool KisIndirectPaintingSupport::hasTemporaryTarget() const
return d->temporaryTarget;
}
void KisIndirectPaintingSupport::mergeToLayer(KisLayerSP layer, const QVector<QRect> &region, const QString &transactionText)
void KisIndirectPaintingSupport::mergeToLayer(KisLayerSP layer, const QRegion &region, const QString &transactionText)
{
/**
* We do not apply selection here, because it has already
......@@ -125,7 +125,7 @@ void KisIndirectPaintingSupport::mergeToLayer(KisLayerSP layer, const QVector<QR
gc.beginTransaction(transactionText);
}
foreach(const QRect &rc, region) {
foreach(const QRect& rc, region.rects()) {
gc.bitBlt(rc.topLeft(), d->temporaryTarget, rc);
}
d->temporaryTarget = 0;
......
......@@ -52,7 +52,7 @@ public:
* Writes the temporary target into the paint device of the layer.
* This action will lock the temporary target itself.
*/
void mergeToLayer(KisLayerSP layer, const QVector<QRect> &region,
void mergeToLayer(KisLayerSP layer, const QRegion &region,
const QString &transactionText);
/**
......@@ -65,7 +65,7 @@ public:
/**
* Unlock the temporary target
*
*
* \see lockTemporaryTarget()
*/
void unlockTemporaryTarget() const;
......
......@@ -22,6 +22,7 @@
#include <QMutex>
#include <QMutexLocker>
#include <QPainterPath>
#include <QRect>
#include <ksharedconfig.h>
#include <kconfiggroup.h>
......@@ -321,11 +322,18 @@ void KisNode::setDirty()
setDirty(extent());
}
void KisNode::setDirty(const QVector<QRect> &region)
void KisNode::setDirty(const QVector<QRect> &rects)
{
foreach(const QRect &rc, rects) {
setDirty(rc);
}
}
void KisNode::setDirty(const QRegion & region)
{
if (region.isEmpty()) return;
foreach(const QRect &rc, region) {
foreach(const QRect &rc, region.rects()) {
setDirty(rc);
}
}
......
......@@ -22,7 +22,11 @@
#include "kis_base_node.h"
#include "krita_export.h"
#include <QVector>
class QRect;
class QStringList;
class KoProperties;
class KisNodeVisitor;
......@@ -105,12 +109,19 @@ public:
Q_UNUSED(rect);
}
/**
* Add the given rects to the set of dirty rects for this node;
* this percolates up to parent nodes all the way to the root
* node.
*/
virtual void setDirty(const QVector<QRect> &rects);
/**
* Add the given region to the set of dirty rects for this node;
* this percolates up to parent nodes all the way to the root
* node, if propagate is true;
*/
virtual void setDirty(const QVector<QRect> & region);
virtual void setDirty(const QRegion & region);
/**
* Some filters will cause a change of pixels those are outside
......
......@@ -304,14 +304,11 @@ void KisPaintDevice::setDirty(const QRect & rc)
m_d->parent->setDirty(rc);
}
void KisPaintDevice::setDirty(const QVector<QRect> &rects)
void KisPaintDevice::setDirty(const QRegion & region)
{
m_d->cache.invalidate();
if (m_d->parent.isValid()) {
foreach(const QRect &rc, rects) {
m_d->parent->setDirty(rc);
}
}
if (m_d->parent.isValid())
m_d->parent->setDirty(region);
}
void KisPaintDevice::setDirty()
......@@ -321,6 +318,13 @@ void KisPaintDevice::setDirty()
m_d->parent->setDirty();
}
void KisPaintDevice::setDirty(const QVector<QRect> rects)
{
m_d->cache.invalidate();
if (m_d->parent.isValid())
m_d->parent->setDirty(rects);
}
void KisPaintDevice::setParentNode(KisNodeWSP parent)
{
m_d->parent = parent;
......
......@@ -21,6 +21,7 @@
#include <QObject>
#include <QRect>
#include <QVector>
#include "kis_debug.h"
......@@ -545,10 +546,10 @@ public:
virtual void setDirty(const QRect & rc);
/**
* Add the specified rects to the parent layer's set of dirty rects
* (if there's a parent layer)
* Add the specified region to the parent layer's dirty region
* (if there is a parent layer)
*/
virtual void setDirty(const QVector<QRect> &rc);
virtual void setDirty(const QRegion & region);
/**
* Set the parent layer completely dirty, if this paint device has
......@@ -556,6 +557,8 @@ public:
*/
virtual void setDirty();
virtual void setDirty(const QVector<QRect> rects);
public:
/**
......
......@@ -658,8 +658,7 @@ public:
void setCompositeOp(const QString& op);
/**
* Add the r to the current dirty rect, and return the vector
* of dirty rects after adding r to it.
* Add the r to the current dirty rect.
*/
void addDirtyRect(const QRect & r);
......
......@@ -24,7 +24,7 @@
#include <QMouseEvent>
#include <QPaintEvent>
#include <QRectF>
#include <QVector>
#include <QRegion>
#include <QResizeEvent>
#include <QTabletEvent>
#include <kundo2command.h>
......@@ -185,9 +185,11 @@ void MixerCanvas::paintEvent(QPaintEvent *event)
void MixerCanvas::updateCanvas(const QVector<QRect>& region)
{
m_dirty = true;
QRect bounds;
foreach(const QRect &rc, region) {
update(rc);
bounds |= rc;
}
update(bounds);
}
void MixerCanvas::slotClear()
......
......@@ -22,7 +22,6 @@
#define MIXERCANVAS_H_
#include <QFrame>
#include <QVector>
#include <KoCanvasBase.h>
#include <kis_types.h>
......@@ -31,8 +30,8 @@ class QPoint;
class QImage;
class QMouseEvent;
class QPaintEvent;
class QRect;
class QRectF;
class QRegion;
class QResizeEvent;
class QTabletEvent;
class KUndo2Command;
......
......@@ -238,9 +238,9 @@ void MixerTool::mouseReleaseEvent(KoPointerEvent *event)
m_d->mixer->resourceManager()->setResource(KoCanvasResource::ForegroundColor, event->pos());
}
void MixerTool::setDirty(const QVector<QRect>& region)
void MixerTool::setDirty(const QRegion& region)
{
m_d->mixer->updateCanvas(region);
m_d->mixer->updateCanvas(region.rects());
}
......
......@@ -23,11 +23,9 @@
#include <KoToolBase.h>
#include <QVector>
#include <QRect>
class KoPointerEvent;
class MixerCanvas;
class QRegion;
class KisPaintInformation;
class MixerTool : public KoToolBase
......@@ -49,7 +47,7 @@ public:
public:
void setDirty(const QVector<QRect> &region);
void setDirty(const QRegion &region);
// KoToolBase Implementation.
......
......@@ -77,9 +77,7 @@ void KisToolBrush::timeoutPaint()
Q_ASSERT(currentPaintOpPreset()->settings()->isAirbrushing());
if (currentImage() && m_painter) {
paintAt(m_previousPaintInformation);
QVector<QRect> r = m_painter->takeDirtyRegion();
dbgPlugins << "Timeout paint dirty region:" << r;
currentNode()->setDirty(r);
currentNode()->setDirty(m_painter->takeDirtyRegion());
}
}
......
......@@ -70,8 +70,7 @@ void KisToolEllipse::finishEllipse(const QRectF& rect)
painter.paintEllipse(rect);
painter.endTransaction(image()->undoAdapter());
QVector<QRect> bound = painter.takeDirtyRegion();
device->setDirty(bound);
device->setDirty(painter.takeDirtyRegion());
notifyModified();
} else {
QRectF r = convertToPt(rect);
......
......@@ -126,16 +126,11 @@ bool KisToolFill::flood(int startX, int startY)
m_painter->beginTransaction(i18n("Fill"));
QVector<QRect>::iterator it = dirty.begin();
QVector<QRect>::iterator end = dirty.end();
m_painter->setCompositeOp(m_compositeOp);
m_painter->setOpacity(m_opacity);
while (it != end) {
QRect rc = *it;
foreach(const QRect &rc, dirty) {
m_painter->bitBlt(rc.topLeft(), filled, rc);
++it;
}
m_painter->endTransaction(image()->undoAdapter());
......
......@@ -225,10 +225,9 @@ void KisToolLine::mouseReleaseEvent(KoPointerEvent *event)
setupPainter(m_painter);
m_painter->paintLine(m_startPos, m_endPos);
QVector<QRect> dirtyRegion = m_painter->takeDirtyRegion();
m_painter->endTransaction(image()->undoAdapter());
device->setDirty(dirtyRegion);
device->setDirty(m_painter->takeDirtyRegion());
notifyModified();
delete m_painter;
......
......@@ -132,11 +132,13 @@ void KisToolMultihand::timeoutPaint()
if (currentImage() && !m_painters.isEmpty()) {
for (int i = 0; i < m_painters.size(); i++){
KisPainter * painter = m_painters.at(i);
KisPaintInformation pi1 = m_previousPaintInformation;
pi1.setPos( m_brushTransforms.at(i).map(pi1.pos()) );
paintAt(pi1, m_painters[i]);
currentNode()->setDirty(m_painters[i]->takeDirtyRegion());
}
}
}
......@@ -600,7 +602,7 @@ void KisToolMultihand::endPaint()
indirect->mergeToLayer(layer, m_incrementalDirtyRegion, m_transactionText);
m_incrementalDirtyRegion.clear();
m_incrementalDirtyRegion = QRegion();
} else {
m_transaction->commit(image()->undoAdapter());
}
......@@ -677,7 +679,17 @@ bool KisToolMultihand::wantsAutoScroll() const
return false;
}
void KisToolMultihand::setDirty(const QVector<QRect>& region)
void KisToolMultihand::setDirty(const QVector<QRect> &rects)
{
currentNode()->setDirty(rects);
if (!m_paintIncremental) {
foreach (const QRect &rc, rects) {
m_incrementalDirtyRegion += rc;
}
}
}
void KisToolMultihand::setDirty(const QRegion& region)
{
if (region.isEmpty())
return;
......
......@@ -60,7 +60,8 @@ public:
KisToolMultihand(KoCanvasBase * canvas, const QCursor & cursor, const QString & transactionText);
virtual ~KisToolMultihand();
virtual int flags() const;
virtual void setDirty(const QVector<QRect>& region);
virtual void setDirty(const QVector<QRect> &rects);
virtual void setDirty(const QRegion &region);
protected:
void gesture(const QPointF &offsetInDocPixels,
......@@ -197,7 +198,7 @@ private:
qint32 m_rate;
bool m_isAirbrushing;
QVector<QRect> m_incrementalDirtyRegion;
QRegion m_incrementalDirtyRegion;
QList<FreehandPaintJob*> m_paintJobs;
KisRecordedPathPaintAction* m_pathPaintAction;
QThreadPool* m_executor;
......
......@@ -441,7 +441,7 @@ void KisToolFreehand::endPaint()
indirect->mergeToLayer(layer, m_incrementalDirtyRegion, m_transactionText);
m_incrementalDirtyRegion.clear();
m_incrementalDirtyRegion = QRegion();
} else {
m_painter->endTransaction(image()->undoAdapter());
}
......@@ -511,7 +511,18 @@ bool KisToolFreehand::wantsAutoScroll() const
return false;
}
void KisToolFreehand::setDirty(const QVector<QRect>& region)
void KisToolFreehand::setDirty(const QVector<QRect> &rects)
{
currentNode()->setDirty(rects);
if (!m_paintIncremental) {
foreach(const QRect &rc, rects) {
m_incrementalDirtyRegion += rc;
}
}
}
void KisToolFreehand::setDirty(const QRegion& region)
{
if (region.isEmpty())
return;
......
......@@ -53,7 +53,8 @@ public:
KisToolFreehand(KoCanvasBase * canvas, const QCursor & cursor, const QString & transactionText);
virtual ~KisToolFreehand();
virtual int flags() const;
virtual void setDirty(const QVector<QRect>& region);
virtual void setDirty(const QVector<QRect> &rects);
virtual void setDirty(const QRegion &region);
protected:
void gesture(const QPointF &offsetInDocPixels,
......@@ -143,7 +144,7 @@ private:
bool m_explicitShowOutline;
QVector<QRect> m_incrementalDirtyRegion;
QRegion m_incrementalDirtyRegion;
QList<FreehandPaintJob*> m_paintJobs;
KisRecordedPathPaintAction* m_pathPaintAction;
QThreadPool* m_executor;
......
......@@ -407,9 +407,14 @@ void KisScratchPad::initPainting(QEvent* event) {
}
m_distanceInformation.spacing = m_painter->paintAt(m_previousPaintInformation);
m_distanceInformation.distance = 0.0;
QRect bounds;
foreach(const QRect &rc, m_painter->takeDirtyRegion()) {
update(pos.x() - rc.width(), pos.y() - rc.height(), rc.width() * 2, rc.height() *2);
bounds |= rc;
}
update(pos.x() - bounds.width(), pos.y() - bounds.height(), bounds.width() * 2, bounds.height() *2);
}
void KisScratchPad::paint(QEvent* event) {
......@@ -440,14 +445,14 @@ void KisScratchPad::paint(QEvent* event) {
m_distanceInformation = m_painter->paintLine(m_previousPaintInformation, info, m_distanceInformation);
m_previousPaintInformation = info;
QVector<QRect> rects = m_painter->takeDirtyRegion();
m_incrementalDirtyRegion += rects;
foreach(const QRect &rc, rects) {
m_paintLayer->updateProjection(rc);
update(pos.x() - rc.width(), pos.y() - rc.height(), rc.width() * 2, rc.height() *2);
QRect bounds;
foreach(const QRect &rc, m_painter->takeDirtyRegion()) {
bounds |= rc;
m_incrementalDirtyRegion += rc;
}
m_paintLayer->updateProjection(bounds);
update(pos.x() - bounds.width(), pos.y() - bounds.height(), bounds.width() * 2, bounds.height() *2);
}
void KisScratchPad::endPaint(QEvent *event) {
......@@ -470,17 +475,21 @@ void KisScratchPad::endPaint(QEvent *event) {
Q_ASSERT(indirect);
indirect->mergeToLayer(layer, m_incrementalDirtyRegion, QString("scratchpaint"));
m_incrementalDirtyRegion.clear();
m_incrementalDirtyRegion = QRegion();
} else {
KisDumbUndoAdapter dua;
m_painter->endTransaction(&dua);
}
}
QRect bounds;
foreach(const QRect &rc, m_painter->takeDirtyRegion()) {
update(rc.translated(m_currentMousePosition));
bounds |= rc;
}
update(bounds.translated(m_currentMousePosition));
delete m_painter;
m_painter = 0;
}
......
......@@ -107,7 +107,7 @@ public slots:
/// fill the visible area of the paint device with a solid color
void fillSolid(const KoColor& color);
/// fill the cutoutOverlay rect with the cotent of an image, used to get the image back when selecting a preset
void setPresetImage(const QImage& image);
......@@ -180,7 +180,7 @@ private:
QBrush m_checkBrush;
bool m_paintIncremental;
quint8 m_opacity;
QVector<QRect> m_incrementalDirtyRegion;
QRegion m_incrementalDirtyRegion;
KisCanvasResourceProvider* m_resourceProvider;
};
......
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