1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtGui module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#ifndef QBLENDFUNCTIONS_P_H
43
#define QBLENDFUNCTIONS_P_H
46
#include "qdrawhelper_p.h"
54
// This file is not part of the Qt API. It exists purely as an
55
// implementation detail. This header file may change from version to
56
// version without notice, or even be removed.
61
template <typename SRC, typename T>
62
void qt_scale_image_16bit(uchar *destPixels, int dbpl,
63
const uchar *srcPixels, int sbpl,
64
const QRectF &targetRect,
65
const QRectF &srcRect,
69
qreal sx = targetRect.width() / (qreal) srcRect.width();
70
qreal sy = targetRect.height() / (qreal) srcRect.height();
72
int ix = 0x00010000 / sx;
73
int iy = 0x00010000 / sy;
75
// qDebug() << "scale:" << endl
76
// << " - target" << targetRect << endl
77
// << " - source" << srcRect << endl
78
// << " - clip" << clip << endl
79
// << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy;
82
int cx2 = clip.x() + clip.width();
84
int cy2 = clip.y() + clip.height();
86
int tx1 = qRound(targetRect.left());
87
int tx2 = qRound(targetRect.right());
88
int ty1 = qRound(targetRect.top());
89
int ty2 = qRound(targetRect.bottom());
123
int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
124
basex = quint32(srcRect.right() * 65536) + dstx;
126
int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
127
basex = quint32(srcRect.left() * 65536) + dstx;
130
int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
131
srcy = quint32(srcRect.bottom() * 65536) + dsty;
133
int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
134
srcy = quint32(srcRect.top() * 65536) + dsty;
137
quint16 *dst = ((quint16 *) (destPixels + ty1 * dbpl)) + tx1;
140
const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl);
143
for (; x<w-7; x+=8) {
144
blender.write(&dst[x], src[srcx >> 16]); srcx += ix;
145
blender.write(&dst[x+1], src[srcx >> 16]); srcx += ix;
146
blender.write(&dst[x+2], src[srcx >> 16]); srcx += ix;
147
blender.write(&dst[x+3], src[srcx >> 16]); srcx += ix;
148
blender.write(&dst[x+4], src[srcx >> 16]); srcx += ix;
149
blender.write(&dst[x+5], src[srcx >> 16]); srcx += ix;
150
blender.write(&dst[x+6], src[srcx >> 16]); srcx += ix;
151
blender.write(&dst[x+7], src[srcx >> 16]); srcx += ix;
154
blender.write(&dst[x], src[srcx >> 16]);
157
blender.flush(&dst[x]);
158
dst = (quint16 *)(((uchar *) dst) + dbpl);
163
template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl,
164
const uchar *srcPixels, int sbpl,
165
const QRectF &targetRect,
166
const QRectF &srcRect,
170
qreal sx = targetRect.width() / (qreal) srcRect.width();
171
qreal sy = targetRect.height() / (qreal) srcRect.height();
173
int ix = 0x00010000 / sx;
174
int iy = 0x00010000 / sy;
176
// qDebug() << "scale:" << endl
177
// << " - target" << targetRect << endl
178
// << " - source" << srcRect << endl
179
// << " - clip" << clip << endl
180
// << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy;
183
int cx2 = clip.x() + clip.width();
184
int cy1 = clip.top();
185
int cy2 = clip.y() + clip.height();
187
int tx1 = qRound(targetRect.left());
188
int tx2 = qRound(targetRect.right());
189
int ty1 = qRound(targetRect.top());
190
int ty2 = qRound(targetRect.bottom());
223
int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
224
basex = quint32(srcRect.right() * 65536) + dstx;
226
int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
227
basex = quint32(srcRect.left() * 65536) + dstx;
230
int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
231
srcy = quint32(srcRect.bottom() * 65536) + dsty;
233
int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
234
srcy = quint32(srcRect.top() * 65536) + dsty;
237
quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1;
240
const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl);
244
blender.write(&dst[x], src[srcx >> 16]);
247
blender.flush(&dst[x]);
248
dst = (quint32 *)(((uchar *) dst) + dbpl);
253
struct QTransformImageVertex
255
qreal x, y, u, v; // destination coordinates (x, y) and source coordinates (u, v)
258
template <class SrcT, class DestT, class Blender>
259
void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
260
const SrcT *srcPixels, int sbpl,
261
const QTransformImageVertex &topLeft, const QTransformImageVertex &bottomLeft,
262
const QTransformImageVertex &topRight, const QTransformImageVertex &bottomRight,
263
const QRect &sourceRect,
265
qreal topY, qreal bottomY,
266
int dudx, int dvdx, int dudy, int dvdy, int u0, int v0,
269
int fromY = qMax(qRound(topY), clip.top());
270
int toY = qMin(qRound(bottomY), clip.top() + clip.height());
274
qreal leftSlope = (bottomLeft.x - topLeft.x) / (bottomLeft.y - topLeft.y);
275
qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y);
276
int dx_l = int(leftSlope * 0x10000);
277
int dx_r = int(rightSlope * 0x10000);
278
int x_l = int((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000);
279
int x_r = int((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000);
281
int fromX, toX, x1, x2, u, v, i, ii;
283
for (int y = fromY; y < toY; ++y) {
284
line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl);
286
fromX = qMax(x_l >> 16, clip.left());
287
toX = qMin(x_r >> 16, clip.left() + clip.width());
289
// Because of rounding, we can get source coordinates outside the source image.
290
// Clamp these coordinates to the source rect to avoid segmentation fault and
291
// garbage on the screen.
293
// Find the first pixel on the current scan line where the source coordinates are within the source rect.
295
u = x1 * dudx + y * dudy + u0;
296
v = x1 * dvdx + y * dvdy + v0;
297
for (; x1 < toX; ++x1) {
300
if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
301
&& vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
308
// Find the last pixel on the current scan line where the source coordinates are within the source rect.
310
u = (x2 - 1) * dudx + y * dudy + u0;
311
v = (x2 - 1) * dvdx + y * dvdy + v0;
312
for (; x2 > x1; --x2) {
315
if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
316
&& vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
323
// Set up values at the beginning of the scan line.
324
u = fromX * dudx + y * dudy + u0;
325
v = fromX * dvdx + y * dvdy + v0;
328
// Beginning of the scan line, with per-pixel checks.
331
int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
332
int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
333
blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
340
// Middle of the scan line, without checks.
341
// Manual loop unrolling.
345
blender.write(&line[0], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
346
blender.write(&line[1], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
347
blender.write(&line[2], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
348
blender.write(&line[3], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
349
blender.write(&line[4], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
350
blender.write(&line[5], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
351
blender.write(&line[6], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
352
blender.write(&line[7], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
359
case 7: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
360
case 6: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
361
case 5: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
362
case 4: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
363
case 3: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
364
case 2: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
365
case 1: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
368
// End of the scan line, with per-pixel checks.
371
int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
372
int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
373
blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
387
template <class SrcT, class DestT, class Blender>
388
void qt_transform_image(DestT *destPixels, int dbpl,
389
const SrcT *srcPixels, int sbpl,
390
const QRectF &targetRect,
391
const QRectF &sourceRect,
393
const QTransform &targetRectTransform,
404
// map source rectangle to destination.
405
QTransformImageVertex v[4];
406
v[TopLeft].u = v[BottomLeft].u = sourceRect.left();
407
v[TopLeft].v = v[TopRight].v = sourceRect.top();
408
v[TopRight].u = v[BottomRight].u = sourceRect.right();
409
v[BottomLeft].v = v[BottomRight].v = sourceRect.bottom();
410
targetRectTransform.map(targetRect.left(), targetRect.top(), &v[TopLeft].x, &v[TopLeft].y);
411
targetRectTransform.map(targetRect.right(), targetRect.top(), &v[TopRight].x, &v[TopRight].y);
412
targetRectTransform.map(targetRect.left(), targetRect.bottom(), &v[BottomLeft].x, &v[BottomLeft].y);
413
targetRectTransform.map(targetRect.right(), targetRect.bottom(), &v[BottomRight].x, &v[BottomRight].y);
415
// find topmost vertex.
417
for (int i = 1; i < 4; ++i) {
418
if (v[i].y < v[topmost].y)
421
// rearrange array such that topmost vertex is at index 0.
425
QTransformImageVertex t = v[0];
426
for (int i = 0; i < 3; ++i)
437
QTransformImageVertex t = v[3];
438
for (int i = 3; i > 0; --i)
445
// if necessary, swap vertex 1 and 3 such that 1 is to the left of 3.
446
qreal dx1 = v[1].x - v[0].x;
447
qreal dy1 = v[1].y - v[0].y;
448
qreal dx2 = v[3].x - v[0].x;
449
qreal dy2 = v[3].y - v[0].y;
450
if (dx1 * dy2 - dx2 * dy1 > 0)
453
QTransformImageVertex u = {v[1].x - v[0].x, v[1].y - v[0].y, v[1].u - v[0].u, v[1].v - v[0].v};
454
QTransformImageVertex w = {v[2].x - v[0].x, v[2].y - v[0].y, v[2].u - v[0].u, v[2].v - v[0].v};
456
qreal det = u.x * w.y - u.y * w.x;
460
qreal invDet = 1.0 / det;
461
qreal m11, m12, m21, m22, mdx, mdy;
463
m11 = (u.u * w.y - u.y * w.u) * invDet;
464
m12 = (u.x * w.u - u.u * w.x) * invDet;
465
m21 = (u.v * w.y - u.y * w.v) * invDet;
466
m22 = (u.x * w.v - u.v * w.x) * invDet;
467
mdx = v[0].u - m11 * v[0].x - m12 * v[0].y;
468
mdy = v[0].v - m21 * v[0].x - m22 * v[0].y;
470
int dudx = int(m11 * 0x10000);
471
int dvdx = int(m21 * 0x10000);
472
int dudy = int(m12 * 0x10000);
473
int dvdy = int(m22 * 0x10000);
474
int u0 = qCeil((qreal(0.5) * m11 + qreal(0.5) * m12 + mdx) * 0x10000) - 1;
475
int v0 = qCeil((qreal(0.5) * m21 + qreal(0.5) * m22 + mdy) * 0x10000) - 1;
477
int x1 = qFloor(sourceRect.left());
478
int y1 = qFloor(sourceRect.top());
479
int x2 = qCeil(sourceRect.right());
480
int y2 = qCeil(sourceRect.bottom());
481
QRect sourceRectI(x1, y1, x2 - x1, y2 - y1);
483
// rasterize trapezoids.
484
if (v[1].y < v[3].y) {
485
qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
486
qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[0], v[3], sourceRectI, clip, v[1].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
487
qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[3].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
489
qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
490
qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[3], v[2], sourceRectI, clip, v[3].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
491
qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[1].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
497
#endif // QBLENDFUNCTIONS_P_H