1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "private/qmemrotate_p.h"
46 #if QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
47 static const int tileSize = 32;
50 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
51 #if QT_ROTATION_ALGORITHM == QT_ROTATION_PACKED || QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
52 #error Big endian version not implemented for the transformed driver!
57 Q_STATIC_TEMPLATE_FUNCTION
58 inline void qt_memrotate90_cachedRead(const T *src, int w, int h, int sstride, T *dest,
61 const char *s = reinterpret_cast<const char*>(src);
62 char *d = reinterpret_cast<char*>(dest);
63 for (int y = 0; y < h; ++y) {
64 for (int x = w - 1; x >= 0; --x) {
65 T *destline = reinterpret_cast<T *>(d + (w - x - 1) * dstride);
69 src = reinterpret_cast<const T*>(s);
74 Q_STATIC_TEMPLATE_FUNCTION
75 inline void qt_memrotate270_cachedRead(const T *src, int w, int h, int sstride, T *dest,
78 const char *s = reinterpret_cast<const char*>(src);
79 char *d = reinterpret_cast<char*>(dest);
80 s += (h - 1) * sstride;
81 for (int y = h - 1; y >= 0; --y) {
82 src = reinterpret_cast<const T*>(s);
83 for (int x = 0; x < w; ++x) {
84 T *destline = reinterpret_cast<T *>(d + x * dstride);
85 destline[h - y - 1] = src[x];
91 #if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
94 Q_STATIC_TEMPLATE_FUNCTION
95 inline void qt_memrotate90_cachedWrite(const T *src, int w, int h, int sstride, T *dest,
98 for (int x = w - 1; x >= 0; --x) {
99 T *d = dest + (w - x - 1) * dstride;
100 for (int y = 0; y < h; ++y) {
101 *d++ = src[y * sstride + x];
108 Q_STATIC_TEMPLATE_FUNCTION
109 inline void qt_memrotate270_cachedWrite(const T *src, int w, int h, int sstride, T *dest,
112 for (int x = 0; x < w; ++x) {
113 T *d = dest + x * dstride;
114 for (int y = h - 1; y >= 0; --y) {
115 *d++ = src[y * sstride + x];
120 #endif // QT_ROTATION_CACHEDWRITE
122 #if QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
124 // TODO: packing algorithms should probably be modified on 64-bit architectures
127 Q_STATIC_TEMPLATE_FUNCTION
128 inline void qt_memrotate90_packing(const T *src, int w, int h, int sstride, T *dest, int dstride)
130 sstride /= sizeof(T);
131 dstride /= sizeof(T);
133 const int pack = sizeof(quint32) / sizeof(T);
134 const int unaligned = int((long(dest) & (sizeof(quint32)-1))) / sizeof(T);
136 for (int x = w - 1; x >= 0; --x) {
139 for (int i = 0; i < unaligned; ++i) {
140 dest[(w - x - 1) * dstride + y] = src[y * sstride + x];
144 quint32 *d = reinterpret_cast<quint32*>(dest + (w - x - 1) * dstride
146 const int rest = (h - unaligned) % pack;
147 while (y < h - rest) {
148 quint32 c = src[y * sstride + x];
149 for (int i = 1; i < pack; ++i) {
150 c |= src[(y + i) * sstride + x] << (sizeof(int) * 8 / pack * i);
157 dest[(w - x - 1) * dstride + y] = src[y * sstride + x];
164 Q_STATIC_TEMPLATE_FUNCTION
165 inline void qt_memrotate270_packing(const T *src, int w, int h, int sstride, T *dest, int dstride)
167 sstride /= sizeof(T);
168 dstride /= sizeof(T);
170 const int pack = sizeof(quint32) / sizeof(T);
171 const int unaligned = int((long(dest) & (sizeof(quint32)-1))) / sizeof(T);
173 for (int x = 0; x < w; ++x) {
176 for (int i = 0; i < unaligned; ++i) {
177 dest[x * dstride + h - y - 1] = src[y * sstride + x];
181 quint32 *d = reinterpret_cast<quint32*>(dest + x * dstride
183 const int rest = (h - unaligned) % pack;
185 quint32 c = src[y * sstride + x];
186 for (int i = 1; i < pack; ++i) {
187 c |= src[(y - i) * sstride + x] << (sizeof(int) * 8 / pack * i);
193 dest[x * dstride + h - y - 1] = src[y * sstride + x];
199 #endif // QT_ROTATION_PACKING
201 #if QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
203 Q_STATIC_TEMPLATE_FUNCTION
204 inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
206 sstride /= sizeof(T);
207 dstride /= sizeof(T);
209 const int pack = sizeof(quint32) / sizeof(T);
210 const int unaligned =
211 qMin(uint((quintptr(dest) & (sizeof(quint32)-1)) / sizeof(T)), uint(h));
212 const int restX = w % tileSize;
213 const int restY = (h - unaligned) % tileSize;
214 const int unoptimizedY = restY % pack;
215 const int numTilesX = w / tileSize + (restX > 0);
216 const int numTilesY = (h - unaligned) / tileSize + (restY >= pack);
218 for (int tx = 0; tx < numTilesX; ++tx) {
219 const int startx = w - tx * tileSize - 1;
220 const int stopx = qMax(startx - tileSize, 0);
223 for (int x = startx; x >= stopx; --x) {
224 T *d = dest + (w - x - 1) * dstride;
225 for (int y = 0; y < unaligned; ++y) {
226 *d++ = src[y * sstride + x];
231 for (int ty = 0; ty < numTilesY; ++ty) {
232 const int starty = ty * tileSize + unaligned;
233 const int stopy = qMin(starty + tileSize, h - unoptimizedY);
235 for (int x = startx; x >= stopx; --x) {
236 quint32 *d = reinterpret_cast<quint32*>(dest + (w - x - 1) * dstride + starty);
237 for (int y = starty; y < stopy; y += pack) {
238 quint32 c = src[y * sstride + x];
239 for (int i = 1; i < pack; ++i) {
240 const int shift = (sizeof(int) * 8 / pack * i);
241 const T color = src[(y + i) * sstride + x];
250 const int starty = h - unoptimizedY;
251 for (int x = startx; x >= stopx; --x) {
252 T *d = dest + (w - x - 1) * dstride + starty;
253 for (int y = starty; y < h; ++y) {
254 *d++ = src[y * sstride + x];
262 Q_STATIC_TEMPLATE_FUNCTION
263 inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
266 const int numTilesX = (w + tileSize - 1) / tileSize;
267 const int numTilesY = (h + tileSize - 1) / tileSize;
269 for (int tx = 0; tx < numTilesX; ++tx) {
270 const int startx = w - tx * tileSize - 1;
271 const int stopx = qMax(startx - tileSize, 0);
273 for (int ty = 0; ty < numTilesY; ++ty) {
274 const int starty = ty * tileSize;
275 const int stopy = qMin(starty + tileSize, h);
277 for (int x = startx; x >= stopx; --x) {
278 T *d = (T *)((char*)dest + (w - x - 1) * dstride) + starty;
279 const char *s = (const char*)(src + x) + starty * sstride;
280 for (int y = starty; y < stopy; ++y) {
281 *d++ = *(const T *)(s);
290 Q_STATIC_TEMPLATE_FUNCTION
291 inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
293 sstride /= sizeof(T);
294 dstride /= sizeof(T);
296 const int pack = sizeof(quint32) / sizeof(T);
297 const int unaligned =
298 qMin(uint((long(dest) & (sizeof(quint32)-1)) / sizeof(T)), uint(h));
299 const int restX = w % tileSize;
300 const int restY = (h - unaligned) % tileSize;
301 const int unoptimizedY = restY % pack;
302 const int numTilesX = w / tileSize + (restX > 0);
303 const int numTilesY = (h - unaligned) / tileSize + (restY >= pack);
305 for (int tx = 0; tx < numTilesX; ++tx) {
306 const int startx = tx * tileSize;
307 const int stopx = qMin(startx + tileSize, w);
310 for (int x = startx; x < stopx; ++x) {
311 T *d = dest + x * dstride;
312 for (int y = h - 1; y >= h - unaligned; --y) {
313 *d++ = src[y * sstride + x];
318 for (int ty = 0; ty < numTilesY; ++ty) {
319 const int starty = h - 1 - unaligned - ty * tileSize;
320 const int stopy = qMax(starty - tileSize, unoptimizedY);
322 for (int x = startx; x < stopx; ++x) {
323 quint32 *d = reinterpret_cast<quint32*>(dest + x * dstride
325 for (int y = starty; y > stopy; y -= pack) {
326 quint32 c = src[y * sstride + x];
327 for (int i = 1; i < pack; ++i) {
328 const int shift = (sizeof(int) * 8 / pack * i);
329 const T color = src[(y - i) * sstride + x];
337 const int starty = unoptimizedY - 1;
338 for (int x = startx; x < stopx; ++x) {
339 T *d = dest + x * dstride + h - 1 - starty;
340 for (int y = starty; y >= 0; --y) {
341 *d++ = src[y * sstride + x];
349 Q_STATIC_TEMPLATE_FUNCTION
350 inline void qt_memrotate270_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
353 const int numTilesX = (w + tileSize - 1) / tileSize;
354 const int numTilesY = (h + tileSize - 1) / tileSize;
356 for (int tx = 0; tx < numTilesX; ++tx) {
357 const int startx = tx * tileSize;
358 const int stopx = qMin(startx + tileSize, w);
360 for (int ty = 0; ty < numTilesY; ++ty) {
361 const int starty = h - 1 - ty * tileSize;
362 const int stopy = qMax(starty - tileSize, 0);
364 for (int x = startx; x < stopx; ++x) {
365 T *d = (T*)((char*)dest + x * dstride) + h - 1 - starty;
366 const char *s = (const char*)(src + x) + starty * sstride;
367 for (int y = starty; y >= stopy; --y) {
376 #endif // QT_ROTATION_ALGORITHM
379 Q_STATIC_TEMPLATE_FUNCTION
380 inline void qt_memrotate90_template(const T *src, int srcWidth, int srcHeight, int srcStride,
381 T *dest, int dstStride)
383 #if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
384 qt_memrotate90_cachedRead<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
385 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
386 qt_memrotate90_cachedWrite<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
387 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
388 qt_memrotate90_packing<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
389 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
390 qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
395 Q_STATIC_TEMPLATE_FUNCTION
396 inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
398 const char *s = (const char*)(src) + (h - 1) * sstride;
399 for (int y = h - 1; y >= 0; --y) {
400 T *d = reinterpret_cast<T*>((char *)(dest) + (h - y - 1) * dstride);
401 src = reinterpret_cast<const T*>(s);
402 for (int x = w - 1; x >= 0; --x) {
403 d[w - x - 1] = src[x];
410 Q_STATIC_TEMPLATE_FUNCTION
411 inline void qt_memrotate270_template(const T *src, int srcWidth, int srcHeight, int srcStride,
412 T *dest, int dstStride)
414 #if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
415 qt_memrotate270_cachedRead<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
416 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
417 qt_memrotate270_cachedWrite<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
418 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
419 qt_memrotate270_packing<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
420 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
421 qt_memrotate270_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
426 inline void qt_memrotate90_template<quint24>(const quint24 *src, int srcWidth, int srcHeight,
427 int srcStride, quint24 *dest, int dstStride)
429 #if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
430 qt_memrotate90_cachedRead<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
431 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
432 qt_memrotate90_cachedWrite<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
433 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
434 // packed algorithm not implemented
435 qt_memrotate90_cachedRead<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
436 #elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
437 // packed algorithm not implemented
438 qt_memrotate90_tiled_unpacked<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
442 #define QT_IMPL_MEMROTATE(type) \
443 Q_GUI_EXPORT void qt_memrotate90(const type *src, int w, int h, int sstride, \
444 type *dest, int dstride) \
446 qt_memrotate90_template(src, w, h, sstride, dest, dstride); \
448 Q_GUI_EXPORT void qt_memrotate180(const type *src, int w, int h, int sstride, \
449 type *dest, int dstride) \
451 qt_memrotate180_template(src, w, h, sstride, dest, dstride); \
453 Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
454 type *dest, int dstride) \
456 qt_memrotate270_template(src, w, h, sstride, dest, dstride); \
459 #define QT_IMPL_SIMPLE_MEMROTATE(type) \
460 Q_GUI_EXPORT void qt_memrotate90(const type *src, int w, int h, int sstride, \
461 type *dest, int dstride) \
463 qt_memrotate90_tiled_unpacked<type>(src, w, h, sstride, dest, dstride); \
465 Q_GUI_EXPORT void qt_memrotate180(const type *src, int w, int h, int sstride, \
466 type *dest, int dstride) \
468 qt_memrotate180_template(src, w, h, sstride, dest, dstride); \
470 Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
471 type *dest, int dstride) \
473 qt_memrotate270_tiled_unpacked<type>(src, w, h, sstride, dest, dstride); \
479 QT_IMPL_MEMROTATE(quint32)
480 QT_IMPL_MEMROTATE(quint16)
481 QT_IMPL_MEMROTATE(quint24)
482 QT_IMPL_MEMROTATE(quint8)
484 void qt_memrotate90_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
486 qt_memrotate90((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
489 void qt_memrotate180_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
491 qt_memrotate180((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
494 void qt_memrotate270_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
496 qt_memrotate270((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
499 void qt_memrotate90_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
501 qt_memrotate90((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
504 void qt_memrotate180_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
506 qt_memrotate180((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
509 void qt_memrotate270_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
511 qt_memrotate270((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
514 MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3] =
517 { 0, 0, 0 }, // Format_Invalid,
518 { 0, 0, 0 }, // Format_Mono,
519 { 0, 0, 0 }, // Format_MonoLSB,
520 { 0, 0, 0 }, // Format_Indexed8,
521 { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGB32,
522 { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_ARGB32,
523 { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_ARGB32_Premultiplied,
524 { qt_memrotate90_16, qt_memrotate180_16, qt_memrotate270_16 }, // Format_RGB16,
525 { 0, 0, 0 }, // Format_ARGB8565_Premultiplied,
526 { 0, 0, 0 }, // Format_RGB666,
527 { 0, 0, 0 }, // Format_ARGB6666_Premultiplied,
528 { 0, 0, 0 }, // Format_RGB555,
529 { 0, 0, 0 }, // Format_ARGB8555_Premultiplied,
530 { 0, 0, 0 }, // Format_RGB888,
531 { 0, 0, 0 }, // Format_RGB444,
532 { 0, 0, 0 } // Format_ARGB4444_Premultiplied,