Make QRegion not need to be friends with QVector
[profile/ivi/qtbase.git] / src / gui / painting / qblendfunctions_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QBLENDFUNCTIONS_P_H
43 #define QBLENDFUNCTIONS_P_H
44
45 #include <qmath.h>
46 #include "qdrawhelper_p.h"
47
48 QT_BEGIN_NAMESPACE
49
50 //
51 //  W A R N I N G
52 //  -------------
53 //
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.
57 //
58 // We mean it.
59 //
60
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,
66                           const QRect &clip,
67                           T blender)
68 {
69     qreal sx = targetRect.width() / (qreal) srcRect.width();
70     qreal sy = targetRect.height() / (qreal) srcRect.height();
71
72     int ix = 0x00010000 / sx;
73     int iy = 0x00010000 / sy;
74
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;
80
81     int cx1 = clip.x();
82     int cx2 = clip.x() + clip.width();
83     int cy1 = clip.top();
84     int cy2 = clip.y() + clip.height();
85
86     int tx1 = qRound(targetRect.left());
87     int tx2 = qRound(targetRect.right());
88     int ty1 = qRound(targetRect.top());
89     int ty2 = qRound(targetRect.bottom());
90
91     if (tx2 < tx1)
92         qSwap(tx2, tx1);
93
94     if (ty2 < ty1)
95         qSwap(ty2, ty1);
96
97     if (tx1 < cx1)
98         tx1 = cx1;
99
100     if (tx2 >= cx2)
101         tx2 = cx2;
102
103     if (tx1 >= tx2)
104         return;
105
106     if (ty1 < cy1)
107         ty1 = cy1;
108
109     if (ty2 >= cy2)
110        ty2 = cy2;
111
112     if (ty1 >= ty2)
113         return;
114
115     int h = ty2 - ty1;
116     int w = tx2 - tx1;
117
118
119     quint32 basex;
120     quint32 srcy;
121
122     if (sx < 0) {
123         int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
124         basex = quint32(srcRect.right() * 65536) + dstx;
125     } else {
126         int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
127         basex = quint32(srcRect.left() * 65536) + dstx;
128     }
129     if (sy < 0) {
130         int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
131         srcy = quint32(srcRect.bottom() * 65536) + dsty;
132     } else {
133         int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
134         srcy = quint32(srcRect.top() * 65536) + dsty;
135     }
136
137     quint16 *dst = ((quint16 *) (destPixels + ty1 * dbpl)) + tx1;
138
139     while (h--) {
140         const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl);
141         int srcx = basex;
142         int x = 0;
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;
152         }
153         for (; x<w; ++x) {
154             blender.write(&dst[x], src[srcx >> 16]);
155             srcx += ix;
156         }
157         blender.flush(&dst[x]);
158         dst = (quint16 *)(((uchar *) dst) + dbpl);
159         srcy += iy;
160     }
161 }
162
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,
167                                                 const QRect &clip,
168                                                 T blender)
169 {
170     qreal sx = targetRect.width() / (qreal) srcRect.width();
171     qreal sy = targetRect.height() / (qreal) srcRect.height();
172
173     int ix = 0x00010000 / sx;
174     int iy = 0x00010000 / sy;
175
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;
181
182     int cx1 = clip.x();
183     int cx2 = clip.x() + clip.width();
184     int cy1 = clip.top();
185     int cy2 = clip.y() + clip.height();
186
187     int tx1 = qRound(targetRect.left());
188     int tx2 = qRound(targetRect.right());
189     int ty1 = qRound(targetRect.top());
190     int ty2 = qRound(targetRect.bottom());
191
192     if (tx2 < tx1)
193         qSwap(tx2, tx1);
194
195     if (ty2 < ty1)
196         qSwap(ty2, ty1);
197
198     if (tx1 < cx1)
199         tx1 = cx1;
200
201     if (tx2 >= cx2)
202         tx2 = cx2;
203
204     if (tx1 >= tx2)
205         return;
206
207     if (ty1 < cy1)
208         ty1 = cy1;
209
210     if (ty2 >= cy2)
211        ty2 = cy2;
212
213     if (ty1 >= ty2)
214         return;
215
216     int h = ty2 - ty1;
217     int w = tx2 - tx1;
218
219     quint32 basex;
220     quint32 srcy;
221
222     if (sx < 0) {
223         int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
224         basex = quint32(srcRect.right() * 65536) + dstx;
225     } else {
226         int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
227         basex = quint32(srcRect.left() * 65536) + dstx;
228     }
229     if (sy < 0) {
230         int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
231         srcy = quint32(srcRect.bottom() * 65536) + dsty;
232     } else {
233         int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
234         srcy = quint32(srcRect.top() * 65536) + dsty;
235     }
236
237     quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1;
238
239     while (h--) {
240         const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl);
241         int srcx = basex;
242         int x = 0;
243         for (; x<w; ++x) {
244             blender.write(&dst[x], src[srcx >> 16]);
245             srcx += ix;
246         }
247         blender.flush(&dst[x]);
248         dst = (quint32 *)(((uchar *) dst) + dbpl);
249         srcy += iy;
250     }
251 }
252
253 struct QTransformImageVertex
254 {
255     qreal x, y, u, v; // destination coordinates (x, y) and source coordinates (u, v)
256 };
257
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,
264                                   const QRect &clip,
265                                   qreal topY, qreal bottomY,
266                                   int dudx, int dvdx, int dudy, int dvdy, int u0, int v0,
267                                   Blender blender)
268 {
269     int fromY = qMax(qRound(topY), clip.top());
270     int toY = qMin(qRound(bottomY), clip.top() + clip.height());
271     if (fromY >= toY)
272         return;
273
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);
280
281     int fromX, toX, x1, x2, u, v, i, ii;
282     DestT *line;
283     for (int y = fromY; y < toY; ++y) {
284         line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl);
285
286         fromX = qMax(x_l >> 16, clip.left());
287         toX = qMin(x_r >> 16, clip.left() + clip.width());
288         if (fromX < toX) {
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.
292
293             // Find the first pixel on the current scan line where the source coordinates are within the source rect.
294             x1 = fromX;
295             u = x1 * dudx + y * dudy + u0;
296             v = x1 * dvdx + y * dvdy + v0;
297             for (; x1 < toX; ++x1) {
298                 int uu = u >> 16;
299                 int vv = v >> 16;
300                 if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
301                     && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
302                     break;
303                 }
304                 u += dudx;
305                 v += dvdx;
306             }
307
308             // Find the last pixel on the current scan line where the source coordinates are within the source rect.
309             x2 = toX;
310             u = (x2 - 1) * dudx + y * dudy + u0;
311             v = (x2 - 1) * dvdx + y * dvdy + v0;
312             for (; x2 > x1; --x2) {
313                 int uu = u >> 16;
314                 int vv = v >> 16;
315                 if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
316                     && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
317                     break;
318                 }
319                 u -= dudx;
320                 v -= dvdx;
321             }
322
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;
326             line += fromX;
327
328             // Beginning of the scan line, with per-pixel checks.
329             i = x1 - fromX;
330             while (i) {
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]);
334                 u += dudx;
335                 v += dvdx;
336                 ++line;
337                 --i;
338             }
339
340             // Middle of the scan line, without checks.
341             // Manual loop unrolling.
342             i = x2 - x1;
343             ii = i >> 3;
344             while (ii) {
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;
353
354                 line += 8;
355
356                 --ii;
357             }
358             switch (i & 7) {
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;
366             }
367
368             // End of the scan line, with per-pixel checks.
369             i = toX - x2;
370             while (i) {
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]);
374                 u += dudx;
375                 v += dvdx;
376                 ++line;
377                 --i;
378             }
379
380             blender.flush(line);
381         }
382         x_l += dx_l;
383         x_r += dx_r;
384     }
385 }
386
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,
392                         const QRect &clip,
393                         const QTransform &targetRectTransform,
394                         Blender blender)
395 {
396     enum Corner
397     {
398         TopLeft,
399         TopRight,
400         BottomRight,
401         BottomLeft
402     };
403
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);
414
415     // find topmost vertex.
416     int topmost = 0;
417     for (int i = 1; i < 4; ++i) {
418         if (v[i].y < v[topmost].y)
419             topmost = i;
420     }
421     // rearrange array such that topmost vertex is at index 0.
422     switch (topmost) {
423     case 1:
424         {
425             QTransformImageVertex t = v[0];
426             for (int i = 0; i < 3; ++i)
427                 v[i] = v[i+1];
428             v[3] = t;
429         }
430         break;
431     case 2:
432         qSwap(v[0], v[2]);
433         qSwap(v[1], v[3]);
434         break;
435     case 3:
436         {
437             QTransformImageVertex t = v[3];
438             for (int i = 3; i > 0; --i)
439                 v[i] = v[i-1];
440             v[0] = t;
441         }
442         break;
443     }
444
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)
451         qSwap(v[1], v[3]);
452
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};
455
456     qreal det = u.x * w.y - u.y * w.x;
457     if (det == 0)
458         return;
459
460     qreal invDet = 1.0 / det;
461     qreal m11, m12, m21, m22, mdx, mdy;
462
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;
469
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;
476
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);
482
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);
488     } else {
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);
492     }
493 }
494
495 QT_END_NAMESPACE
496
497 #endif // QBLENDFUNCTIONS_P_H