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 cd18cbf6 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement wrap-around mode for KisPaintDevice

This patch effectively does the following:

1) Refactors the KisPaintDevice so that the behavior of most of
   the methods is switchable with a strategy. There are two strategies
   available: KisPaintDeviceStrategy and KisPaintDeviceWrappedStrategy.

2) The choice of Wrapped/Unwrapped mode is defined by the KisDefaultBounds
   object, which is accessible from all the paint devices of the image.

3) Implements wrapped versions of hline, vline, rect and random accessor
   iterators. Construction of different iterators is done by means of
   switching strategies.

4) The basic maths of the wrapping is done by a special object named
   KisWrappedRect.
parent da37fd26
......@@ -48,7 +48,7 @@ void KisBContrastBenchmark::initTestCase()
int r,g,b;
KisRectIteratorSP it = m_device->createRectIteratorNG(0, 0, GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT);
KisRectIteratorSP it = m_device->createRectIteratorNG(QRect(0, 0, GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT));
do {
r = rand() % 255;
g = rand() % 255;
......
......@@ -49,7 +49,7 @@ void KisBlurBenchmark::initTestCase()
int r,g,b;
KisRectIteratorSP it = m_device->createRectIteratorNG(0,0,GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT);
KisRectIteratorSP it = m_device->createRectIteratorNG(QRect(0,0,GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT));
do {
r = rand() % 255;
g = rand() % 255;
......
......@@ -184,6 +184,7 @@ set(kritaimage_LIB_SRCS
kis_random_accessor_ng.cpp
kis_random_generator.cc
kis_random_sub_accessor.cpp
kis_wrapped_random_accessor.cpp
kis_selection.cc
kis_selection_mask.cpp
kis_update_outline_job.cpp
......
......@@ -254,8 +254,9 @@ public:
*/
inline void readBytes(quint8 * data,
qint32 x, qint32 y,
qint32 w, qint32 h) const {
ACTUAL_DATAMGR::readBytes(data, x, y, w, h);
qint32 w, qint32 h,
qint32 dataRowStride = -1) const {
ACTUAL_DATAMGR::readBytes(data, x, y, w, h, dataRowStride);
}
/**
......@@ -264,8 +265,9 @@ public:
*/
inline void writeBytes(const quint8 * data,
qint32 x, qint32 y,
qint32 w, qint32 h) {
ACTUAL_DATAMGR::writeBytes(data, x, y, w, h);
qint32 w, qint32 h,
qint32 dataRowStride = -1) {
ACTUAL_DATAMGR::writeBytes(data, x, y, w, h, dataRowStride);
}
......
......@@ -55,6 +55,10 @@ QRect KisDefaultBounds::bounds() const
return m_d->image ? m_d->image->bounds() : infiniteRect;
}
bool KisDefaultBounds::wrapAroundMode() const
{
return false;
}
/******************************************************************/
/* KisSelectionDefaultBounds */
......
......@@ -35,7 +35,8 @@ public:
KisDefaultBounds(KisImageWSP image = 0);
virtual ~KisDefaultBounds();
virtual QRect bounds() const;
QRect bounds() const;
bool wrapAroundMode() const;
protected:
static const QRect infiniteRect;
......
......@@ -33,6 +33,7 @@ public:
virtual ~KisDefaultBoundsBase();
virtual QRect bounds() const = 0;
virtual bool wrapAroundMode() const = 0;
};
......
......@@ -82,7 +82,7 @@ void KisHistogram::updateHistogram()
return;
}
KisRectConstIteratorSP srcIt = m_paintDevice->createRectConstIteratorNG(m_bounds.left(), m_bounds.top(), m_bounds.width(), m_bounds.height());
KisRectConstIteratorSP srcIt = m_paintDevice->createRectConstIteratorNG(m_bounds);
const KoColorSpace* cs = m_paintDevice->colorSpace();
// Let the producer do it's work
......
This diff is collapsed.
......@@ -356,7 +356,7 @@ public:
* @param data The address of the memory to receive the bytes read
* @param rect The rectangle in the paint device to read from
*/
void readBytes(quint8 * data, const QRect &rect);
void readBytes(quint8 * data, const QRect &rect) const;
/**
* Copy the bytes in data into the rect specified by x, y, w, h. If the
......@@ -658,21 +658,15 @@ public:
public:
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w);
KisHLineConstIteratorSP createHLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const;
KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 h);
KisVLineConstIteratorSP createVLineConstIteratorNG(qint32 x, qint32 y, qint32 h) const;
KisRectIteratorSP createRectIteratorNG(qint32 x, qint32 y, qint32 w, qint32 h);
KisRectIteratorSP createRectIteratorNG(const QRect& r);
KisRectConstIteratorSP createRectConstIteratorNG(qint32 x, qint32 y, qint32 w, qint32 h) const;
KisRectConstIteratorSP createRectConstIteratorNG(const QRect& r) const;
KisRectIteratorSP createRectIteratorNG(const QRect &rc);
KisRectConstIteratorSP createRectConstIteratorNG(const QRect &rc) const;
KisRandomAccessorSP createRandomAccessorNG(qint32 x, qint32 y);
KisRandomConstAccessorSP createRandomConstAccessorNG(qint32 x, qint32 y) const;
/**
......@@ -741,7 +735,6 @@ protected:
private:
struct Private;
Private * const m_d;
};
#endif // KIS_PAINT_DEVICE_IMPL_H_
This diff is collapsed.
......@@ -237,7 +237,7 @@ void KisPixelSelection::invert()
QRect rc = region().boundingRect();
if (!rc.isEmpty()) {
KisRectIteratorSP it = createRectIteratorNG(rc.x(), rc.y(), rc.width(), rc.height());
KisRectIteratorSP it = createRectIteratorNG(rc);
do {
*(it->rawData()) = MAX_SELECTED - *(it->rawData());
} while (it->nextPixel());
......
/*
* Copyright (c) 2013 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_WRAPPED_HLINE_ITERATOR_H
#define __KIS_WRAPPED_HLINE_ITERATOR_H
#include "kis_iterator_ng.h"
#include "kis_wrapped_rect.h"
class WrappedHLineIteratorStrategy
{
public:
typedef KisHLineIteratorSP IteratorTypeSP;
WrappedHLineIteratorStrategy()
: m_iteratorRowStart(KisWrappedRect::TOPLEFT),
m_lastRowCoord(-1)
{
}
inline IteratorTypeSP createIterator(KisDataManager *dataManager,
const QRect &rc,
qint32 offsetX, qint32 offsetY,
bool writable) {
return new KisHLineIterator2(dataManager,
rc.x(), rc.y(),
rc.width(),
offsetX, offsetY,
writable);
}
inline void completeInitialization(QVector<IteratorTypeSP> *iterators,
KisWrappedRect *splitRect) {
m_splitRect = splitRect;
m_iterators = iterators;
m_lastRowCoord = m_splitRect->topLeft().bottom();
}
inline IteratorTypeSP leftColumnIterator() const {
return m_iterators->at(m_iteratorRowStart + KisWrappedRect::TOPLEFT);
}
inline IteratorTypeSP rightColumnIterator() const {
return m_iterators->at(m_iteratorRowStart + KisWrappedRect::TOPRIGHT);
}
inline bool trySwitchIteratorStripe() {
bool needSwitching = leftColumnIterator()->y() == m_lastRowCoord;
if (needSwitching) {
if (m_iteratorRowStart != KisWrappedRect::BOTTOMLEFT &&
m_iterators->at(KisWrappedRect::BOTTOMLEFT)) {
m_iteratorRowStart = KisWrappedRect::BOTTOMLEFT;
m_lastRowCoord = m_splitRect->bottomLeft().bottom();
}
}
return needSwitching;
}
inline void iteratorsToNextRow() {
leftColumnIterator()->nextRow();
if (rightColumnIterator()) {
rightColumnIterator()->nextRow();
}
}
inline bool trySwitchColumnForced() {
return false;
}
private:
KisWrappedRect *m_splitRect;
QVector<IteratorTypeSP> *m_iterators;
int m_iteratorRowStart; // may be either KisWrappedRect::TOPLEFT or KisWrappedRect::BOTTOMLEFT
int m_lastRowCoord;
};
#include "kis_wrapped_line_iterator_base.h"
typedef KisWrappedLineIteratorBase<WrappedHLineIteratorStrategy, KisHLineIteratorNG> KisWrappedHLineIterator;
#endif /* __KIS_WRAPPED_HLINE_ITERATOR_H */
/*
* Copyright (c) 2013 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_WRAPPED_LINE_ITERATOR_BASE_H
#define __KIS_WRAPPED_LINE_ITERATOR_BASE_H
template <class IteratorStrategy, class BaseClass>
class KisWrappedLineIteratorBase : public BaseClass
{
public:
KisWrappedLineIteratorBase(KisDataManager *dataManager,
const KisWrappedRect &splitRect,
qint32 offsetX, qint32 offsetY,
bool writable)
: m_splitRect(splitRect)
{
Q_ASSERT(m_splitRect.isSplit());
m_iterators.resize(4);
for (int i = 0; i < 4; i++) {
QRect rc = m_splitRect[i];
if (rc.isEmpty()) continue;
m_iterators[i] = m_strategy.createIterator(dataManager,
rc,
offsetX, offsetY,
writable);
}
m_strategy.completeInitialization(&m_iterators, &m_splitRect);
m_currentIterator = m_strategy.leftColumnIterator();
}
bool nextPixel() {
int result = m_currentIterator->nextPixel();
if (!result) {
result = trySwitchColumn();
}
return result;
}
bool nextPixels(qint32 n) {
int result = m_currentIterator->nextPixels(n);
if (!result) {
result = trySwitchColumn();
}
return result;
}
void nextRow() {
if (!m_strategy.trySwitchIteratorStripe()) {
m_strategy.iteratorsToNextRow();
}
m_currentIterator = m_strategy.leftColumnIterator();
}
void nextColumn() {
nextRow();
}
const quint8* oldRawData() const {
return m_currentIterator->oldRawData();
}
const quint8* rawDataConst() const {
return m_currentIterator->rawDataConst();
}
quint8* rawData() {
return m_currentIterator->rawData();
}
qint32 nConseqPixels() const {
return m_currentIterator->nConseqPixels();
}
qint32 x() const {
return m_currentIterator->x();
}
qint32 y() const {
return m_currentIterator->y();
}
private:
bool trySwitchColumn() {
int result =
m_currentIterator == m_strategy.leftColumnIterator() &&
m_strategy.rightColumnIterator();
if (result) {
m_currentIterator = m_strategy.rightColumnIterator();
} else {
result = m_strategy.trySwitchColumnForced();
if (result) {
m_currentIterator = m_strategy.leftColumnIterator();
}
}
return result;
}
private:
KisWrappedRect m_splitRect;
QVector<typename IteratorStrategy::IteratorTypeSP> m_iterators;
typename IteratorStrategy::IteratorTypeSP m_currentIterator;
IteratorStrategy m_strategy;
};
#endif /* __KIS_WRAPPED_LINE_ITERATOR_BASE_H */
/*
* Copyright (c) 2013 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_wrapped_random_accessor.h"
#include "kis_wrapped_rect.h"
KisWrappedRandomAccessor::KisWrappedRandomAccessor(KisTiledDataManager *ktm,
qint32 x, qint32 y,
qint32 offsetX, qint32 offsetY,
bool writable,
const QRect &wrapRect)
: KisRandomAccessor2(ktm, x, y, offsetX, offsetY, writable),
m_wrapRect(wrapRect)
{
}
void KisWrappedRandomAccessor::moveTo(qint32 x, qint32 y)
{
x = KisWrappedRect::xToWrappedX(x, m_wrapRect);
y = KisWrappedRect::yToWrappedY(y, m_wrapRect);
KisRandomAccessor2::moveTo(x, y);
}
qint32 KisWrappedRandomAccessor::numContiguousColumns(qint32 x) const
{
x = KisWrappedRect::xToWrappedX(x, m_wrapRect);
return KisRandomAccessor2::numContiguousColumns(x);
}
qint32 KisWrappedRandomAccessor::numContiguousRows(qint32 y) const
{
y = KisWrappedRect::yToWrappedY(y, m_wrapRect);
return KisRandomAccessor2::numContiguousRows(y);
}
qint32 KisWrappedRandomAccessor::rowStride(qint32 x, qint32 y) const
{
x = KisWrappedRect::xToWrappedX(x, m_wrapRect);
y = KisWrappedRect::yToWrappedY(y, m_wrapRect);
return KisRandomAccessor2::rowStride(x, y);
}
/*
* Copyright (c) 2013 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_WRAPPED_RANDOM_ACCESSOR_H
#define __KIS_WRAPPED_RANDOM_ACCESSOR_H
#include "tiles3/kis_random_accessor.h"
class KisWrappedRandomAccessor : public KisRandomAccessor2
{
public:
KisWrappedRandomAccessor(KisTiledDataManager *ktm,
qint32 x, qint32 y,
qint32 offsetX, qint32 offsetY,
bool writable,
const QRect &wrapRect);
void moveTo(qint32 x, qint32 y);
qint32 numContiguousColumns(qint32 x) const;
qint32 numContiguousRows(qint32 y) const;
qint32 rowStride(qint32 x, qint32 y) const;
private:
QRect m_wrapRect;
};
#endif /* __KIS_WRAPPED_RANDOM_ACCESSOR_H */
/*
* Copyright (c) 2013 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_WRAPPED_RECT_H
#define __KIS_WRAPPED_RECT_H
#include <QVector>
#include <QRect>
struct KisWrappedRect : public QVector<QRect> {
static inline int xToWrappedX(int x, const QRect &wrapRect) {
x = (x - wrapRect.x()) % wrapRect.width();
if (x < 0) x += wrapRect.width();
return x;
}
static inline int yToWrappedY(int y, const QRect &wrapRect) {
y = (y - wrapRect.y()) % wrapRect.height();
if (y < 0) y += wrapRect.height();
return y;
}
enum {
TOPLEFT = 0,
TOPRIGHT,
BOTTOMLEFT,
BOTTOMRIGHT
};
KisWrappedRect(const QRect &rc, const QRect &wrapRect) {
if (wrapRect.contains(rc)) {
append(rc);
} else {
int x = xToWrappedX(rc.x(), wrapRect);
int y = yToWrappedY(rc.y(), wrapRect);
int w = qMin(rc.width(), wrapRect.width());
int h = qMin(rc.height(), wrapRect.height());
// we ensure that the topleft of the rect belongs to the
// visible rectangle
Q_ASSERT(x >= 0 && x < wrapRect.width());
Q_ASSERT(y >= 0 && y < wrapRect.height());
QRect newRect(x, y, w, h);
append(newRect & wrapRect); // tl
append(newRect.translated(-wrapRect.width(), 0) & wrapRect); // tr
append(newRect.translated(0, -wrapRect.height()) & wrapRect); // bl
append(newRect.translated(-wrapRect.width(), -wrapRect.height()) & wrapRect); // br
}
}
bool isSplit() const {
int size = this->size();
// we can either split or not split only
Q_ASSERT(size == 1 || size == 4);
return size > 1;
}
QRect topLeft() const {
return this->at(TOPLEFT);
}
QRect topRight() const {
return this->at(TOPRIGHT);
}
QRect bottomLeft() const {
return this->at(BOTTOMLEFT);
}
QRect bottomRight() const {
return this->at(BOTTOMRIGHT);
}
};
#endif /* __KIS_WRAPPED_RECT_H */
/*
* Copyright (c) 2013 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_WRAPPED_RECT_ITERATOR_H
#define __KIS_WRAPPED_RECT_ITERATOR_H
#include "kis_iterator_ng.h"
#include "kis_wrapped_rect.h"
class WrappedRectIteratorStrategy
{
public:
typedef KisRectIteratorSP IteratorTypeSP;
WrappedRectIteratorStrategy()
: m_iteratorRowStart(KisWrappedRect::TOPLEFT)
{
}
inline IteratorTypeSP createIterator(KisDataManager *dataManager,
const QRect &rc,
qint32 offsetX, qint32 offsetY,
bool writable) {
return new KisRectIterator2(dataManager,
rc.x(), rc.y(),
rc.width(),
rc.height(),
offsetX, offsetY,
writable);
}
inline void completeInitialization(QVector<IteratorTypeSP> *iterators,
KisWrappedRect *splitRect) {
m_splitRect = splitRect;
m_iterators = iterators;
}
inline IteratorTypeSP leftColumnIterator() const {
return m_iterators->at(m_iteratorRowStart + KisWrappedRect::TOPLEFT);
}
inline IteratorTypeSP rightColumnIterator() const {
return m_iterators->at(m_iteratorRowStart + KisWrappedRect::TOPRIGHT);
}
inline bool trySwitchColumnForced() {
bool result =
m_iteratorRowStart != KisWrappedRect::BOTTOMLEFT &&
m_iterators->at(KisWrappedRect::BOTTOMLEFT);
if (result) {
m_iteratorRowStart = KisWrappedRect::BOTTOMLEFT;
}