1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
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 The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
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 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QBLENDFUNCTIONS_P_H |
41 | #define QBLENDFUNCTIONS_P_H |
42 | |
43 | #include <QtGui/private/qtguiglobal_p.h> |
44 | #include <qmath.h> |
45 | #include "qdrawhelper_p.h" |
46 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | // |
50 | // W A R N I N G |
51 | // ------------- |
52 | // |
53 | // This file is not part of the Qt API. It exists purely as an |
54 | // implementation detail. This header file may change from version to |
55 | // version without notice, or even be removed. |
56 | // |
57 | // We mean it. |
58 | // |
59 | |
60 | template <typename SRC, typename T> |
61 | void qt_scale_image_16bit(uchar *destPixels, int dbpl, |
62 | const uchar *srcPixels, int sbpl, int srch, |
63 | const QRectF &targetRect, |
64 | const QRectF &srcRect, |
65 | const QRect &clip, |
66 | T blender) |
67 | { |
68 | qreal sx = srcRect.width() / (qreal) targetRect.width(); |
69 | qreal sy = srcRect.height() / (qreal) targetRect.height(); |
70 | |
71 | const int ix = 0x00010000 * sx; |
72 | const int iy = 0x00010000 * sy; |
73 | |
74 | // qDebug() << "scale:" << Qt::endl |
75 | // << " - target" << targetRect << Qt::endl |
76 | // << " - source" << srcRect << Qt::endl |
77 | // << " - clip" << clip << Qt::endl |
78 | // << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy; |
79 | |
80 | QRect tr = targetRect.normalized().toRect(); |
81 | tr = tr.intersected(other: clip); |
82 | if (tr.isEmpty()) |
83 | return; |
84 | const int tx1 = tr.left(); |
85 | const int ty1 = tr.top(); |
86 | int h = tr.height(); |
87 | int w = tr.width(); |
88 | |
89 | quint32 basex; |
90 | quint32 srcy; |
91 | |
92 | if (sx < 0) { |
93 | int dstx = qFloor(v: (tx1 + qreal(0.5) - targetRect.right()) * sx * 65536) + 1; |
94 | basex = quint32(srcRect.right() * 65536) + dstx; |
95 | } else { |
96 | int dstx = qCeil(v: (tx1 + qreal(0.5) - targetRect.left()) * sx * 65536) - 1; |
97 | basex = quint32(srcRect.left() * 65536) + dstx; |
98 | } |
99 | if (sy < 0) { |
100 | int dsty = qFloor(v: (ty1 + qreal(0.5) - targetRect.bottom()) * sy * 65536) + 1; |
101 | srcy = quint32(srcRect.bottom() * 65536) + dsty; |
102 | } else { |
103 | int dsty = qCeil(v: (ty1 + qreal(0.5) - targetRect.top()) * sy * 65536) - 1; |
104 | srcy = quint32(srcRect.top() * 65536) + dsty; |
105 | } |
106 | |
107 | quint16 *dst = ((quint16 *) (destPixels + ty1 * dbpl)) + tx1; |
108 | |
109 | // this bounds check here is required as floating point rounding above might in some cases lead to |
110 | // w/h values that are one pixel too large, falling outside of the valid image area. |
111 | const int ystart = srcy >> 16; |
112 | if (ystart >= srch && iy < 0) { |
113 | srcy += iy; |
114 | --h; |
115 | } |
116 | const int xstart = basex >> 16; |
117 | if (xstart >= (int)(sbpl/sizeof(SRC)) && ix < 0) { |
118 | basex += ix; |
119 | --w; |
120 | } |
121 | int yend = (srcy + iy * (h - 1)) >> 16; |
122 | if (yend < 0 || yend >= srch) |
123 | --h; |
124 | int xend = (basex + ix * (w - 1)) >> 16; |
125 | if (xend < 0 || xend >= (int)(sbpl/sizeof(SRC))) |
126 | --w; |
127 | |
128 | while (h--) { |
129 | const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl); |
130 | quint32 srcx = basex; |
131 | int x = 0; |
132 | for (; x<w-7; x+=8) { |
133 | blender.write(&dst[x], src[srcx >> 16]); srcx += ix; |
134 | blender.write(&dst[x+1], src[srcx >> 16]); srcx += ix; |
135 | blender.write(&dst[x+2], src[srcx >> 16]); srcx += ix; |
136 | blender.write(&dst[x+3], src[srcx >> 16]); srcx += ix; |
137 | blender.write(&dst[x+4], src[srcx >> 16]); srcx += ix; |
138 | blender.write(&dst[x+5], src[srcx >> 16]); srcx += ix; |
139 | blender.write(&dst[x+6], src[srcx >> 16]); srcx += ix; |
140 | blender.write(&dst[x+7], src[srcx >> 16]); srcx += ix; |
141 | } |
142 | for (; x<w; ++x) { |
143 | blender.write(&dst[x], src[srcx >> 16]); |
144 | srcx += ix; |
145 | } |
146 | blender.flush(&dst[x]); |
147 | dst = (quint16 *)(((uchar *) dst) + dbpl); |
148 | srcy += iy; |
149 | } |
150 | } |
151 | |
152 | template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl, |
153 | const uchar *srcPixels, int sbpl, int srch, |
154 | const QRectF &targetRect, |
155 | const QRectF &srcRect, |
156 | const QRect &clip, |
157 | T blender) |
158 | { |
159 | qreal sx = srcRect.width() / (qreal) targetRect.width(); |
160 | qreal sy = srcRect.height() / (qreal) targetRect.height(); |
161 | |
162 | const int ix = 0x00010000 * sx; |
163 | const int iy = 0x00010000 * sy; |
164 | |
165 | // qDebug() << "scale:" << Qt::endl |
166 | // << " - target" << targetRect << Qt::endl |
167 | // << " - source" << srcRect << Qt::endl |
168 | // << " - clip" << clip << Qt::endl |
169 | // << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy; |
170 | |
171 | QRect tr = targetRect.normalized().toRect(); |
172 | tr = tr.intersected(other: clip); |
173 | if (tr.isEmpty()) |
174 | return; |
175 | const int tx1 = tr.left(); |
176 | const int ty1 = tr.top(); |
177 | int h = tr.height(); |
178 | int w = tr.width(); |
179 | |
180 | quint32 basex; |
181 | quint32 srcy; |
182 | |
183 | if (sx < 0) { |
184 | int dstx = qFloor(v: (tx1 + qreal(0.5) - targetRect.right()) * sx * 65536) + 1; |
185 | basex = quint32(srcRect.right() * 65536) + dstx; |
186 | } else { |
187 | int dstx = qCeil(v: (tx1 + qreal(0.5) - targetRect.left()) * sx * 65536) - 1; |
188 | basex = quint32(srcRect.left() * 65536) + dstx; |
189 | } |
190 | if (sy < 0) { |
191 | int dsty = qFloor(v: (ty1 + qreal(0.5) - targetRect.bottom()) * sy * 65536) + 1; |
192 | srcy = quint32(srcRect.bottom() * 65536) + dsty; |
193 | } else { |
194 | int dsty = qCeil(v: (ty1 + qreal(0.5) - targetRect.top()) * sy * 65536) - 1; |
195 | srcy = quint32(srcRect.top() * 65536) + dsty; |
196 | } |
197 | |
198 | quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1; |
199 | |
200 | // this bounds check here is required as floating point rounding above might in some cases lead to |
201 | // w/h values that are one pixel too large, falling outside of the valid image area. |
202 | const int ystart = srcy >> 16; |
203 | if (ystart >= srch && iy < 0) { |
204 | srcy += iy; |
205 | --h; |
206 | } |
207 | const int xstart = basex >> 16; |
208 | if (xstart >= (int)(sbpl/sizeof(quint32)) && ix < 0) { |
209 | basex += ix; |
210 | --w; |
211 | } |
212 | int yend = (srcy + iy * (h - 1)) >> 16; |
213 | if (yend < 0 || yend >= srch) |
214 | --h; |
215 | int xend = (basex + ix * (w - 1)) >> 16; |
216 | if (xend < 0 || xend >= (int)(sbpl/sizeof(quint32))) |
217 | --w; |
218 | |
219 | while (h--) { |
220 | const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl); |
221 | quint32 srcx = basex; |
222 | int x = 0; |
223 | for (; x<w; ++x) { |
224 | blender.write(&dst[x], src[srcx >> 16]); |
225 | srcx += ix; |
226 | } |
227 | blender.flush(&dst[x]); |
228 | dst = (quint32 *)(((uchar *) dst) + dbpl); |
229 | srcy += iy; |
230 | } |
231 | } |
232 | |
233 | struct QTransformImageVertex |
234 | { |
235 | qreal x, y, u, v; // destination coordinates (x, y) and source coordinates (u, v) |
236 | }; |
237 | |
238 | template <class SrcT, class DestT, class Blender> |
239 | void qt_transform_image_rasterize(DestT *destPixels, int dbpl, |
240 | const SrcT *srcPixels, int sbpl, |
241 | const QTransformImageVertex &topLeft, const QTransformImageVertex &bottomLeft, |
242 | const QTransformImageVertex &topRight, const QTransformImageVertex &bottomRight, |
243 | const QRect &sourceRect, |
244 | const QRect &clip, |
245 | qreal topY, qreal bottomY, |
246 | int dudx, int dvdx, int dudy, int dvdy, int u0, int v0, |
247 | Blender blender) |
248 | { |
249 | qint64 fromY = qMax(a: qRound(d: topY), b: clip.top()); |
250 | qint64 toY = qMin(a: qRound(d: bottomY), b: clip.top() + clip.height()); |
251 | if (fromY >= toY) |
252 | return; |
253 | |
254 | qreal leftSlope = (bottomLeft.x - topLeft.x) / (bottomLeft.y - topLeft.y); |
255 | qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y); |
256 | qint64 dx_l = qint64(leftSlope * 0x10000); |
257 | qint64 dx_r = qint64(rightSlope * 0x10000); |
258 | qint64 x_l = qint64((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000); |
259 | qint64 x_r = qint64((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000); |
260 | |
261 | qint64 sourceRectTop = qint64(sourceRect.top()); |
262 | qint64 sourceRectLeft = qint64(sourceRect.left()); |
263 | qint64 sourceRectWidth = qint64(sourceRect.width()); |
264 | qint64 sourceRectHeight = qint64(sourceRect.height()); |
265 | qint64 clipLeft = qint64(clip.left()); |
266 | qint64 clipWidth = qint64(clip.width()); |
267 | |
268 | qint64 fromX, toX, x1, x2, u, v, i, ii; |
269 | DestT *line; |
270 | for (qint64 y = fromY; y < toY; ++y) { |
271 | line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl); |
272 | |
273 | fromX = qMax(a: x_l >> 16, b: clipLeft); |
274 | toX = qMin(a: x_r >> 16, b: clipLeft + clipWidth); |
275 | if (fromX < toX) { |
276 | // Because of rounding, we can get source coordinates outside the source image. |
277 | // Clamp these coordinates to the source rect to avoid segmentation fault and |
278 | // garbage on the screen. |
279 | |
280 | // Find the first pixel on the current scan line where the source coordinates are within the source rect. |
281 | x1 = fromX; |
282 | u = x1 * dudx + y * dudy + u0; |
283 | v = x1 * dvdx + y * dvdy + v0; |
284 | for (; x1 < toX; ++x1) { |
285 | qint64 uu = u >> 16; |
286 | qint64 vv = v >> 16; |
287 | if (uu >= sourceRectLeft && uu < sourceRectLeft + sourceRectWidth |
288 | && vv >= sourceRectTop && vv < sourceRectTop + sourceRectHeight) { |
289 | break; |
290 | } |
291 | u += dudx; |
292 | v += dvdx; |
293 | } |
294 | |
295 | // Find the last pixel on the current scan line where the source coordinates are within the source rect. |
296 | x2 = toX; |
297 | u = (x2 - 1) * dudx + y * dudy + u0; |
298 | v = (x2 - 1) * dvdx + y * dvdy + v0; |
299 | for (; x2 > x1; --x2) { |
300 | qint64 uu = u >> 16; |
301 | qint64 vv = v >> 16; |
302 | if (uu >= sourceRectLeft && uu < sourceRectLeft + sourceRectWidth |
303 | && vv >= sourceRectTop && vv < sourceRectTop + sourceRectHeight) { |
304 | break; |
305 | } |
306 | u -= dudx; |
307 | v -= dvdx; |
308 | } |
309 | |
310 | // Set up values at the beginning of the scan line. |
311 | u = fromX * dudx + y * dudy + u0; |
312 | v = fromX * dvdx + y * dvdy + v0; |
313 | line += fromX; |
314 | |
315 | // Beginning of the scan line, with per-pixel checks. |
316 | i = x1 - fromX; |
317 | while (i) { |
318 | qint64 uu = qBound(min: sourceRectLeft, val: u >> 16, max: sourceRectLeft + sourceRectWidth - 1); |
319 | qint64 vv = qBound(min: sourceRectTop, val: v >> 16, max: sourceRectTop + sourceRectHeight - 1); |
320 | blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]); |
321 | u += dudx; |
322 | v += dvdx; |
323 | ++line; |
324 | --i; |
325 | } |
326 | |
327 | // Middle of the scan line, without checks. |
328 | // Manual loop unrolling. |
329 | i = x2 - x1; |
330 | ii = i >> 3; |
331 | while (ii) { |
332 | blender.write(&line[0], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; |
333 | blender.write(&line[1], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; |
334 | blender.write(&line[2], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; |
335 | blender.write(&line[3], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; |
336 | blender.write(&line[4], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; |
337 | blender.write(&line[5], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; |
338 | blender.write(&line[6], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; |
339 | blender.write(&line[7], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; |
340 | |
341 | line += 8; |
342 | |
343 | --ii; |
344 | } |
345 | switch (i & 7) { |
346 | case 7: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; Q_FALLTHROUGH(); |
347 | case 6: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; Q_FALLTHROUGH(); |
348 | case 5: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; Q_FALLTHROUGH(); |
349 | case 4: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; Q_FALLTHROUGH(); |
350 | case 3: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; Q_FALLTHROUGH(); |
351 | case 2: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; Q_FALLTHROUGH(); |
352 | case 1: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; |
353 | } |
354 | |
355 | // End of the scan line, with per-pixel checks. |
356 | i = toX - x2; |
357 | while (i) { |
358 | qint64 uu = qBound(min: sourceRectLeft, val: u >> 16, max: sourceRectLeft + sourceRectWidth - 1); |
359 | qint64 vv = qBound(min: sourceRectTop, val: v >> 16, max: sourceRectTop + sourceRectHeight - 1); |
360 | blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]); |
361 | u += dudx; |
362 | v += dvdx; |
363 | ++line; |
364 | --i; |
365 | } |
366 | |
367 | blender.flush(line); |
368 | } |
369 | x_l += dx_l; |
370 | x_r += dx_r; |
371 | } |
372 | } |
373 | |
374 | template <class SrcT, class DestT, class Blender> |
375 | void qt_transform_image(DestT *destPixels, int dbpl, |
376 | const SrcT *srcPixels, int sbpl, |
377 | const QRectF &targetRect, |
378 | const QRectF &sourceRect, |
379 | const QRect &clip, |
380 | const QTransform &targetRectTransform, |
381 | Blender blender) |
382 | { |
383 | enum Corner |
384 | { |
385 | TopLeft, |
386 | TopRight, |
387 | BottomRight, |
388 | BottomLeft |
389 | }; |
390 | |
391 | // map source rectangle to destination. |
392 | QTransformImageVertex v[4]; |
393 | v[TopLeft].u = v[BottomLeft].u = sourceRect.left(); |
394 | v[TopLeft].v = v[TopRight].v = sourceRect.top(); |
395 | v[TopRight].u = v[BottomRight].u = sourceRect.right(); |
396 | v[BottomLeft].v = v[BottomRight].v = sourceRect.bottom(); |
397 | targetRectTransform.map(targetRect.left(), targetRect.top(), &v[TopLeft].x, &v[TopLeft].y); |
398 | targetRectTransform.map(targetRect.right(), targetRect.top(), &v[TopRight].x, &v[TopRight].y); |
399 | targetRectTransform.map(targetRect.left(), targetRect.bottom(), &v[BottomLeft].x, &v[BottomLeft].y); |
400 | targetRectTransform.map(targetRect.right(), targetRect.bottom(), &v[BottomRight].x, &v[BottomRight].y); |
401 | |
402 | // find topmost vertex. |
403 | int topmost = 0; |
404 | for (int i = 1; i < 4; ++i) { |
405 | if (v[i].y < v[topmost].y) |
406 | topmost = i; |
407 | } |
408 | // rearrange array such that topmost vertex is at index 0. |
409 | switch (topmost) { |
410 | case 1: |
411 | { |
412 | QTransformImageVertex t = v[0]; |
413 | for (int i = 0; i < 3; ++i) |
414 | v[i] = v[i+1]; |
415 | v[3] = t; |
416 | } |
417 | break; |
418 | case 2: |
419 | qSwap(value1&: v[0], value2&: v[2]); |
420 | qSwap(value1&: v[1], value2&: v[3]); |
421 | break; |
422 | case 3: |
423 | { |
424 | QTransformImageVertex t = v[3]; |
425 | for (int i = 3; i > 0; --i) |
426 | v[i] = v[i-1]; |
427 | v[0] = t; |
428 | } |
429 | break; |
430 | } |
431 | |
432 | // if necessary, swap vertex 1 and 3 such that 1 is to the left of 3. |
433 | qreal dx1 = v[1].x - v[0].x; |
434 | qreal dy1 = v[1].y - v[0].y; |
435 | qreal dx2 = v[3].x - v[0].x; |
436 | qreal dy2 = v[3].y - v[0].y; |
437 | if (dx1 * dy2 - dx2 * dy1 > 0) |
438 | qSwap(value1&: v[1], value2&: v[3]); |
439 | |
440 | QTransformImageVertex u = {.x: v[1].x - v[0].x, .y: v[1].y - v[0].y, .u: v[1].u - v[0].u, .v: v[1].v - v[0].v}; |
441 | QTransformImageVertex w = {.x: v[2].x - v[0].x, .y: v[2].y - v[0].y, .u: v[2].u - v[0].u, .v: v[2].v - v[0].v}; |
442 | |
443 | qreal det = u.x * w.y - u.y * w.x; |
444 | if (det == 0) |
445 | return; |
446 | |
447 | qreal invDet = 1.0 / det; |
448 | qreal m11, m12, m21, m22, mdx, mdy; |
449 | |
450 | m11 = (u.u * w.y - u.y * w.u) * invDet; |
451 | m12 = (u.x * w.u - u.u * w.x) * invDet; |
452 | m21 = (u.v * w.y - u.y * w.v) * invDet; |
453 | m22 = (u.x * w.v - u.v * w.x) * invDet; |
454 | mdx = v[0].u - m11 * v[0].x - m12 * v[0].y; |
455 | mdy = v[0].v - m21 * v[0].x - m22 * v[0].y; |
456 | |
457 | int dudx = int(m11 * 0x10000); |
458 | int dvdx = int(m21 * 0x10000); |
459 | int dudy = int(m12 * 0x10000); |
460 | int dvdy = int(m22 * 0x10000); |
461 | int u0 = qCeil(v: (qreal(0.5) * m11 + qreal(0.5) * m12 + mdx) * 0x10000) - 1; |
462 | int v0 = qCeil(v: (qreal(0.5) * m21 + qreal(0.5) * m22 + mdy) * 0x10000) - 1; |
463 | |
464 | int x1 = qFloor(v: sourceRect.left()); |
465 | int y1 = qFloor(v: sourceRect.top()); |
466 | int x2 = qCeil(v: sourceRect.right()); |
467 | int y2 = qCeil(v: sourceRect.bottom()); |
468 | QRect sourceRectI(x1, y1, x2 - x1, y2 - y1); |
469 | |
470 | // rasterize trapezoids. |
471 | if (v[1].y < v[3].y) { |
472 | 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); |
473 | 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); |
474 | 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); |
475 | } else { |
476 | 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); |
477 | 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); |
478 | 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); |
479 | } |
480 | } |
481 | |
482 | QT_END_NAMESPACE |
483 | |
484 | #endif // QBLENDFUNCTIONS_P_H |
485 | |