~ubuntu-branches/ubuntu/vivid/qpdfview/vivid

« back to all changes in this revision

Viewing changes to sources/rendertask.cpp

  • Committer: Package Import Robot
  • Author(s): Benjamin Eltzner
  • Date: 2014-10-22 21:49:15 UTC
  • mfrom: (1.2.15)
  • Revision ID: package-import@ubuntu.com-20141022214915-agqeoe318lzs2s4d
Tags: 0.4.12-1
* New upstream release.
* Fixed option to zoom to selection and implemented tiled rendering
  (Closes: #739554)
* Enable support for qt5 and poppler-qt5.
* Explicit dependence on hicolor-icon-theme.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
#include "rendertask.h"
23
23
 
 
24
#include <qmath.h>
24
25
#include <QThreadPool>
25
26
 
26
27
#include "model.h"
27
28
 
 
29
namespace
 
30
{
 
31
 
 
32
using namespace qpdfview;
 
33
 
 
34
enum
 
35
{
 
36
    NotCanceled = 0,
 
37
    CanceledNormally = 1,
 
38
    CanceledForcibly = 2
 
39
};
 
40
 
 
41
void setCancellation(QAtomicInt& wasCanceled, bool force)
 
42
{
 
43
#if QT_VERSION > QT_VERSION_CHECK(5,0,0)
 
44
 
 
45
    wasCanceled.storeRelease(force ? CanceledForcibly : CanceledNormally);
 
46
 
 
47
#else
 
48
 
 
49
    wasCanceled.fetchAndStoreRelease(force ? CanceledForcibly : CanceledNormally);
 
50
 
 
51
#endif // QT_VERSION
 
52
}
 
53
 
 
54
void resetCancellation(QAtomicInt& wasCanceled)
 
55
{
 
56
#if QT_VERSION > QT_VERSION_CHECK(5,0,0)
 
57
 
 
58
    wasCanceled.storeRelease(NotCanceled);
 
59
 
 
60
#else
 
61
 
 
62
    wasCanceled.fetchAndStoreRelease(NotCanceled);
 
63
 
 
64
#endif // QT_VERSION
 
65
}
 
66
 
 
67
bool testCancellation(QAtomicInt& wasCanceled, bool prefetch)
 
68
{
 
69
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
 
70
 
 
71
    return prefetch ?
 
72
                wasCanceled.load() == CanceledForcibly :
 
73
                wasCanceled.load() != NotCanceled;
 
74
 
 
75
#else
 
76
 
 
77
    return prefetch ?
 
78
                wasCanceled.testAndSetRelaxed(CanceledForcibly, CanceledForcibly) :
 
79
                !wasCanceled.testAndSetRelaxed(NotCanceled, NotCanceled);
 
80
 
 
81
#endif // QT_VERSION
 
82
}
 
83
 
 
84
int loadWasCanceled(const QAtomicInt& wasCanceled)
 
85
{
 
86
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
 
87
 
 
88
    return wasCanceled.load();
 
89
 
 
90
#else
 
91
 
 
92
    return wasCanceled;
 
93
 
 
94
#endif // QT_VERSION
 
95
}
 
96
 
 
97
qreal scaledResolutionX(const RenderParam& renderParam)
 
98
{
 
99
    return renderParam.resolution.devicePixelRatio *
 
100
            renderParam.resolution.resolutionX * renderParam.scaleFactor;
 
101
}
 
102
 
 
103
qreal scaledResolutionY(const RenderParam& renderParam)
 
104
{
 
105
    return renderParam.resolution.devicePixelRatio *
 
106
            renderParam.resolution.resolutionY * renderParam.scaleFactor;
 
107
}
 
108
 
 
109
bool columnHasPaperColor(int x, QRgb paperColor, const QImage& image)
 
110
{
 
111
    const int height = image.height();
 
112
 
 
113
    for(int y = 0; y < height; ++y)
 
114
    {
 
115
        if(paperColor != (image.pixel(x, y) | 0xff000000u))
 
116
        {
 
117
            return false;
 
118
        }
 
119
    }
 
120
 
 
121
    return true;
 
122
}
 
123
 
 
124
bool rowHasPaperColor(int y, QRgb paperColor, const QImage& image)
 
125
{
 
126
    const int width = image.width();
 
127
 
 
128
    for(int x = 0; x < width; ++x)
 
129
    {
 
130
        if(paperColor != (image.pixel(x, y) | 0xff000000u))
 
131
        {
 
132
            return false;
 
133
        }
 
134
    }
 
135
 
 
136
    return true;
 
137
}
 
138
 
 
139
QRectF trimMargins(QRgb paperColor, const QImage& image)
 
140
{
 
141
    if(image.isNull())
 
142
    {
 
143
        return QRectF(0.0, 0.0, 1.0, 1.0);
 
144
    }
 
145
 
 
146
    const int width = image.width();
 
147
    const int height = image.height();
 
148
 
 
149
    int left;
 
150
    for(left = 0; left < width; ++left)
 
151
    {
 
152
        if(!columnHasPaperColor(left, paperColor, image))
 
153
        {
 
154
            break;
 
155
        }
 
156
    }
 
157
    left = qMin(left, width / 3);
 
158
 
 
159
    int right;
 
160
    for(right = width - 1; right >= left; --right)
 
161
    {
 
162
        if(!columnHasPaperColor(right, paperColor, image))
 
163
        {
 
164
            break;
 
165
        }
 
166
    }
 
167
    right = qMax(right, 2 * width / 3);
 
168
 
 
169
    int top;
 
170
    for(top = 0; top < height; ++top)
 
171
    {
 
172
        if(!rowHasPaperColor(top, paperColor, image))
 
173
        {
 
174
            break;
 
175
        }
 
176
    }
 
177
    top = qMin(top, height / 3);
 
178
 
 
179
    int bottom;
 
180
    for(bottom = height - 1; bottom >= top; --bottom)
 
181
    {
 
182
        if(!rowHasPaperColor(bottom, paperColor, image))
 
183
        {
 
184
            break;
 
185
        }
 
186
    }
 
187
    bottom = qMax(bottom, 2 * height / 3);
 
188
 
 
189
    left = qMax(left - width / 100, 0);
 
190
    top = qMax(top - height / 100, 0);
 
191
 
 
192
    right = qMin(right + width / 100, width);
 
193
    bottom = qMin(bottom + height / 100, height);
 
194
 
 
195
    return QRectF(static_cast< qreal >(left) / width,
 
196
                  static_cast< qreal >(top) / height,
 
197
                  static_cast< qreal >(right - left) / width,
 
198
                  static_cast< qreal >(bottom - top) / height);
 
199
}
 
200
 
 
201
} // anonymous
 
202
 
28
203
namespace qpdfview
29
204
{
30
205
 
31
 
RenderTask::RenderTask(QObject* parent) : QObject(parent), QRunnable(),
 
206
RenderTask::RenderTask(Model::Page* page, QObject* parent) : QObject(parent), QRunnable(),
32
207
    m_isRunning(false),
33
 
    m_wasCanceled(false),
34
 
    m_page(0),
35
 
    m_resolutionX(72),
36
 
    m_resolutionY(72),
37
 
    m_devicePixelRatio(1.0),
38
 
    m_scaleFactor(1.0),
39
 
    m_rotation(RotateBy0),
40
 
    m_invertColors(false),
41
 
    m_prefetch(false)
 
208
    m_wasCanceled(NotCanceled),
 
209
    m_page(page),
 
210
    m_renderParam(),
 
211
    m_rect(),
 
212
    m_prefetch(false),
 
213
    m_trimMargins(false),
 
214
    m_paperColor()
42
215
{
43
216
    setAutoDelete(false);
44
217
}
62
235
 
63
236
bool RenderTask::wasCanceled() const
64
237
{
65
 
    return m_wasCanceled;
 
238
    return loadWasCanceled(m_wasCanceled) != NotCanceled;
 
239
}
 
240
 
 
241
bool RenderTask::wasCanceledNormally() const
 
242
{
 
243
    return loadWasCanceled(m_wasCanceled) == CanceledNormally;
 
244
}
 
245
 
 
246
bool RenderTask::wasCanceledForcibly() const
 
247
{
 
248
    return loadWasCanceled(m_wasCanceled) == CanceledForcibly;
66
249
}
67
250
 
68
251
void RenderTask::run()
69
252
{
70
 
    if(m_wasCanceled && !m_prefetch)
71
 
    {
72
 
        finish();
73
 
 
74
 
        return;
75
 
    }
76
 
 
77
 
    qreal resolutionX;
78
 
    qreal resolutionY;
79
 
 
80
 
    switch(m_rotation)
81
 
    {
82
 
    default:
83
 
    case RotateBy0:
84
 
    case RotateBy180:
85
 
        resolutionX = m_resolutionX * m_scaleFactor;
86
 
        resolutionY = m_resolutionY * m_scaleFactor;
87
 
        break;
88
 
    case RotateBy90:
89
 
    case RotateBy270:
90
 
        resolutionX = m_resolutionY * m_scaleFactor;
91
 
        resolutionY = m_resolutionX * m_scaleFactor;
92
 
        break;
93
 
    }
 
253
#define CANCELLATION_POINT if(testCancellation(m_wasCanceled, m_prefetch)) { finish(); return; }
 
254
 
 
255
    CANCELLATION_POINT
 
256
 
 
257
    QImage image;
 
258
    QRectF cropRect;
 
259
 
 
260
    image = m_page->render(scaledResolutionX(m_renderParam), scaledResolutionY(m_renderParam),
 
261
                           m_renderParam.rotation, m_rect);
94
262
 
95
263
#if QT_VERSION >= QT_VERSION_CHECK(5,1,0)
96
264
 
97
 
    QImage image = m_page->render(m_devicePixelRatio * resolutionX, m_devicePixelRatio * resolutionY, m_rotation);
98
 
 
99
 
    image.setDevicePixelRatio(m_devicePixelRatio);
100
 
 
101
 
#else
102
 
 
103
 
    QImage image = m_page->render(resolutionX, resolutionY, m_rotation);
 
265
    image.setDevicePixelRatio(m_renderParam.resolution.devicePixelRatio);
104
266
 
105
267
#endif // QT_VERSION
106
268
 
107
 
    if(m_wasCanceled && !m_prefetch)
108
 
    {
109
 
        finish();
110
 
 
111
 
        return;
112
 
    }
113
 
 
114
 
    if(m_invertColors)
115
 
    {
 
269
    if(m_renderParam.invertColors)
 
270
    {
 
271
        CANCELLATION_POINT
 
272
 
116
273
        image.invertPixels();
117
274
    }
118
275
 
119
 
    emit imageReady(m_resolutionX, m_resolutionY, m_devicePixelRatio, m_scaleFactor, m_rotation, m_invertColors, m_prefetch, image);
 
276
    if(m_trimMargins)
 
277
    {
 
278
        CANCELLATION_POINT
 
279
 
 
280
        cropRect = trimMargins(m_paperColor.rgb(), image);
 
281
    }
 
282
 
 
283
    CANCELLATION_POINT
 
284
 
 
285
    emit imageReady(m_renderParam,
 
286
                    m_rect, m_prefetch,
 
287
                    image, cropRect);
120
288
 
121
289
    finish();
 
290
 
 
291
#undef CANCELLATION_POINT
122
292
}
123
293
 
124
 
void RenderTask::start(Model::Page* page, int resolutionX, int resolutionY, qreal devicePixelRatio, qreal scaleFactor, Rotation rotation, bool invertColors, bool prefetch)
 
294
void RenderTask::start(const RenderParam& renderParam,
 
295
                       const QRect& rect, bool prefetch,
 
296
                       bool trimMargins, const QColor& paperColor)
125
297
{
126
 
    m_page = page;
127
 
 
128
 
    m_resolutionX = resolutionX;
129
 
    m_resolutionY = resolutionY;
130
 
    m_devicePixelRatio = devicePixelRatio;
131
 
 
132
 
    m_scaleFactor = scaleFactor;
133
 
    m_rotation = rotation;
134
 
 
135
 
    m_invertColors = invertColors;
136
 
 
 
298
    m_renderParam = renderParam;
 
299
 
 
300
    m_rect = rect;
137
301
    m_prefetch = prefetch;
138
302
 
 
303
    m_trimMargins = trimMargins;
 
304
    m_paperColor = paperColor;
 
305
 
139
306
    m_mutex.lock();
140
307
    m_isRunning = true;
141
308
    m_mutex.unlock();
142
309
 
143
 
    m_wasCanceled = false;
 
310
    resetCancellation(m_wasCanceled);
144
311
 
145
 
    QThreadPool::globalInstance()->start(this);
 
312
    QThreadPool::globalInstance()->start(this, prefetch ? 0 : 1);
146
313
}
147
314
 
148
 
void RenderTask::cancel()
 
315
void RenderTask::cancel(bool force)
149
316
{
150
 
    m_wasCanceled = true;
 
317
    setCancellation(m_wasCanceled, force);
151
318
}
152
319
 
153
320
void RenderTask::finish()