1/*
2 * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#include "kis_convolution_painter.h"
20
21#include <stdlib.h>
22#include <string.h>
23#include <cfloat>
24
25#include <QBrush>
26#include <QColor>
27#include <QFontInfo>
28#include <QFontMetrics>
29#include <QPen>
30#include <QMatrix>
31#include <QImage>
32#include <QMap>
33#include <QPainter>
34#include <QRect>
35#include <QString>
36#include <QVector>
37
38#include <kis_debug.h>
39#include <klocale.h>
40
41#include <KoProgressUpdater.h>
42
43#include "kis_convolution_kernel.h"
44#include "kis_global.h"
45#include "kis_image.h"
46#include "kis_layer.h"
47#include "kis_paint_device.h"
48#include "kis_painter.h"
49#include "KoColorSpace.h"
50#include <KoChannelInfo.h>
51#include "kis_types.h"
52
53#include "kis_selection.h"
54
55#include "kis_convolution_worker.h"
56#include "kis_convolution_worker_spatial.h"
57
58#include "config_convolution.h"
59
60#ifdef HAVE_FFTW3
61#include "kis_convolution_worker_fft.h"
62#endif
63
64
65template<class factory>
66KisConvolutionWorker<factory>* KisConvolutionPainter::createWorker(const KisConvolutionKernelSP kernel,
67 KisPainter *painter,
68 KoUpdater *progress)
69{
70 KisConvolutionWorker<factory> *worker;
71
72#ifdef HAVE_FFTW3
73 #define THRESHOLD_SIZE 5
74
75 if(m_enginePreference == SPATIAL ||
76 (m_enginePreference != FFTW &&
77 kernel->width() <= THRESHOLD_SIZE &&
78 kernel->height() <= THRESHOLD_SIZE)) {
79
80 worker = new KisConvolutionWorkerSpatial<factory>(painter, progress);
81 }
82 else {
83 worker = new KisConvolutionWorkerFFT<factory>(painter, progress);
84 }
85#else
86 Q_UNUSED(kernel);
87 worker = new KisConvolutionWorkerSpatial<factory>(painter, progress);
88#endif
89
90 return worker;
91}
92
93
94KisConvolutionPainter::KisConvolutionPainter()
95 : KisPainter(),
96 m_enginePreference(NONE)
97{
98}
99
100KisConvolutionPainter::KisConvolutionPainter(KisPaintDeviceSP device)
101 : KisPainter(device),
102 m_enginePreference(NONE)
103{
104}
105
106KisConvolutionPainter::KisConvolutionPainter(KisPaintDeviceSP device, KisSelectionSP selection)
107 : KisPainter(device, selection),
108 m_enginePreference(NONE)
109{
110}
111
112KisConvolutionPainter::KisConvolutionPainter(KisPaintDeviceSP device, TestingEnginePreference enginePreference)
113 : KisPainter(device),
114 m_enginePreference(enginePreference)
115{
116}
117
118void KisConvolutionPainter::applyMatrix(const KisConvolutionKernelSP kernel, const KisPaintDeviceSP src, QPoint srcPos, QPoint dstPos, QSize areaSize, KisConvolutionBorderOp borderOp)
119{
120 /**
121 * Force BORDER_IGNORE op for the wraparound mode,
122 * because the paint device has its own special
123 * iterators, which do everything for us.
124 */
125 if (src->defaultBounds()->wrapAroundMode()) {
126 borderOp = BORDER_IGNORE;
127 }
128
129 // Determine whether we convolve border pixels, or not.
130 switch (borderOp) {
131 case BORDER_REPEAT: {
132 const QRect boundsRect = src->exactBounds();
133 const QRect requestedRect = QRect(srcPos, areaSize);
134 QRect dataRect = requestedRect | boundsRect;
135
136 /**
137 * FIXME: Implementation can return empty destination device
138 * on faults and has no way to report this. This will cause a crash
139 * on sequential convolutions inside iteratiors.
140 *
141 * o implementation should do it's work or assert otherwise
142 * (or report the issue somehow)
143 * o check other cases of the switch for the vulnerability
144 */
145
146 if(dataRect.isValid()) {
147 KisConvolutionWorker<RepeatIteratorFactory> *worker;
148 worker = createWorker<RepeatIteratorFactory>(kernel, this, progressUpdater());
149 worker->execute(kernel, src, srcPos, dstPos, areaSize, dataRect);
150 delete worker;
151 }
152 break;
153 }
154 case BORDER_IGNORE:
155 default: {
156 KisConvolutionWorker<StandardIteratorFactory> *worker;
157 worker = createWorker<StandardIteratorFactory>(kernel, this, progressUpdater());
158 worker->execute(kernel, src, srcPos, dstPos, areaSize, QRect());
159 delete worker;
160 }
161 }
162}
163