diff options
author | Paul Olav Tvete <paul.tvete@theqtcompany.com> | 2015-05-13 12:42:46 +0200 |
---|---|---|
committer | Paul Olav Tvete <paul.tvete@theqtcompany.com> | 2015-05-13 12:42:46 +0200 |
commit | 8524853227c753b5cfa14184a086ec0acff3930a (patch) | |
tree | 808fab49e65286a4b4416a8462bb78fc188dfeac /src/gui/painting | |
parent | d5a6c1613b52ebc015aa85a46c1387909d435926 (diff) | |
parent | bf06924f3ffd22747c93a720caa501d8478dcbe6 (diff) |
Merge branch 'wip/highdpi' of git://code.qt.io/qt/qtbase into dev-highdpi
Conflicts:
src/plugins/platforms/xcb/qxcbscreen.cpp
src/plugins/platforms/xcb/qxcbwindow.cpp
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/painting.pri | 4 | ||||
-rw-r--r-- | src/gui/painting/qblendfunctions.cpp | 2136 | ||||
-rw-r--r-- | src/gui/painting/qcompositionfunctions.cpp | 2197 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 3349 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_neon.cpp | 2 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_p.h | 144 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_sse2.cpp | 86 | ||||
-rw-r--r-- | src/gui/painting/qdrawingprimitive_sse2_p.h | 6 | ||||
-rw-r--r-- | src/gui/painting/qimagescale.cpp | 1155 | ||||
-rw-r--r-- | src/gui/painting/qimagescale_p.h | 9 | ||||
-rw-r--r-- | src/gui/painting/qimagescale_sse4.cpp | 247 | ||||
-rw-r--r-- | src/gui/painting/qmatrix.cpp | 24 | ||||
-rw-r--r-- | src/gui/painting/qmatrix.h | 2 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_raster.cpp | 1 | ||||
-rw-r--r-- | src/gui/painting/qpainter_p.h | 1 | ||||
-rw-r--r-- | src/gui/painting/qpdf.cpp | 490 | ||||
-rw-r--r-- | src/gui/painting/qpdf_p.h | 13 | ||||
-rw-r--r-- | src/gui/painting/qrgba64.h | 16 | ||||
-rw-r--r-- | src/gui/painting/qrgba64_p.h | 53 | ||||
-rw-r--r-- | src/gui/painting/qtransform.cpp | 24 | ||||
-rw-r--r-- | src/gui/painting/qtransform.h | 2 |
21 files changed, 4639 insertions, 5322 deletions
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index fafc67cf46..791b5f1a9a 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -60,6 +60,7 @@ SOURCES += \ painting/qbrush.cpp \ painting/qcolor.cpp \ painting/qcolor_p.cpp \ + painting/qcompositionfunctions.cpp \ painting/qcosmeticstroker.cpp \ painting/qcssutil.cpp \ painting/qdrawhelper.cpp \ @@ -95,7 +96,8 @@ SOURCES += \ SSE2_SOURCES += painting/qdrawhelper_sse2.cpp SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp -SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp +SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ + painting/qimagescale_sse4.cpp AVX2_SOURCES += painting/qdrawhelper_avx2.cpp !ios { diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 478fe6564c..b3710411c9 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -432,10 +432,10 @@ static void qt_blend_argb32pm_on_a2rgb30pm(uchar *destPixels, int dbpl, } template<QtPixelOrder PixelOrder> -void qt_blend_rgb32_on_rgb30(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) +static void qt_blend_rgb32_on_rgb30(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) { #ifdef QT_DEBUG_DRAW fprintf(stdout, "qt_blend_rgb32_on_rgb30: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", @@ -496,10 +496,10 @@ static void qt_blend_a2rgb30pm_on_a2rgb30pm(uchar *destPixels, int dbpl, } -void qt_blend_rgb30_on_rgb30(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) +static void qt_blend_rgb30_on_rgb30(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) { #ifdef QT_DEBUG_DRAW fprintf(stdout, "qt_blend_rgb30_on_rgb30: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", @@ -740,2071 +740,75 @@ void qt_transform_image_argb32_on_argb32(uchar *destPixels, int dbpl, } } -SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGRs30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_scale_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_scale_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_scale_image_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_scale_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_scale_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_scale_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_scale_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - } -}; - +SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats]; +SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats]; +SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats]; -SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb16, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_blend_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_blend_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_blend_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, +void qInitBlendFunctions() +{ + qScaleFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_blend_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_blend_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30<PixelOrderBGR>, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm<PixelOrderBGR>, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_RGB30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30<PixelOrderBGR>, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm<PixelOrderBGR>, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_BGR30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_RGB30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30<PixelOrderRGB>, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm<PixelOrderRGB>, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_BGR30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30<PixelOrderRGB>, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm<PixelOrderRGB>, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_BGR30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - } -}; -SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_transform_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_transform_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_transform_image_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb16; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_transform_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_transform_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, + qBlendFunctions[QImage::Format_BGR30][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30<PixelOrderBGR>; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm<PixelOrderBGR>; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_BGR30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_RGB30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30<PixelOrderBGR>; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm<PixelOrderBGR>; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_BGR30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30<PixelOrderRGB>; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm<PixelOrderRGB>; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_BGR30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_RGB30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30<PixelOrderRGB>; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm<PixelOrderRGB>; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_BGR30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + + qTransformFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_transform_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_transform_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qTransformFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_transform_image_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, -}; +} QT_END_NAMESPACE diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp new file mode 100644 index 0000000000..ba428a7938 --- /dev/null +++ b/src/gui/painting/qcompositionfunctions.cpp @@ -0,0 +1,2197 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> +#include <private/qdrawhelper_p.h> +#include <private/qrgba64_p.h> + +QT_BEGIN_NAMESPACE + +# define PRELOAD_INIT(x) +# define PRELOAD_INIT2(x,y) +# define PRELOAD_COND(x) +# define PRELOAD_COND2(x,y) + +/* The constant alpha factor describes an alpha factor that gets applied + to the result of the composition operation combining it with the destination. + + The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1. + we get the unmodified operation + + result = src op dest + dest = result * const_alpha + dest * (1. - const_alpha) + + This means that in the comments below, the first line is the const_alpha==255 case, the + second line the general one. + + In the lines below: + s == src, sa == alpha(src), sia = 1 - alpha(src) + d == dest, da == alpha(dest), dia = 1 - alpha(dest) + ca = const_alpha, cia = 1 - const_alpha + + The methods exist in two variants. One where we have a constant source, the other + where the source is an array of pixels. +*/ + +/* + result = 0 + d = d * cia +*/ +#define comp_func_Clear_impl(dest, length, const_alpha)\ +{\ + if (const_alpha == 255) {\ + QT_MEMFILL_UINT(dest, length, 0);\ + } else {\ + int ialpha = 255 - const_alpha;\ + PRELOAD_INIT(dest)\ + for (int i = 0; i < length; ++i) {\ + PRELOAD_COND(dest)\ + dest[i] = BYTE_MUL(dest[i], ialpha);\ + }\ + }\ +} + +void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha) +{ + comp_func_Clear_impl(dest, length, const_alpha); +} + +void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, 0, length); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha255(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) +{ + comp_func_Clear_impl(dest, length, const_alpha); +} + +void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int length, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, 0, length); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha255(dest[i], ialpha); + } + } +} + +/* + result = s + dest = s * ca + d * cia +*/ +void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) { + QT_MEMFILL_UINT(dest, length, color); + } else { + int ialpha = 255 - const_alpha; + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = color + BYTE_MUL(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, color, length); + else { + int ialpha = 255 - const_alpha; + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + dest[i] = color + multiplyAlpha255(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + ::memcpy(dest, src, length * sizeof(uint)); + } else { + int ialpha = 255 - const_alpha; + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + ::memcpy(dest, src, length * sizeof(quint64)); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = interpolate255(src[i], const_alpha, dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint) +{ +} + +void QT_FASTCALL comp_func_solid_Destination_rgb64(QRgba64 *, int, QRgba64, uint) +{ +} + +void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint) +{ +} + +void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, uint) +{ +} + +/* + result = s + d * sia + dest = (s + d * sia) * ca + d * cia + = s * ca + d * (sia * ca + cia) + = s * ca + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha) +{ + if ((const_alpha & qAlpha(color)) == 255) { + QT_MEMFILL_UINT(dest, length, color); + } else { + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255 && color.isOpaque()) { + qt_memfill64((quint64*)dest, color, length); + } else { + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + dest[i] = color + multiplyAlpha65535(dest[i], 65535 - color.alpha()); + } + } +} + +void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + if (s >= 0xff000000) + dest[i] = s; + else if (s != 0) + dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + if (s.isOpaque()) + dest[i] = s; + else if (!s.isTransparent()) + dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); + } + } +} + +/* + result = d + s * dia + dest = (d + s * dia) * ca + d * cia + = d + s * dia * ca +*/ +void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = d + BYTE_MUL(color, qAlpha(~d)); + } +} + +void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = d + multiplyAlpha65535(color, 65535 - d.alpha()); + } +} + +void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = d + BYTE_MUL(s, qAlpha(~d)); + } + } +} + +void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = d + multiplyAlpha65535(src[i], 65535 - d.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = d + multiplyAlpha65535(s, 65535 - d.alpha()); + } + } +} + +/* + result = s * da + dest = s * da * ca + d * cia +*/ +void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) +{ + PRELOAD_INIT(dest) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(color, qAlpha(dest[i])); + } + } else { + color = BYTE_MUL(color, const_alpha); + uint cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(color, dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + color = multiplyAlpha65535(color, ca); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, d.alpha(), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); + } + } else { + uint cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(src[i], dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha65535(src[i], ca); + dest[i] = interpolate65535(s, d.alpha(), d, cia); + } + } +} + +/* + result = d * sa + dest = d * sa * ca + d * cia + = d * (sa * ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(color); + if (const_alpha != 255) { + a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; + } + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(dest[i], a); + } +} + +void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = color.alpha(); + uint ca64k = const_alpha * 257; + if (const_alpha != 255) + a = qt_div_65535(a * ca64k) + 65535 - ca64k; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], a); + } +} + +void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; + dest[i] = BYTE_MUL(dest[i], a); + } + } +} + +void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], src[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + uint a = qt_div_65535(src[i].alpha() * ca) + cia; + dest[i] = multiplyAlpha65535(dest[i], a); + } + } +} + +/* + result = s * dia + dest = s * dia * ca + d * cia +*/ + +void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) +{ + PRELOAD_INIT(dest) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); + } + } else { + color = BYTE_MUL(color, const_alpha); + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(color, 65535 - dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + color = multiplyAlpha65535(color, ca); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, 65535 - d.alpha(), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(src[i], 65535 - dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha65535(src[i], ca); + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, cia); + } + } +} + +/* + result = d * sia + dest = d * sia * ca + d * cia + = d * (sia * ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(~color); + if (const_alpha != 255) + a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(dest[i], a); + } +} + +void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = 65535 - color.alpha(); + uint ca64k = const_alpha * 257; + if (const_alpha != 255) + a = qt_div_65535(a * ca64k) + 65535 - ca64k; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], a); + } +} + +void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; + dest[i] = BYTE_MUL(dest[i], sia); + } + } +} + +void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], 65535 - src[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + uint a = qt_div_65535((65535 - src[i].alpha()) * ca) + cia; + dest[i] = multiplyAlpha65535(dest[i], a); + } + } +} + +/* + result = s*da + d*sia + dest = s*da*ca + d*sia*ca + d *cia + = s*ca * da + d * (sia*ca + cia) + = s*ca * da + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) { + color = BYTE_MUL(color, const_alpha); + } + uint sia = qAlpha(~color); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); + } +} + +void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + uint sia = 65535 - color.alpha(); + for (int i = 0; i < length; ++i) { + dest[i] = interpolate65535(color, dest[i].alpha(), dest[i], sia); + } +} + +void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + QRgba64 d = dest[i]; + dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + QRgba64 d = dest[i]; + dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); + } + } +} + +/* + result = d*sa + s*dia + dest = d*sa*ca + s*dia*ca + d *cia + = s*ca * dia + d * (sa*ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(color); + if (const_alpha != 255) { + color = BYTE_MUL(color, const_alpha); + a = qAlpha(color) + 255 - const_alpha; + } + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); + } +} + +void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = color.alpha(); + if (const_alpha != 255) { + color = multiplyAlpha255(color, const_alpha); + a = color.alpha() + 65535 - (const_alpha * 257); + } + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(d, a, color, 65535 - d.alpha()); + } +} + +void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + uint a = qAlpha(s) + cia; + dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d)); + } + } +} + +void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + QRgba64 d = dest[i]; + dest[i] = interpolate65535(d, s.alpha(), s, 65535 - d.alpha()); + } + } else { + int ca = const_alpha * 257; + int cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha65535(src[i], ca); + QRgba64 d = dest[i]; + uint a = s.alpha() + cia; + dest[i] = interpolate65535(d, a, s, 65535 - d.alpha()); + } + } +} + +/* + result = d*sia + s*dia + dest = d*sia*ca + s*dia*ca + d *cia + = s*ca * dia + d * (sia*ca + cia) + = s*ca * dia + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + uint sia = qAlpha(~color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); + } +} + +void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + uint sia = 65535 - color.alpha(); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, 65535 - d.alpha(), d, sia); + } +} + +void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = src[i]; + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); + } + } +} + +struct QFullCoverage { + inline void store(uint *dest, const uint src) const + { + *dest = src; + } +}; + +struct QPartialCoverage { + inline QPartialCoverage(uint const_alpha) + : ca(const_alpha) + , ica(255 - const_alpha) + { + } + + inline void store(uint *dest, const uint src) const + { + *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica); + } + +private: + const uint ca; + const uint ica; +}; + +static inline int mix_alpha(int da, int sa) +{ + return 255 - ((255 - sa) * (255 - da) >> 8); +} + +/* + Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca +*/ +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage) +{ + uint s = color; + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + d = comp_func_Plus_one_pixel(d, s); + coverage.store(&dest[i], d); + } +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl_rgb64(QRgba64 *dest, int length, QRgba64 color, const T &coverage) +{ + QRgba64 s = color; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + d = comp_func_Plus_one_pixel(d, s); + coverage.store(&dest[i], d); + } +} + +void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Plus_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = addWithSaturation(dest[i], color); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = addWithSaturation(dest[i], color); + dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); + } + } +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + d = comp_func_Plus_one_pixel(d, s); + + coverage.store(&dest[i], d); + } +} + +void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Plus_impl(dest, src, length, QFullCoverage()); + else + comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = addWithSaturation(dest[i], src[i]); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = addWithSaturation(dest[i], src[i]); + dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); + } + } +} + +/* + Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int multiply_op(int dst, int src, int da, int sa) +{ + return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) multiply_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) multiply_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Multiply_impl(dest, src, length, QFullCoverage()); + else + comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca - Sca.Dca +*/ +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) 255 - qt_div_255((255-a) * (255-b)) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Screen_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Screen_impl(dest, src, length, QFullCoverage()); + else + comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Dca < Da + Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int overlay_op(int dst, int src, int da, int sa) +{ + const int temp = src * (255 - da) + dst * (255 - sa); + if (2 * dst < da) + return qt_div_255(2 * src * dst + temp); + else + return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) overlay_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) overlay_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Overlay_impl(dest, src, length, QFullCoverage()); + else + comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + Da' = Sa + Da - Sa.Da +*/ +static inline int darken_op(int dst, int src, int da, int sa) +{ + return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) darken_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Darken_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) darken_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Darken_impl(dest, src, length, QFullCoverage()); + else + comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + Da' = Sa + Da - Sa.Da +*/ +static inline int lighten_op(int dst, int src, int da, int sa) +{ + return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) lighten_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) lighten_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Lighten_impl(dest, src, length, QFullCoverage()); + else + comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if Sca.Da + Dca.Sa >= Sa.Da + Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int color_dodge_op(int dst, int src, int da, int sa) +{ + const int sa_da = sa * da; + const int dst_sa = dst * sa; + const int src_da = src * da; + + const int temp = src * (255 - da) + dst * (255 - sa); + if (src_da + dst_sa >= sa_da) + return qt_div_255(sa_da + temp); + else + return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a,b) color_dodge_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) color_dodge_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_ColorDodge_impl(dest, src, length, QFullCoverage()); + else + comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if Sca.Da + Dca.Sa <= Sa.Da + Dca' = Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int color_burn_op(int dst, int src, int da, int sa) +{ + const int src_da = src * da; + const int dst_sa = dst * sa; + const int sa_da = sa * da; + + const int temp = src * (255 - da) + dst * (255 - sa); + + if (src == 0 || src_da + dst_sa <= sa_da) + return qt_div_255(temp); + return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) color_burn_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) color_burn_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_ColorBurn_impl(dest, src, length, QFullCoverage()); + else + comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Sca < Sa + Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline uint hardlight_op(int dst, int src, int da, int sa) +{ + const uint temp = src * (255 - da) + dst * (255 - sa); + + if (2 * src < sa) + return qt_div_255(2 * src * dst + temp); + else + return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) hardlight_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) hardlight_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_HardLight_impl(dest, src, length, QFullCoverage()); + else + comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Sca <= Sa + Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise if 2.Sca > Sa and 4.Dca <= Da + Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise if 2.Sca > Sa and 4.Dca > Da + Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int soft_light_op(int dst, int src, int da, int sa) +{ + const int src2 = src << 1; + const int dst_np = da != 0 ? (255 * dst) / da : 0; + const int temp = (src * (255 - da) + dst * (255 - sa)) * 255; + + if (src2 < sa) + return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025; + else if (4 * dst <= da) + return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025; + else { + return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; + } +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) soft_light_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) soft_light_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_SoftLight_impl(dest, src, length, QFullCoverage()); + else + comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca - 2.min(Sca.Da, Dca.Sa) +*/ +static inline int difference_op(int dst, int src, int da, int sa) +{ + return src + dst - qt_div_255(2 * qMin(src * da, dst * sa)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) difference_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Difference_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) difference_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Difference_impl(dest, src, length, QFullCoverage()); + else + comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) (a + b - qt_div_255(2*(a*b))) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) (a + b - ((a*b) >> 7)) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Exclusion_impl(dest, src, length, QFullCoverage()); + else + comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ |= color; +} + +void QT_FASTCALL rasterop_SourceOrDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ |= *src++; +} + +void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color |= 0xff000000; + while (length--) + *dest++ &= color; +} + +void QT_FASTCALL rasterop_SourceAndDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src & *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color &= 0x00ffffff; + while (length--) + *dest++ ^= color; +} + +void QT_FASTCALL rasterop_SourceXorDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src ^ *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color; + while (length--) { + *dest = (color & ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) & ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) { + *dest = color | ~(*dest); + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = ~(*src) | ~(*dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color & 0x00ffffff; + while (length--) { + *dest = color ^ (*dest); + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceXorDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = ((~(*src)) ^ (*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, + uint color, uint const_alpha) +{ + Q_UNUSED(const_alpha); + qt_memfill(dest, ~color | 0xff000000, length); +} + +void QT_FASTCALL rasterop_NotSource(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, + int length, uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ = ~(*src++) | 0xff000000; +} + +void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) { + *dest = color & *dest; + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceAndDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) & *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (color & ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_SourceAndNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src & ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) | *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) + *dest++ |= color; +} + +void QT_FASTCALL rasterop_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src | ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (color | ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_ClearDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); +} + +void QT_FASTCALL rasterop_solid_ClearDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); +} + +void QT_FASTCALL rasterop_SetDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); +} + +void QT_FASTCALL rasterop_solid_SetDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); +} + +void QT_FASTCALL rasterop_NotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); +} + +void QT_FASTCALL rasterop_solid_NotDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); +} + +CompositionFunctionSolid qt_functionForModeSolid_C[] = { + comp_func_solid_SourceOver, + comp_func_solid_DestinationOver, + comp_func_solid_Clear, + comp_func_solid_Source, + comp_func_solid_Destination, + comp_func_solid_SourceIn, + comp_func_solid_DestinationIn, + comp_func_solid_SourceOut, + comp_func_solid_DestinationOut, + comp_func_solid_SourceAtop, + comp_func_solid_DestinationAtop, + comp_func_solid_XOR, + comp_func_solid_Plus, + comp_func_solid_Multiply, + comp_func_solid_Screen, + comp_func_solid_Overlay, + comp_func_solid_Darken, + comp_func_solid_Lighten, + comp_func_solid_ColorDodge, + comp_func_solid_ColorBurn, + comp_func_solid_HardLight, + comp_func_solid_SoftLight, + comp_func_solid_Difference, + comp_func_solid_Exclusion, + rasterop_solid_SourceOrDestination, + rasterop_solid_SourceAndDestination, + rasterop_solid_SourceXorDestination, + rasterop_solid_NotSourceAndNotDestination, + rasterop_solid_NotSourceOrNotDestination, + rasterop_solid_NotSourceXorDestination, + rasterop_solid_NotSource, + rasterop_solid_NotSourceAndDestination, + rasterop_solid_SourceAndNotDestination, + rasterop_solid_NotSourceOrDestination, + rasterop_solid_SourceOrNotDestination, + rasterop_solid_ClearDestination, + rasterop_solid_SetDestination, + rasterop_solid_NotDestination +}; + +CompositionFunctionSolid64 qt_functionForModeSolid64_C[] = { + comp_func_solid_SourceOver_rgb64, + comp_func_solid_DestinationOver_rgb64, + comp_func_solid_Clear_rgb64, + comp_func_solid_Source_rgb64, + comp_func_solid_Destination_rgb64, + comp_func_solid_SourceIn_rgb64, + comp_func_solid_DestinationIn_rgb64, + comp_func_solid_SourceOut_rgb64, + comp_func_solid_DestinationOut_rgb64, + comp_func_solid_SourceAtop_rgb64, + comp_func_solid_DestinationAtop_rgb64, + comp_func_solid_XOR_rgb64, + comp_func_solid_Plus_rgb64, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +CompositionFunction qt_functionForMode_C[] = { + comp_func_SourceOver, + comp_func_DestinationOver, + comp_func_Clear, + comp_func_Source, + comp_func_Destination, + comp_func_SourceIn, + comp_func_DestinationIn, + comp_func_SourceOut, + comp_func_DestinationOut, + comp_func_SourceAtop, + comp_func_DestinationAtop, + comp_func_XOR, + comp_func_Plus, + comp_func_Multiply, + comp_func_Screen, + comp_func_Overlay, + comp_func_Darken, + comp_func_Lighten, + comp_func_ColorDodge, + comp_func_ColorBurn, + comp_func_HardLight, + comp_func_SoftLight, + comp_func_Difference, + comp_func_Exclusion, + rasterop_SourceOrDestination, + rasterop_SourceAndDestination, + rasterop_SourceXorDestination, + rasterop_NotSourceAndNotDestination, + rasterop_NotSourceOrNotDestination, + rasterop_NotSourceXorDestination, + rasterop_NotSource, + rasterop_NotSourceAndDestination, + rasterop_SourceAndNotDestination, + rasterop_NotSourceOrDestination, + rasterop_SourceOrNotDestination, + rasterop_ClearDestination, + rasterop_SetDestination, + rasterop_NotDestination +}; + +CompositionFunction64 qt_functionForMode64_C[] = { + comp_func_SourceOver_rgb64, + comp_func_DestinationOver_rgb64, + comp_func_Clear_rgb64, + comp_func_Source_rgb64, + comp_func_Destination_rgb64, + comp_func_SourceIn_rgb64, + comp_func_DestinationIn_rgb64, + comp_func_SourceOut_rgb64, + comp_func_DestinationOut_rgb64, + comp_func_SourceAtop_rgb64, + comp_func_DestinationAtop_rgb64, + comp_func_XOR_rgb64, + comp_func_Plus_rgb64, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index b6f06135cd..e46e997f1d 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -185,6 +185,36 @@ static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int } template<QImage::Format Format> +static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + + for (int i = 0; i < count; ++i) { + uint red = (src[i] >> redShift<Format>()) & redMask; + uint green = (src[i] >> greenShift<Format>()) & greenMask; + uint blue = (src[i] >> blueShift<Format>()) & blueMask; + + red = ((red << redLeftShift) | (red >> redRightShift)) << 16; + green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; + blue = (blue << blueLeftShift) | (blue >> blueRightShift); + buffer[i] = QRgba64::fromRgba(red, green, blue, 255); + } + + return buffer; +} + +template<QImage::Format Format> static const uint *QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -220,6 +250,41 @@ static const uint *QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, const uint } template<QImage::Format Format> +static const QRgba64 *QT_FASTCALL convertARGBPMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1); + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar alphaLeftShift = 8 - alphaWidth<Format>(); + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uchar alphaRightShift = 2 * alphaWidth<Format>() - 8; + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + + for (int i = 0; i < count; ++i) { + uint alpha = (src[i] >> alphaShift<Format>()) & alphaMask; + uint red = (src[i] >> redShift<Format>()) & redMask; + uint green = (src[i] >> greenShift<Format>()) & greenMask; + uint blue = (src[i] >> blueShift<Format>()) & blueMask; + + alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift); + red = qMin(alpha, (red << redLeftShift) | (red >> redRightShift)); + green = qMin(alpha, (green << greenLeftShift) | (green >> greenRightShift)); + blue = qMin(alpha, (blue << blueLeftShift) | (blue >> blueRightShift)); + buffer[i] = QRgba64::fromRgba(red, green, blue, alpha); + } + + return buffer; +} + +template<QImage::Format Format> static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -321,7 +386,8 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe false, bitsPerPixel<Format>(), convertToRGB32<Format>, convertRGBFromARGB32PM<Format>, - convertRGBFromRGB32<Format> + convertRGBFromRGB32<Format>, + convertToRGB64<Format> }; } @@ -335,7 +401,8 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe true, bitsPerPixel<Format>(), convertARGBPMToARGB32PM<Format>, convertARGBPMFromARGB32PM<Format>, - convertARGBPMFromRGB32<Format> + convertARGBPMFromRGB32<Format>, + convertARGBPMToARGB64PM<Format> }; } @@ -350,6 +417,14 @@ static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint return buffer; } +static const QRgba64 *QT_FASTCALL convertIndexedToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *clut) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(clut[src[i]]).premultiplied(); + return buffer; +} + static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int, const QPixelLayout *, const QRgb *) { @@ -392,6 +467,22 @@ static const uint *QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, const uint return buffer; } +static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]); + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255); + return buffer; +} + static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -408,6 +499,111 @@ static const uint *QT_FASTCALL convertRGBA8888PMFromARGB32PM(uint *buffer, const return buffer; } +#ifdef __SSE2__ +template<bool RGBA, bool maskAlpha> +static inline void qConvertARGB32PMToARGB64PM_sse2(QRgba64 *buffer, const uint *src, int count) +{ + const __m128i amask = _mm_set1_epi32(0xff000000); + int i = 0; + if (((uintptr_t)buffer & 0xf) && count > 0) { + uint s = *src++; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + i++; + } + for (; i < count-3; i += 4) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + if (maskAlpha) + vs = _mm_or_si128(vs, amask); + src += 4; + __m128i v1 = _mm_unpacklo_epi8(vs, vs); + __m128i v2 = _mm_unpackhi_epi8(vs, vs); + if (!RGBA) { + v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); + v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); + v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); + v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); + } + _mm_store_si128((__m128i*)(buffer), v1); + buffer += 2; + _mm_store_si128((__m128i*)(buffer), v2); + buffer += 2; + } + + for (; i < count; ++i) { + uint s = *src++; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + } +} +#endif + +static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<false, true>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertARGB32ToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<false, false>(buffer, src, count); + for (int i = 0; i < count; ++i) + buffer[i] = buffer[i].premultiplied(); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertARGB32PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<false, false>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(src[i]); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertRGBA8888ToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<true, false>(buffer, src, count); + for (int i = 0; i < count; ++i) + buffer[i] = buffer[i].premultiplied(); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied(); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertRGBA8888PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<true, false>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])); +#endif + return buffer; +} + static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -441,6 +637,60 @@ static const uint *QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, const ui return buffer; } +#ifdef __SSE2__ +template<QtPixelOrder PixelOrder> +static inline void qConvertA2RGB30PMToARGB64PM_sse2(QRgba64 *buffer, const uint *src, int count) +{ + const __m128i rmask = _mm_set1_epi32(0x3ff00000); + const __m128i gmask = _mm_set1_epi32(0x000ffc00); + const __m128i bmask = _mm_set1_epi32(0x000003ff); + const __m128i afactor = _mm_set1_epi16(0x5555); + int i = 0; + if (((uintptr_t)buffer & 0xf) && count > 0) { + *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); + i++; + } + for (; i < count-3; i += 4) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + src += 4; + __m128i va = _mm_srli_epi32(vs, 30); + __m128i vr = _mm_and_si128(vs, rmask); + __m128i vb = _mm_and_si128(vs, bmask); + __m128i vg = _mm_and_si128(vs, gmask); + va = _mm_mullo_epi16(va, afactor); + vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24)); + vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14)); + vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4)); + __m128i vrb; + if (PixelOrder == PixelOrderRGB) + vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2)); + else + vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2)); + __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2)); + _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga)); + buffer += 2; + _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga)); + buffer += 2; + } + + for (; i < count; ++i) + *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); +} +#endif + +template<QtPixelOrder PixelOrder> +static const QRgba64 *QT_FASTCALL convertA2RGB30PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertA2RGB30PMToARGB64PM_sse2<PixelOrder>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]); +#endif + return buffer; +} + template<QtPixelOrder PixelOrder> static const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) @@ -602,15 +852,15 @@ inline void QT_FASTCALL storePixels<QPixelLayout::BPP32>(uchar *dest, const uint // convertFromArgb32() assumes that no color channel is more than 8 bits. // QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits. QPixelLayout qPixelLayouts[QImage::NImageFormats] = { - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0 }, // Format_Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0 }, // Format_Mono - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0 }, // Format_MonoLSB - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0 }, // Format_Indexed8 + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0, 0 }, // Format_Invalid + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Mono + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_MonoLSB + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Indexed8 // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong, // but everywhere this generic conversion would be wrong is currently overloaded. - { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_RGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough }, // Format_ARGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_ARGB32_Premultiplied + { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertRGB32ToRGB64 }, // Format_RGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough, convertARGB32ToARGB64PM }, // Format_ARGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertARGB32PMToARGB64PM }, // Format_ARGB32_Premultiplied #ifdef Q_COMPILER_CONSTEXPR pixelLayoutRGB<QImage::Format_RGB16>(), pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(), @@ -625,55 +875,73 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32<QImage::Format_RGB16>, convertRGBFromARGB32PM<QImage::Format_RGB16>, - convertRGBFromRGB32<QImage::Format_RGB16>}, + convertRGBFromRGB32<QImage::Format_RGB16>, + convertToRGB64<QImage::Format_RGB16>, + }, { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM<QImage::Format_ARGB8565_Premultiplied>, convertARGBPMFromARGB32PM<QImage::Format_ARGB8565_Premultiplied>, - convertARGBPMFromRGB32<QImage::Format_ARGB8565_Premultiplied>}, + convertARGBPMFromRGB32<QImage::Format_ARGB8565_Premultiplied>, + convertARGBPMToARGB64PM<QImage::Format_ARGB8565_Premultiplied>, + }, { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32<QImage::Format_RGB666>, convertRGBFromARGB32PM<QImage::Format_RGB666>, - convertRGBFromRGB32<QImage::Format_RGB666>}, + convertRGBFromRGB32<QImage::Format_RGB666>, + convertToRGB64<QImage::Format_RGB666>, + }, { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM<QImage::Format_ARGB6666_Premultiplied>, convertARGBPMFromARGB32PM<QImage::Format_ARGB6666_Premultiplied>, - convertARGBPMFromRGB32<QImage::Format_ARGB6666_Premultiplied>}, + convertARGBPMFromRGB32<QImage::Format_ARGB6666_Premultiplied>, + convertARGBPMToARGB64PM<QImage::Format_ARGB6666_Premultiplied>, + }, { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32<QImage::Format_RGB555>, convertRGBFromARGB32PM<QImage::Format_RGB555>, - convertRGBFromRGB32<QImage::Format_RGB555> }, + convertRGBFromRGB32<QImage::Format_RGB555>, + convertToRGB64<QImage::Format_RGB555>, + }, { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM<QImage::Format_ARGB8555_Premultiplied>, convertARGBPMFromARGB32PM<QImage::Format_ARGB8555_Premultiplied>, - convertARGBPMFromRGB32<QImage::Format_ARGB8555_Premultiplied>}, + convertARGBPMFromRGB32<QImage::Format_ARGB8555_Premultiplied>, + convertARGBPMToARGB64PM<QImage::Format_ARGB8555_Premultiplied>, + }, { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32<QImage::Format_RGB888>, convertRGBFromARGB32PM<QImage::Format_RGB888>, - convertRGBFromRGB32<QImage::Format_RGB888>}, + convertRGBFromRGB32<QImage::Format_RGB888>, + convertToRGB64<QImage::Format_RGB888>, + }, { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32<QImage::Format_RGB444>, convertRGBFromARGB32PM<QImage::Format_RGB444>, - convertRGBFromRGB32<QImage::Format_RGB444>}, + convertRGBFromRGB32<QImage::Format_RGB444>, + convertToRGB64<QImage::Format_RGB444>, + }, { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertARGBPMToARGB32PM<QImage::Format_ARGB4444_Premultiplied>, convertARGBPMFromARGB32PM<QImage::Format_ARGB4444_Premultiplied>, - convertARGBPMFromRGB32<QImage::Format_ARGB4444_Premultiplied>}, + convertARGBPMFromRGB32<QImage::Format_ARGB4444_Premultiplied>, + convertARGBPMToARGB64PM<QImage::Format_ARGB4444_Premultiplied>, + }, #endif #if Q_BYTE_ORDER == Q_BIG_ENDIAN - { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 - { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888 - { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32}, // Format_RGBA8888_Premultiplied + { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 + { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 + { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM}, // Format_RGBA8888_Premultiplied #else - { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 - { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888 (ABGR32) - { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied + { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 + { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 (ABGR32) + { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBA8888_Premultiplied #endif - { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR> }, // Format_BGR30 - { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied - { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB> }, // Format_RGB30 - { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied - { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0 }, // Format_Alpha8 - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32 } // Format_Grayscale8 + { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_BGR30 + { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied + { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_RGB30 + { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied + { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8 + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8 }; FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { @@ -764,29 +1032,14 @@ static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBu const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; uint buffer32[buffer_size]; const uint *ptr = qFetchPixels[layout->bpp](buffer32, rasterBuffer->scanLine(y), x, length); - ptr = const_cast<uint *>(layout->convertToARGB32PM(buffer32, ptr, length, layout, 0)); - - for (int i = 0; i < length; ++i) { - buffer[i] = QRgba64::fromArgb32(ptr[i]); - } - return buffer; -} - -static QRgba64 *QT_FASTCALL destFetch64ARGB32(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) -{ - const uint *src = ((const uint *)rasterBuffer->scanLine(y)) + x; - for (int i = 0; i < length; ++i) - buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); - return buffer; + return const_cast<QRgba64 *>(layout->convertToARGB64PM(buffer, ptr, length, layout, 0)); } -template<QtPixelOrder PixelOrder> -static QRgba64 *QT_FASTCALL destFetch64RGB30(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) +static QRgba64 *QT_FASTCALL destFetch64uint32(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) { + const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; const uint *src = ((const uint *)rasterBuffer->scanLine(y)) + x; - for (int i = 0; i < length; ++i) - buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]); - return buffer; + return const_cast<QRgba64 *>(layout->convertToARGB64PM(buffer, src, length, layout, 0)); } static DestFetchProc destFetchProc[QImage::NImageFormats] = @@ -824,9 +1077,9 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = destFetch64, // Format_Mono, destFetch64, // Format_MonoLSB 0, // Format_Indexed8 - destFetch64, // Format_RGB32 - destFetch64ARGB32, // Format_ARGB32, - destFetch64, // Format_ARGB32_Premultiplied + destFetch64uint32, // Format_RGB32 + destFetch64uint32, // Format_ARGB32, + destFetch64uint32, // Format_ARGB32_Premultiplied destFetch64, // Format_RGB16 destFetch64, // Format_ARGB8565_Premultiplied destFetch64, // Format_RGB666 @@ -836,13 +1089,13 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = destFetch64, // Format_RGB888 destFetch64, // Format_RGB444 destFetch64, // Format_ARGB4444_Premultiplied - destFetch64, // Format_RGBX8888 - destFetch64, // Format_RGBA8888 - destFetch64, // Format_RGBA8888_Premultiplied - destFetch64RGB30<PixelOrderBGR>, // Format_BGR30 - destFetch64RGB30<PixelOrderBGR>, // Format_A2BGR30_Premultiplied - destFetch64RGB30<PixelOrderRGB>, // Format_RGB30 - destFetch64RGB30<PixelOrderRGB>, // Format_A2RGB30_Premultiplied + destFetch64uint32, // Format_RGBX8888 + destFetch64uint32, // Format_RGBA8888 + destFetch64uint32, // Format_RGBA8888_Premultiplied + destFetch64uint32, // Format_BGR30 + destFetch64uint32, // Format_A2BGR30_Premultiplied + destFetch64uint32, // Format_RGB30 + destFetch64uint32, // Format_A2RGB30_Premultiplied destFetch64, // Format_Alpha8 destFetch64, // Format_Grayscale8 }; @@ -991,6 +1244,40 @@ static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, c } } +#ifdef __SSE2__ +template<QtPixelOrder PixelOrder> +static inline void qConvertARGB64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count) +{ + const __m128i gmask = _mm_set1_epi32(0x000ffc00); + const __m128i cmask = _mm_set1_epi32(0x000003ff); + int i = 0; + __m128i vr, vg, vb, va; + for (; i < count-1; i += 2) { + __m128i vs = _mm_loadu_si128((const __m128i*)buffer); + buffer += 2; + vr = _mm_srli_epi64(vs, 6); + vg = _mm_srli_epi64(vs, 16 + 6 - 10); + vb = _mm_srli_epi64(vs, 32 + 6); + vr = _mm_and_si128(vr, cmask); + vg = _mm_and_si128(vg, gmask); + vb = _mm_and_si128(vb, cmask); + va = _mm_srli_epi64(vs, 48 + 14); + if (PixelOrder == PixelOrderRGB) + vr = _mm_slli_epi32(vr, 20); + else + vb = _mm_slli_epi32(vb, 20); + va = _mm_slli_epi32(va, 30); + __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va)); + vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0)); + _mm_storel_epi64((__m128i*)dest, vd); + dest += 2; + } + + for (; i < count; ++i) + *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++); +} +#endif + static void QT_FASTCALL destStore64ARGB32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) { uint *dest = (uint*)rasterBuffer->scanLine(y) + x; @@ -999,13 +1286,25 @@ static void QT_FASTCALL destStore64ARGB32(QRasterBuffer *rasterBuffer, int x, in } } +static void QT_FASTCALL destStore64RGBA8888(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + uint *dest = (uint*)rasterBuffer->scanLine(y) + x; + for (int i = 0; i < length; ++i) { + dest[i] = ARGB2RGBA(buffer[i].unpremultiplied().toArgb32()); + } +} + template<QtPixelOrder PixelOrder> static void QT_FASTCALL destStore64RGB30(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) { uint *dest = (uint*)rasterBuffer->scanLine(y) + x; +#ifdef __SSE2__ + qConvertARGB64PMToA2RGB30PM_sse2<PixelOrder>(dest, buffer, length); +#else for (int i = 0; i < length; ++i) { dest[i] = qConvertRgb64ToRgb30<PixelOrder>(buffer[i]); } +#endif } static DestStoreProc destStoreProc[QImage::NImageFormats] = @@ -1056,7 +1355,7 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = destStore64, // Format_RGB444 destStore64, // Format_ARGB4444_Premultiplied destStore64, // Format_RGBX8888 - destStore64, // Format_RGBA8888 + destStore64RGBA8888, // Format_RGBA8888 destStore64, // Format_RGBA8888_Premultiplied destStore64RGB30<PixelOrderBGR>, // Format_BGR30 destStore64RGB30<PixelOrderBGR>, // Format_A2BGR30_Premultiplied @@ -1121,6 +1420,21 @@ static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Opera return buffer; } +static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Operator *, + const QSpanData *data, int y, int x, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + if (layout->bpp != QPixelLayout::BPP32) { + uint buffer32[buffer_size]; + const uint *ptr = qFetchPixels[layout->bpp](buffer32, data->texture.scanLine(y), x, length); + return layout->convertToARGB64PM(buffer, ptr, length, layout, clut); + } else { + const uint *src = (const uint *)data->texture.scanLine(y) + x; + return layout->convertToARGB64PM(buffer, src, length, layout, clut); + } +} + // blendType is either BlendTransformed or BlendTransformedTiled template<TextureBlendType blendType> static const uint *QT_FASTCALL fetchTransformedARGB32PM(uint *buffer, const Operator *, const QSpanData *data, @@ -1288,6 +1602,111 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, return layout->convertToARGB32PM(buffer, buffer, length, layout, clut); } +template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */ +static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) +{ + int image_width = data->texture.width; + int image_height = data->texture.height; + + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); + + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + + uint buffer32[buffer_size]; + QRgba64 *b = buffer; + if (data->fast_matrix) { + // The increment pr x in the scanline + int fdx = (int)(data->m11 * fixed_scale); + int fdy = (int)(data->m12 * fixed_scale); + + int fx = int((data->m21 * cy + + data->m11 * cx + data->dx) * fixed_scale); + int fy = int((data->m22 * cy + + data->m12 * cx + data->dy) * fixed_scale); + + int i = 0, j = 0; + while (i < length) { + if (j == buffer_size) { + layout->convertToARGB64PM(b, buffer32, buffer_size, layout, clut); + b += buffer_size; + j = 0; + } + int px = fx >> 16; + int py = fy >> 16; + + if (blendType == BlendTransformedTiled) { + px %= image_width; + py %= image_height; + if (px < 0) px += image_width; + if (py < 0) py += image_height; + } else { + px = qBound(0, px, image_width - 1); + py = qBound(0, py, image_height - 1); + } + buffer32[j] = fetch(data->texture.scanLine(py), px); + + fx += fdx; + fy += fdy; + ++i; ++j; + } + if (j > 0) { + layout->convertToARGB64PM(b, buffer32, j, layout, clut); + b += j; + } + } else { + const qreal fdx = data->m11; + const qreal fdy = data->m12; + const qreal fdw = data->m13; + + qreal fx = data->m21 * cy + data->m11 * cx + data->dx; + qreal fy = data->m22 * cy + data->m12 * cx + data->dy; + qreal fw = data->m23 * cy + data->m13 * cx + data->m33; + + int i = 0, j = 0; + while (i < length) { + if (j == buffer_size) { + layout->convertToARGB64PM(b, buffer32, buffer_size, layout, clut); + b += buffer_size; + j = 0; + } + const qreal iw = fw == 0 ? 1 : 1 / fw; + const qreal tx = fx * iw; + const qreal ty = fy * iw; + int px = int(tx) - (tx < 0); + int py = int(ty) - (ty < 0); + + if (blendType == BlendTransformedTiled) { + px %= image_width; + py %= image_height; + if (px < 0) px += image_width; + if (py < 0) py += image_height; + } else { + px = qBound(0, px, image_width - 1); + py = qBound(0, py, image_height - 1); + } + buffer32[j] = fetch(data->texture.scanLine(py), px); + + fx += fdx; + fy += fdy; + fw += fdw; + //force increment to avoid /0 + if (!fw) { + fw += fdw; + } + ++i; ++j; + } + if (j > 0) { + layout->convertToARGB64PM(b, buffer32, j, layout, clut); + b += j; + } + } + return buffer; +} + /** \internal interpolate 4 argb pixels with the distx and disty factor. distx and disty bust be between 0 and 16 @@ -1379,43 +1798,41 @@ static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, i #endif #if defined(__SSE2__) -static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) -{ - // First interpolate right and left pixels in parallel. - __m128i vl = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tl), _mm_cvtsi32_si128(bl)); - __m128i vr = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tr), _mm_cvtsi32_si128(br)); - vl = _mm_unpacklo_epi8(vl, _mm_setzero_si128()); - vr = _mm_unpacklo_epi8(vr, _mm_setzero_si128()); - vl = _mm_mullo_epi16(vl, _mm_set1_epi16(256 - distx)); - vr = _mm_mullo_epi16(vr, _mm_set1_epi16(distx)); - __m128i vtb = _mm_add_epi16(vl, vr); - vtb = _mm_srli_epi16(vtb, 8); - // vtb now contains the result of the first two interpolate calls vtb = unpacked((xbot << 64) | xtop) - - // Now the last interpolate between top and bottom interpolations. - const __m128i vidisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(256 - disty), _MM_SHUFFLE(0, 0, 0, 0)); - const __m128i vdisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(disty), _MM_SHUFFLE(0, 0, 0, 0)); - const __m128i vmuly = _mm_unpacklo_epi16(vidisty, vdisty); - vtb = _mm_unpacklo_epi16(vtb, _mm_srli_si128(vtb, 8)); - // vtb now contains the colors of top and bottom interleaved { ta, ba, tr, br, tg, bg, tb, bb } - vtb = _mm_madd_epi16(vtb, vmuly); // Multiply and horizontal add. - vtb = _mm_srli_epi32(vtb, 8); - vtb = _mm_packs_epi32(vtb, _mm_setzero_si128()); - vtb = _mm_packus_epi16(vtb, _mm_setzero_si128()); - return _mm_cvtsi128_si32(vtb); +static inline QRgba64 interpolate_4_pixels_rgb64(QRgba64 t[], QRgba64 b[], uint distx, uint disty) +{ + const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0)); + + __m128i vt = _mm_loadu_si128((const __m128i*)t); + if (disty) { + __m128i vb = _mm_loadu_si128((const __m128i*)b); + vt = _mm_mulhi_epu16(vt, _mm_set1_epi16(0x10000 - disty)); + vb = _mm_mulhi_epu16(vb, _mm_set1_epi16(disty)); + vt = _mm_add_epi16(vt, vb); + } + vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx)); + vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8)); +#ifdef Q_PROCESSOR_X86_64 + return QRgba64::fromRgba64(_mm_cvtsi128_si64(vt)); +#else + QRgba64 out; + _mm_storel_epi64((__m128i*)&out, vt); + return out; +#endif } #else -static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +static inline QRgba64 interpolate_4_pixels_rgb64(QRgba64 t[], QRgba64 b[], uint distx, uint disty) { - uint idistx = 256 - distx; - uint idisty = 256 - disty; - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - return INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); + const uint dx = distx>>8; + const uint dy = disty>>8; + const uint idx = 256 - dx; + const uint idy = 256 - dy; + QRgba64 xtop = interpolate256(t[0], idx, t[1], dx); + QRgba64 xbot = interpolate256(b[0], idx, b[1], dx); + return interpolate256(xtop, idy, xbot, dy); } #endif - template<TextureBlendType blendType> void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2); @@ -2102,10 +2519,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper int x2; fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; } @@ -2160,10 +2584,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper const uchar *s1 = data->texture.scanLine(y1); const uchar *s2 = data->texture.scanLine(y2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; fy += fdy; @@ -2245,10 +2676,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper const uchar *s1 = data->texture.scanLine(y1); const uchar *s2 = data->texture.scanLine(y2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; fy += fdy; @@ -2280,6 +2718,349 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper return buffer; } +template<TextureBlendType blendType> +static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, const Operator *, + const QSpanData *data, int y, int x, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + + int image_width = data->texture.width; + int image_height = data->texture.height; + + int image_x1 = data->texture.x1; + int image_y1 = data->texture.y1; + int image_x2 = data->texture.x2 - 1; + int image_y2 = data->texture.y2 - 1; + + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); + + const qreal fdx = data->m11; + const qreal fdy = data->m12; + const qreal fdw = data->m13; + + if (data->fast_matrix) { + // The increment pr x in the scanline + int fdx = (int)(data->m11 * fixed_scale); + int fdy = (int)(data->m12 * fixed_scale); + + int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale); + int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale); + + fx -= half_point; + fy -= half_point; + + if (fdy == 0) { //simple scale, no rotation + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *b = buffer; + while (length) { + int len = qMin(length, buffer_size / 2); + int fracX = fx; + int i = 0; + int disty = (fy & 0x0000ffff); +#if defined(__SSE2__) + const __m128i vdy = _mm_set1_epi16(disty); + const __m128i vidy = _mm_set1_epi16(0x10000 - disty); + if (blendType != BlendTransformedBilinearTiled && layout->bpp == QPixelLayout::BPP32) { + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + if (x1 != x2) + break; + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + fx += fdx; + } + + const __m128i v_fdx = _mm_set1_epi32(fdx*4); + __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx); + for (; i < len-3; i+=4) { + int offset = _mm_extract_epi16(v_fx, 1); + sbuf1[i * 2 + 0] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 3); + sbuf1[i * 2 + 2] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 3] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 2] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 3] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 5); + sbuf1[i * 2 + 4] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 5] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 4] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 5] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 7); + sbuf1[i * 2 + 6] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 7] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 6] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 7] = ((const uint*)s2)[offset + 1]; + v_fx = _mm_add_epi32(v_fx, v_fdx); + } + fx = _mm_cvtsi128_si32(v_fx); + } +#endif + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + } + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + if (disty) + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = (fracX & 0x0000ffff); +#if defined(__SSE2__) + const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0)); + __m128i vt = _mm_loadu_si128((const __m128i*)(buf1 + i*2)); + if (disty) { + __m128i vb = _mm_loadu_si128((const __m128i*)(buf2 + i*2)); + vt = _mm_mulhi_epu16(vt, vidy); + vb = _mm_mulhi_epu16(vb, vdy); + vt = _mm_add_epi16(vt, vb); + } + vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx)); + vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8)); + _mm_storel_epi64((__m128i*)(b+i), vt); +#else + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); +#endif + fracX += fdx; + } + length -= len; + b += len; + } + } else { //rotation + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *end = buffer + length; + QRgba64 *b = buffer; + + while (b < end) { + int len = qMin(length, buffer_size / 2); + int fracX = fx; + int fracY = fy; + int i = 0; +#if defined(__SSE2__) + if (blendType != BlendTransformedBilinearTiled && layout->bpp == QPixelLayout::BPP32) { + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); + if (x1 != x2 && y1 != y2) + break; + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + fx += fdx; + fy += fdy; + } + + const __m128i v_fdx = _mm_set1_epi32(fdx*4); + const __m128i v_fdy = _mm_set1_epi32(fdy*4); + __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx); + __m128i v_fy = _mm_setr_epi32(fy, fy + fdy, fy + fdy + fdy, fy + fdy + fdy + fdy); + const int bytesPerLine = data->texture.bytesPerLine; + const uchar *s1 = data->texture.imageData; + const uchar *s2 = s1 + bytesPerLine; + const __m128i vbpl = _mm_shufflelo_epi16(_mm_cvtsi32_si128(bytesPerLine/4), _MM_SHUFFLE(0, 0, 0, 0)); + for (; i < len-3; i+=4) { + if (fdx > 0 && (short)_mm_extract_epi16(v_fx, 7) >= image_x2) + break; + if (fdx < 0 && (short)_mm_extract_epi16(v_fx, 7) < image_x1) + break; + if (fdy > 0 && (short)_mm_extract_epi16(v_fy, 7) >= image_y2) + break; + if (fdy < 0 && (short)_mm_extract_epi16(v_fy, 7) < image_y1) + break; + const __m128i vy = _mm_packs_epi32(_mm_srai_epi32(v_fy, 16), _mm_setzero_si128()); + __m128i voffset = _mm_unpacklo_epi16(_mm_mullo_epi16(vy, vbpl), _mm_mulhi_epu16(vy, vbpl)); + voffset = _mm_add_epi32(voffset, _mm_srli_epi32(v_fx, 16)); + + int offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 0] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 2] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 3] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 2] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 3] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 4] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 5] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 4] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 5] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); + sbuf1[i * 2 + 6] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 7] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 6] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 7] = ((const uint*)s2)[offset + 1]; + + v_fx = _mm_add_epi32(v_fx, v_fdx); + v_fy = _mm_add_epi32(v_fy, v_fdy); + } + fx = _mm_cvtsi128_si32(v_fx); + fy = _mm_cvtsi128_si32(v_fy); + } +#endif + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); + + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + fy += fdy; + } + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = (fracX & 0x0000ffff); + int disty = (fracY & 0x0000ffff); + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); + fracX += fdx; + fracY += fdy; + } + + length -= len; + b += len; + } + } + } else { + qreal fx = data->m21 * cy + data->m11 * cx + data->dx; + qreal fy = data->m22 * cy + data->m12 * cx + data->dy; + qreal fw = data->m23 * cy + data->m13 * cx + data->m33; + + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *b = buffer; + + int distxs[buffer_size / 2]; + int distys[buffer_size / 2]; + + while (length) { + int len = qMin(length, buffer_size / 2); + for (int i = 0; i < len; ++i) { + const qreal iw = fw == 0 ? 1 : 1 / fw; + const qreal px = fx * iw - qreal(0.5); + const qreal py = fy * iw - qreal(0.5); + + int x1 = int(px) - (px < 0); + int x2; + int y1 = int(py) - (py < 0); + int y2; + + distxs[i] = int((px - x1) * (1<<16)); + distys[i] = int((py - y1) * (1<<16)); + + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); + + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + fy += fdy; + fw += fdw; + //force increment to avoid /0 + if (!fw) + fw += fdw; + } + + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = distxs[i]; + int disty = distys[i]; + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); + } + + length -= len; + b += len; + } + } + + return buffer; +} + static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { // Untransformed { @@ -2448,6 +3229,174 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { }, }; +static SourceFetchProc64 sourceFetch64[NBlendTypes][QImage::NImageFormats] = { + // Untransformed + { + 0, // Invalid + fetchUntransformed64, // Mono + fetchUntransformed64, // MonoLsb + fetchUntransformed64, // Indexed8 + fetchUntransformed64, // RGB32 + fetchUntransformed64, // ARGB32 + fetchUntransformed64, // ARGB32_Premultiplied + fetchUntransformed64, // RGB16 + fetchUntransformed64, // ARGB8565_Premultiplied + fetchUntransformed64, // RGB666 + fetchUntransformed64, // ARGB6666_Premultiplied + fetchUntransformed64, // RGB555 + fetchUntransformed64, // ARGB8555_Premultiplied + fetchUntransformed64, // RGB888 + fetchUntransformed64, // RGB444 + fetchUntransformed64, // ARGB4444_Premultiplied + fetchUntransformed64, // RGBX8888 + fetchUntransformed64, // RGBA8888 + fetchUntransformed64, // RGBA8888_Premultiplied + fetchUntransformed64, // Format_BGR30 + fetchUntransformed64, // Format_A2BGR30_Premultiplied + fetchUntransformed64, // Format_RGB30 + fetchUntransformed64, // Format_A2RGB30_Premultiplied + fetchUntransformed64, // Alpha8 + fetchUntransformed64, // Grayscale8 + }, + // Tiled + { + 0, // Invalid + fetchUntransformed64, // Mono + fetchUntransformed64, // MonoLsb + fetchUntransformed64, // Indexed8 + fetchUntransformed64, // RGB32 + fetchUntransformed64, // ARGB32 + fetchUntransformed64, // ARGB32_Premultiplied + fetchUntransformed64, // RGB16 + fetchUntransformed64, // ARGB8565_Premultiplied + fetchUntransformed64, // RGB666 + fetchUntransformed64, // ARGB6666_Premultiplied + fetchUntransformed64, // RGB555 + fetchUntransformed64, // ARGB8555_Premultiplied + fetchUntransformed64, // RGB888 + fetchUntransformed64, // RGB444 + fetchUntransformed64, // ARGB4444_Premultiplied + fetchUntransformed64, // RGBX8888 + fetchUntransformed64, // RGBA8888 + fetchUntransformed64, // RGBA8888_Premultiplied + fetchUntransformed64, // BGR30 + fetchUntransformed64, // A2BGR30_Premultiplied + fetchUntransformed64, // RGB30 + fetchUntransformed64, // A2RGB30_Premultiplied + fetchUntransformed64, // Alpha8 + fetchUntransformed64, // Grayscale8 + }, + // Transformed + { + 0, // Invalid + fetchTransformed64<BlendTransformed>, // Mono + fetchTransformed64<BlendTransformed>, // MonoLsb + fetchTransformed64<BlendTransformed>, // Indexed8 + fetchTransformed64<BlendTransformed>, // RGB32 + fetchTransformed64<BlendTransformed>, // ARGB32 + fetchTransformed64<BlendTransformed>, // ARGB32_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB16 + fetchTransformed64<BlendTransformed>, // ARGB8565_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB666 + fetchTransformed64<BlendTransformed>, // ARGB6666_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB555 + fetchTransformed64<BlendTransformed>, // ARGB8555_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB888 + fetchTransformed64<BlendTransformed>, // RGB444 + fetchTransformed64<BlendTransformed>, // ARGB4444_Premultiplied + fetchTransformed64<BlendTransformed>, // RGBX8888 + fetchTransformed64<BlendTransformed>, // RGBA8888 + fetchTransformed64<BlendTransformed>, // RGBA8888_Premultiplied + fetchTransformed64<BlendTransformed>, // BGR30 + fetchTransformed64<BlendTransformed>, // A2BGR30_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB30 + fetchTransformed64<BlendTransformed>, // A2RGB30_Premultiplied + fetchTransformed64<BlendTransformed>, // Alpah8 + fetchTransformed64<BlendTransformed>, // Grayscale8 + }, + { + 0, // TransformedTiled + fetchTransformed64<BlendTransformedTiled>, // Mono + fetchTransformed64<BlendTransformedTiled>, // MonoLsb + fetchTransformed64<BlendTransformedTiled>, // Indexed8 + fetchTransformed64<BlendTransformedTiled>, // RGB32 + fetchTransformed64<BlendTransformedTiled>, // ARGB32 + fetchTransformed64<BlendTransformedTiled>, // ARGB32_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB16 + fetchTransformed64<BlendTransformedTiled>, // ARGB8565_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB666 + fetchTransformed64<BlendTransformedTiled>, // ARGB6666_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB555 + fetchTransformed64<BlendTransformedTiled>, // ARGB8555_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB888 + fetchTransformed64<BlendTransformedTiled>, // RGB444 + fetchTransformed64<BlendTransformedTiled>, // ARGB4444_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGBX8888 + fetchTransformed64<BlendTransformedTiled>, // RGBA8888 + fetchTransformed64<BlendTransformedTiled>, // RGBA8888_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // BGR30 + fetchTransformed64<BlendTransformedTiled>, // A2BGR30_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB30 + fetchTransformed64<BlendTransformedTiled>, // A2RGB30_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // Alpha8 + fetchTransformed64<BlendTransformedTiled>, // Grayscale8 + }, + { + 0, // Bilinear + fetchTransformedBilinear64<BlendTransformedBilinear>, // Mono + fetchTransformedBilinear64<BlendTransformedBilinear>, // MonoLsb + fetchTransformedBilinear64<BlendTransformedBilinear>, // Indexed8 + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB32 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB32 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB32_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB16 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB8565_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB666 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB6666_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB555 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB8555_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB888 + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB444 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB4444_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBX8888 + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBA8888 + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBA8888_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // BGR30 + fetchTransformedBilinear64<BlendTransformedBilinear>, // A2BGR30_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB30 + fetchTransformedBilinear64<BlendTransformedBilinear>, // A2RGB30_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // Alpha8 + fetchTransformedBilinear64<BlendTransformedBilinear>, // Grayscale8 + }, + { + 0, // BilinearTiled + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Mono + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // MonoLsb + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Indexed8 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB32 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB32 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB32_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB16 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB8565_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB666 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB6666_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB555 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB8555_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB888 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB444 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB4444_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBX8888 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBA8888 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBA8888_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // BGR30 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // A2BGR30_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB30 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // A2RGB30_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Alpha8 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Grayscale8 + }, +}; + #define FIXPT_BITS 8 #define FIXPT_SIZE (1<<FIXPT_BITS) @@ -2476,78 +3425,50 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q } } -static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +class GradientBase32 { - const uint *b = buffer; - qreal t, inc; - - bool affine = true; - qreal rx=0, ry=0; - if (op->linear.l == 0) { - t = inc = 0; - } else { - rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx; - ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy; - t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off; - inc = op->linear.dx * data->m11 + op->linear.dy * data->m12; - affine = !data->m13 && !data->m23; - - if (affine) { - t *= (GRADIENT_STOPTABLE_SIZE - 1); - inc *= (GRADIENT_STOPTABLE_SIZE - 1); - } +public: + typedef uint Type; + static Type null() { return 0; } + static Type fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel(&gradient, v); } - - const uint *end = buffer + length; - if (affine) { - if (inc > qreal(-1e-5) && inc < qreal(1e-5)) { - QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE))); - } else { - if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) && - t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) { - // we can use fixed point math - int t_fixed = int(t * FIXPT_SIZE); - int inc_fixed = int(inc * FIXPT_SIZE); - while (buffer < end) { - *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed); - t_fixed += inc_fixed; - ++buffer; - } - } else { - // we have to fall back to float math - while (buffer < end) { - *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE); - t += inc; - ++buffer; - } - } - } - } else { // fall back to float math here as well - qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33; - while (buffer < end) { - qreal x = rx/rw; - qreal y = ry/rw; - t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off; - - *buffer = qt_gradient_pixel(&data->gradient, t); - rx += data->m11; - ry += data->m12; - rw += data->m13; - if (!rw) { - rw += data->m13; - } - ++buffer; - } + static Type fetchSingle(const QGradientData& gradient, int v) + { + return qt_gradient_pixel_fixed(&gradient, v); } + static void memfill(Type *buffer, Type fill, int length) + { + qt_memfill32(buffer, fill, length); + } +}; - return b; -} +class GradientBase64 +{ +public: + typedef QRgba64 Type; + static Type null() { return QRgba64::fromRgba64(0); } + static Type fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel64(&gradient, v); + } + static Type fetchSingle(const QGradientData& gradient, int v) + { + return qt_gradient_pixel64_fixed(&gradient, v); + } + static void memfill(Type *buffer, Type fill, int length) + { + qt_memfill64((quint64*)buffer, fill, length); + } +}; -static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +template<class GradientBase, typename BlendType> +static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template( + BlendType *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) { - const QRgba64 *b = buffer; + const BlendType *b = buffer; qreal t, inc; bool affine = true; @@ -2567,11 +3488,10 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe } } - const QRgba64 *end = buffer + length; + const BlendType *end = buffer + length; if (affine) { if (inc > qreal(-1e-5) && inc < qreal(1e-5)) { - QRgba64 color = qt_gradient_pixel64_fixed(&data->gradient, int(t * FIXPT_SIZE)); - qt_memfill64((quint64*)buffer, color, length); + GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length); } else { if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) && t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) { @@ -2579,14 +3499,14 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe int t_fixed = int(t * FIXPT_SIZE); int inc_fixed = int(inc * FIXPT_SIZE); while (buffer < end) { - *buffer = qt_gradient_pixel64_fixed(&data->gradient, t_fixed); + *buffer = GradientBase::fetchSingle(data->gradient, t_fixed); t_fixed += inc_fixed; ++buffer; } } else { // we have to fall back to float math while (buffer < end) { - *buffer = qt_gradient_pixel64(&data->gradient, t/GRADIENT_STOPTABLE_SIZE); + *buffer = GradientBase::fetchSingle(data->gradient, t/GRADIENT_STOPTABLE_SIZE); t += inc; ++buffer; } @@ -2599,7 +3519,7 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe qreal y = ry/rw; t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off; - *buffer = qt_gradient_pixel64(&data->gradient, t); + *buffer = GradientBase::fetchSingle(data->gradient, t); rx += data->m11; ry += data->m12; rw += data->m13; @@ -2613,6 +3533,18 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe return b; } +static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_linear_gradient_template<GradientBase32, uint>(buffer, op, data, y, x, length); +} + +static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_linear_gradient_template<GradientBase64, QRgba64>(buffer, op, data, y, x, length); +} + static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data) { v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x; @@ -2627,19 +3559,22 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0; } -class RadialFetchPlain +template <class GradientBase> +class RadialFetchPlain : public GradientBase { public: - static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, - qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) + typedef typename GradientBase::Type BlendType; + static void fetch(BlendType *buffer, BlendType *end, + const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) { if (op->radial.extended) { while (buffer < end) { - quint32 result = 0; + BlendType result = GradientBase::null(); if (det >= 0) { qreal w = qSqrt(det) - b; if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0) - result = qt_gradient_pixel(&data->gradient, w); + result = GradientBase::fetchSingle(data->gradient, w); } *buffer = result; @@ -2652,7 +3587,7 @@ public: } } else { while (buffer < end) { - *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b); + *buffer++ = GradientBase::fetchSingle(data->gradient, qSqrt(det) - b); det += delta_det; delta_det += delta_delta_det; @@ -2665,15 +3600,23 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase32>, uint>(buffer, op, data, y, x, length); } static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain; -static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, - int y, int x, int length) +const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) { - const uint *b = buffer; + return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase64>, QRgba64>(buffer, op, data, y, x, length); +} + +template <class GradientBase, typename BlendType> +static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template( + BlendType *buffer, const QSpanData *data, + int y, int x, int length) +{ + const BlendType *b = buffer; qreal rx = data->m21 * (y + qreal(0.5)) + data->dx + data->m11 * (x + qreal(0.5)); qreal ry = data->m22 * (y + qreal(0.5)) @@ -2682,14 +3625,14 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op const qreal inv2pi = M_1_PI / 2.0; - const uint *end = buffer + length; + const BlendType *end = buffer + length; if (affine) { rx -= data->gradient.conical.center.x; ry -= data->gradient.conical.center.y; while (buffer < end) { qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle; - *buffer = qt_gradient_pixel(&data->gradient, 1 - angle * inv2pi); + *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi); rx += data->m11; ry += data->m12; @@ -2705,7 +3648,7 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op rx/rw - data->gradient.conical.center.y) + data->gradient.conical.angle; - *buffer = qt_gradient_pixel(&data->gradient, 1 - angle * inv2pi); + *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi); rx += data->m11; ry += data->m12; @@ -2719,1905 +3662,29 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op return b; } -# define PRELOAD_INIT(x) -# define PRELOAD_INIT2(x,y) -# define PRELOAD_COND(x) -# define PRELOAD_COND2(x,y) - -/* The constant alpha factor describes an alpha factor that gets applied - to the result of the composition operation combining it with the destination. - - The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1. - we get the unmodified operation - - result = src op dest - dest = result * const_alpha + dest * (1. - const_alpha) - - This means that in the comments below, the first line is the const_alpha==255 case, the - second line the general one. - - In the lines below: - s == src, sa == alpha(src), sia = 1 - alpha(src) - d == dest, da == alpha(dest), dia = 1 - alpha(dest) - ca = const_alpha, cia = 1 - const_alpha - - The methods exist in two variants. One where we have a constant source, the other - where the source is an array of pixels. -*/ - -/* - result = 0 - d = d * cia -*/ -#define comp_func_Clear_impl(dest, length, const_alpha)\ -{\ - if (const_alpha == 255) {\ - QT_MEMFILL_UINT(dest, length, 0);\ - } else {\ - int ialpha = 255 - const_alpha;\ - PRELOAD_INIT(dest)\ - for (int i = 0; i < length; ++i) {\ - PRELOAD_COND(dest)\ - dest[i] = BYTE_MUL(dest[i], ialpha);\ - }\ - }\ -} - -void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha) -{ - comp_func_Clear_impl(dest, length, const_alpha); -} - -void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha) -{ - if (const_alpha == 255) - qt_memfill64((quint64*)dest, 0, length); - else { - int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha255(dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) -{ - comp_func_Clear_impl(dest, length, const_alpha); -} - -void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int length, uint const_alpha) -{ - if (const_alpha == 255) - qt_memfill64((quint64*)dest, 0, length); - else { - int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha255(dest[i], ialpha); - } - } -} - -/* - result = s - dest = s * ca + d * cia -*/ -void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) { - QT_MEMFILL_UINT(dest, length, color); - } else { - int ialpha = 255 - const_alpha; - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = color + BYTE_MUL(dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha == 255) - qt_memfill64((quint64*)dest, color, length); - else { - int ialpha = 255 - const_alpha; - color = multiplyAlpha255(color, const_alpha); - for (int i = 0; i < length; ++i) { - dest[i] = color + multiplyAlpha255(dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - ::memcpy(dest, src, length * sizeof(uint)); - } else { - int ialpha = 255 - const_alpha; - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - ::memcpy(dest, src, length * sizeof(quint64)); - else { - int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = interpolate255(src[i], const_alpha, dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint) -{ -} - -void QT_FASTCALL comp_func_solid_Destination_rgb64(QRgba64 *, int, QRgba64, uint) -{ -} - -void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint) -{ -} - -void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, uint) -{ -} - -/* - result = s + d * sia - dest = (s + d * sia) * ca + d * cia - = s * ca + d * (sia * ca + cia) - = s * ca + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha) -{ - if ((const_alpha & qAlpha(color)) == 255) { - QT_MEMFILL_UINT(dest, length, color); - } else { - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); - } - } -} - -void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha == 255 && color.isOpaque()) { - qt_memfill64((quint64*)dest, color, length); - } else { - if (const_alpha != 255) - color = multiplyAlpha255(color, const_alpha); - for (int i = 0; i < length; ++i) { - dest[i] = color + multiplyAlpha65535(dest[i], 65535 - color.alpha()); - } - } -} - -void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - if (s >= 0xff000000) - dest[i] = s; - else if (s != 0) - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); - } - } -} - -void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 s = src[i]; - if (s.isOpaque()) - dest[i] = s; - else if (!s.isTransparent()) - dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 s = multiplyAlpha255(src[i], const_alpha); - dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); - } - } -} - -/* - result = d + s * dia - dest = (d + s * dia) * ca + d * cia - = d + s * dia * ca -*/ -void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = d + BYTE_MUL(color, qAlpha(~d)); - } -} - -void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha != 255) - color = multiplyAlpha255(color, const_alpha); - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = d + multiplyAlpha65535(color, 65535 - d.alpha()); - } -} - -void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = d + BYTE_MUL(s, qAlpha(~d)); - } - } -} - -void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = d + multiplyAlpha65535(src[i], 65535 - d.alpha()); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - QRgba64 s = multiplyAlpha255(src[i], const_alpha); - dest[i] = d + multiplyAlpha65535(s, 65535 - d.alpha()); - } - } -} - -/* - result = s * da - dest = s * da * ca + d * cia -*/ -void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) -{ - PRELOAD_INIT(dest) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(color, qAlpha(dest[i])); - } - } else { - color = BYTE_MUL(color, const_alpha); - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); - } - } -} - -void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); - } - } else { - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); - } - } -} - -/* - result = d * sa - dest = d * sa * ca + d * cia - = d * (sa * ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(color); - if (const_alpha != 255) { - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - } - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(dest[i], a); - } -} - -void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], a); - } - } -} - -/* - result = s * dia - dest = s * dia * ca + d * cia -*/ - -void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) -{ - PRELOAD_INIT(dest) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); - } - } else { - color = BYTE_MUL(color, const_alpha); - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); - } - } -} - -void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); - } - } -} - -/* - result = d * sia - dest = d * sia * ca + d * cia - = d * (sia * ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(~color); - if (const_alpha != 255) - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(dest[i], a); - } -} - -void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], sia); - } - } -} - -/* - result = s*da + d*sia - dest = s*da*ca + d*sia*ca + d *cia - = s*ca * da + d * (sia*ca + cia) - = s*ca * da + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) { - color = BYTE_MUL(color, const_alpha); - } - uint sia = qAlpha(~color); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); - } -} - -void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); - } - } -} - -/* - result = d*sa + s*dia - dest = d*sa*ca + s*dia*ca + d *cia - = s*ca * dia + d * (sa*ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(color); - if (const_alpha != 255) { - color = BYTE_MUL(color, const_alpha); - a = qAlpha(color) + 255 - const_alpha; - } - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); - } -} - -void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - uint a = qAlpha(s) + cia; - dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d)); - } - } -} - -/* - result = d*sia + s*dia - dest = d*sia*ca + s*dia*ca + d *cia - = s*ca * dia + d * (sia*ca + cia) - = s*ca * dia + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - uint sia = qAlpha(~color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); - } -} - -void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); - } - } -} - -struct QFullCoverage { - inline void store(uint *dest, const uint src) const - { - *dest = src; - } -}; - -struct QPartialCoverage { - inline QPartialCoverage(uint const_alpha) - : ca(const_alpha) - , ica(255 - const_alpha) - { - } - - inline void store(uint *dest, const uint src) const - { - *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica); - } - -private: - const uint ca; - const uint ica; -}; - -static inline int mix_alpha(int da, int sa) -{ - return 255 - ((255 - sa) * (255 - da) >> 8); -} - -/* - Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca -*/ -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage) -{ - uint s = color; - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - d = comp_func_Plus_one_pixel(d, s); - coverage.store(&dest[i], d); - } -} - -void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Plus_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - d = comp_func_Plus_one_pixel(d, s); - - coverage.store(&dest[i], d); - } -} - -void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Plus_impl(dest, src, length, QFullCoverage()); - else - comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int multiply_op(int dst, int src, int da, int sa) -{ - return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) multiply_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) multiply_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Multiply_impl(dest, src, length, QFullCoverage()); - else - comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca - Sca.Dca -*/ -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) 255 - qt_div_255((255-a) * (255-b)) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Screen_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Screen_impl(dest, src, length, QFullCoverage()); - else - comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Dca < Da - Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int overlay_op(int dst, int src, int da, int sa) -{ - const int temp = src * (255 - da) + dst * (255 - sa); - if (2 * dst < da) - return qt_div_255(2 * src * dst + temp); - else - return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) overlay_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) overlay_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Overlay_impl(dest, src, length, QFullCoverage()); - else - comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - Da' = Sa + Da - Sa.Da -*/ -static inline int darken_op(int dst, int src, int da, int sa) -{ - return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) darken_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Darken_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) darken_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Darken_impl(dest, src, length, QFullCoverage()); - else - comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - Da' = Sa + Da - Sa.Da -*/ -static inline int lighten_op(int dst, int src, int da, int sa) -{ - return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) lighten_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) lighten_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Lighten_impl(dest, src, length, QFullCoverage()); - else - comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if Sca.Da + Dca.Sa >= Sa.Da - Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int color_dodge_op(int dst, int src, int da, int sa) -{ - const int sa_da = sa * da; - const int dst_sa = dst * sa; - const int src_da = src * da; - - const int temp = src * (255 - da) + dst * (255 - sa); - if (src_da + dst_sa >= sa_da) - return qt_div_255(sa_da + temp); - else - return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a,b) color_dodge_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) color_dodge_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_ColorDodge_impl(dest, src, length, QFullCoverage()); - else - comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if Sca.Da + Dca.Sa <= Sa.Da - Dca' = Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int color_burn_op(int dst, int src, int da, int sa) -{ - const int src_da = src * da; - const int dst_sa = dst * sa; - const int sa_da = sa * da; - - const int temp = src * (255 - da) + dst * (255 - sa); - - if (src == 0 || src_da + dst_sa <= sa_da) - return qt_div_255(temp); - return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) color_burn_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) color_burn_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_ColorBurn_impl(dest, src, length, QFullCoverage()); - else - comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Sca < Sa - Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline uint hardlight_op(int dst, int src, int da, int sa) -{ - const uint temp = src * (255 - da) + dst * (255 - sa); - - if (2 * src < sa) - return qt_div_255(2 * src * dst + temp); - else - return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) hardlight_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) hardlight_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_HardLight_impl(dest, src, length, QFullCoverage()); - else - comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Sca <= Sa - Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise if 2.Sca > Sa and 4.Dca <= Da - Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise if 2.Sca > Sa and 4.Dca > Da - Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int soft_light_op(int dst, int src, int da, int sa) -{ - const int src2 = src << 1; - const int dst_np = da != 0 ? (255 * dst) / da : 0; - const int temp = (src * (255 - da) + dst * (255 - sa)) * 255; - - if (src2 < sa) - return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025; - else if (4 * dst <= da) - return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025; - else { - return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; - } -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) soft_light_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) soft_light_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_SoftLight_impl(dest, src, length, QFullCoverage()); - else - comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca - 2.min(Sca.Da, Dca.Sa) -*/ -static inline int difference_op(int dst, int src, int da, int sa) -{ - return src + dst - qt_div_255(2 * qMin(src * da, dst * sa)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) difference_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Difference_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) difference_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Difference_impl(dest, src, length, QFullCoverage()); - else - comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) (a + b - qt_div_255(2*(a*b))) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) (a + b - ((a*b) >> 7)) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Exclusion_impl(dest, src, length, QFullCoverage()); - else - comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ |= color; -} - -void QT_FASTCALL rasterop_SourceOrDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ |= *src++; -} - -void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color |= 0xff000000; - while (length--) - *dest++ &= color; -} - -void QT_FASTCALL rasterop_SourceAndDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src & *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color &= 0x00ffffff; - while (length--) - *dest++ ^= color; -} - -void QT_FASTCALL rasterop_SourceXorDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src ^ *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color; - while (length--) { - *dest = (color & ~(*dest)) | 0xff000000; - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) & ~(*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) { - *dest = color | ~(*dest); - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = ~(*src) | ~(*dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color & 0x00ffffff; - while (length--) { - *dest = color ^ (*dest); - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceXorDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = ((~(*src)) ^ (*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, - uint color, uint const_alpha) -{ - Q_UNUSED(const_alpha); - qt_memfill(dest, ~color | 0xff000000, length); -} - -void QT_FASTCALL rasterop_NotSource(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, - int length, uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ = ~(*src++) | 0xff000000; -} - -void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) { - *dest = color & *dest; - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceAndDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) & *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (color & ~(*dest)) | 0xff000000; - ++dest; - } -} - -void QT_FASTCALL rasterop_SourceAndNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src & ~(*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) +static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) { - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) | *dest) | 0xff000000; - ++dest; ++src; - } + return qt_fetch_conical_gradient_template<GradientBase32, uint>(buffer, data, y, x, length); } -void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) +static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) { - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) - *dest++ |= color; + return qt_fetch_conical_gradient_template<GradientBase64, QRgba64>(buffer, data, y, x, length); } -void QT_FASTCALL rasterop_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src | ~(*dest)) | 0xff000000; - ++dest; ++src; - } -} +extern CompositionFunctionSolid qt_functionForModeSolid_C[]; +extern CompositionFunctionSolid64 qt_functionForModeSolid64_C[]; -void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (color | ~(*dest)) | 0xff000000; - ++dest; - } -} - -void QT_FASTCALL rasterop_ClearDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); -} - -void QT_FASTCALL rasterop_solid_ClearDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); -} - -void QT_FASTCALL rasterop_SetDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); -} - -void QT_FASTCALL rasterop_solid_SetDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); -} - -void QT_FASTCALL rasterop_NotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); -} - -void QT_FASTCALL rasterop_solid_NotDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); -} - -static CompositionFunctionSolid functionForModeSolid_C[] = { - comp_func_solid_SourceOver, - comp_func_solid_DestinationOver, - comp_func_solid_Clear, - comp_func_solid_Source, - comp_func_solid_Destination, - comp_func_solid_SourceIn, - comp_func_solid_DestinationIn, - comp_func_solid_SourceOut, - comp_func_solid_DestinationOut, - comp_func_solid_SourceAtop, - comp_func_solid_DestinationAtop, - comp_func_solid_XOR, - comp_func_solid_Plus, - comp_func_solid_Multiply, - comp_func_solid_Screen, - comp_func_solid_Overlay, - comp_func_solid_Darken, - comp_func_solid_Lighten, - comp_func_solid_ColorDodge, - comp_func_solid_ColorBurn, - comp_func_solid_HardLight, - comp_func_solid_SoftLight, - comp_func_solid_Difference, - comp_func_solid_Exclusion, - rasterop_solid_SourceOrDestination, - rasterop_solid_SourceAndDestination, - rasterop_solid_SourceXorDestination, - rasterop_solid_NotSourceAndNotDestination, - rasterop_solid_NotSourceOrNotDestination, - rasterop_solid_NotSourceXorDestination, - rasterop_solid_NotSource, - rasterop_solid_NotSourceAndDestination, - rasterop_solid_SourceAndNotDestination, - rasterop_solid_NotSourceOrDestination, - rasterop_solid_SourceOrNotDestination, - rasterop_solid_ClearDestination, - rasterop_solid_SetDestination, - rasterop_solid_NotDestination -}; +static const CompositionFunctionSolid *functionForModeSolid = qt_functionForModeSolid_C; +static const CompositionFunctionSolid64 *functionForModeSolid64 = qt_functionForModeSolid64_C; -static CompositionFunctionSolid64 functionForModeSolid64_C[] = { - comp_func_solid_SourceOver_rgb64, - comp_func_solid_DestinationOver_rgb64, - comp_func_solid_Clear_rgb64, - comp_func_solid_Source_rgb64, - comp_func_solid_Destination_rgb64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C; -static const CompositionFunctionSolid64 *functionForModeSolid64 = functionForModeSolid64_C; - -static CompositionFunction functionForMode_C[] = { - comp_func_SourceOver, - comp_func_DestinationOver, - comp_func_Clear, - comp_func_Source, - comp_func_Destination, - comp_func_SourceIn, - comp_func_DestinationIn, - comp_func_SourceOut, - comp_func_DestinationOut, - comp_func_SourceAtop, - comp_func_DestinationAtop, - comp_func_XOR, - comp_func_Plus, - comp_func_Multiply, - comp_func_Screen, - comp_func_Overlay, - comp_func_Darken, - comp_func_Lighten, - comp_func_ColorDodge, - comp_func_ColorBurn, - comp_func_HardLight, - comp_func_SoftLight, - comp_func_Difference, - comp_func_Exclusion, - rasterop_SourceOrDestination, - rasterop_SourceAndDestination, - rasterop_SourceXorDestination, - rasterop_NotSourceAndNotDestination, - rasterop_NotSourceOrNotDestination, - rasterop_NotSourceXorDestination, - rasterop_NotSource, - rasterop_NotSourceAndDestination, - rasterop_SourceAndNotDestination, - rasterop_NotSourceOrDestination, - rasterop_SourceOrNotDestination, - rasterop_ClearDestination, - rasterop_SetDestination, - rasterop_NotDestination -}; - -static CompositionFunction64 functionForMode64_C[] = { - comp_func_SourceOver_rgb64, - comp_func_DestinationOver_rgb64, - comp_func_Clear_rgb64, - comp_func_Source_rgb64, - comp_func_Destination_rgb64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; +extern CompositionFunction qt_functionForMode_C[]; +extern CompositionFunction64 qt_functionForMode64_C[]; -static const CompositionFunction *functionForMode = functionForMode_C; -static const CompositionFunction64 *functionForMode64 = functionForMode64_C; +static const CompositionFunction *functionForMode = qt_functionForMode_C; +static const CompositionFunction64 *functionForMode64 = qt_functionForMode64_C; static TextureBlendType getBlendType(const QSpanData *data) { @@ -4648,6 +3715,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in switch(data->type) { case QSpanData::Solid: solidSource = data->solid.color.isOpaque(); + op.srcFetch = 0; + op.srcFetch64 = 0; break; case QSpanData::LinearGradient: solidSource = !data->gradient.alphaColor; @@ -4659,18 +3728,20 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in solidSource = !data->gradient.alphaColor; getRadialGradientValues(&op.radial, data); op.srcFetch = qt_fetch_radial_gradient; - op.srcFetch64 = 0; //qt_fetch_radial_gradient_rgb64; + op.srcFetch64 = qt_fetch_radial_gradient_rgb64; break; case QSpanData::ConicalGradient: solidSource = !data->gradient.alphaColor; op.srcFetch = qt_fetch_conical_gradient; - op.srcFetch64 = 0; //qt_fetch_conical_gradient_rgb64; + op.srcFetch64 = qt_fetch_conical_gradient_rgb64; break; case QSpanData::Texture: - op.srcFetch = sourceFetch[getBlendType(data)][data->texture.format]; - op.srcFetch64 = 0; // sourceFetch64[getBlendType(data)][data->texture.format]; solidSource = !data->texture.hasAlpha; + op.srcFetch = sourceFetch[getBlendType(data)][data->texture.format]; + op.srcFetch64 = sourceFetch64[getBlendType(data)][data->texture.format]; + break; default: + Q_UNREACHABLE(); break; } @@ -4698,10 +3769,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in } ++spans; } - if (!alphaSpans) { + if (!alphaSpans) op.destFetch = 0; - op.destFetch64 = 0; - } } } } @@ -4795,10 +3864,9 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) int length = spans->len; while (length) { int l = qMin(buffer_size, length); - QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.funcSolid64(dest, l, color, spans->coverage); - if (op.destStore64) - op.destStore64(data->rasterBuffer, x, spans->y, dest, l); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); length -= l; x += l; } @@ -4987,7 +4055,7 @@ public: bool isSupported() const { - return op.srcFetch64 && op.func64; + return op.func64 && op.destFetch64 && op.destStore64; } const QRgba64 *fetch(int x, int y, int len) @@ -5078,7 +4146,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi QSpanData *data = reinterpret_cast<QSpanData *>(userData); Operator op = getOperator(data, spans, count); - if (!op.srcFetch64 || !op.func64) { + if (!op.func64) { qWarning() << Q_FUNC_INFO << "Unsupported blend"; return blend_untransformed_generic(count, spans, userData); } @@ -5108,10 +4176,9 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi while (length) { int l = qMin(buffer_size, length); const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); - QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); - if (op.destStore64) - op.destStore64(data->rasterBuffer, x, spans->y, dest, l); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); x += l; sx += l; length -= l; @@ -5320,7 +4387,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD QSpanData *data = reinterpret_cast<QSpanData *>(userData); Operator op = getOperator(data, spans, count); - if (!op.srcFetch64 || !op.func64) { + if (!op.func64) { qDebug("unsupported rgb64 blend"); return blend_tiled_generic(count, spans, userData); } @@ -5353,10 +4420,9 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD if (buffer_size < l) l = buffer_size; const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); - QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); - if (op.destStore64) - op.destStore64(data->rasterBuffer, x, spans->y, dest, l); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); x += l; sx += l; length -= l; @@ -6568,6 +5634,16 @@ inline static void qt_bitmapblit_rgba8888(QRasterBuffer *rasterBuffer, map, mapWidth, mapHeight, mapStride); } +template<QtPixelOrder PixelOrder> +inline static void qt_bitmapblit_rgb30(QRasterBuffer *rasterBuffer, + int x, int y, const QRgba64 &color, + const uchar *map, + int mapWidth, int mapHeight, int mapStride) +{ + qt_bitmapblit_template<quint32>(rasterBuffer, x, y, qConvertRgb64ToRgb30<PixelOrder>(color), + map, mapWidth, mapHeight, mapStride); +} + inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uchar *map, @@ -7090,7 +6166,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = { blend_color_generic_rgb64, blend_src_generic_rgb64, - 0, + qt_bitmapblit_rgb30<PixelOrderBGR>, 0, 0, qt_rectfill_rgb30<PixelOrderBGR> @@ -7099,7 +6175,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = { blend_color_generic_rgb64, blend_src_generic_rgb64, - 0, + qt_bitmapblit_rgb30<PixelOrderBGR>, 0, 0, qt_rectfill_rgb30<PixelOrderBGR> @@ -7108,7 +6184,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = { blend_color_generic_rgb64, blend_src_generic_rgb64, - 0, + qt_bitmapblit_rgb30<PixelOrderRGB>, 0, 0, qt_rectfill_rgb30<PixelOrderRGB> @@ -7117,7 +6193,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = { blend_color_generic_rgb64, blend_src_generic_rgb64, - 0, + qt_bitmapblit_rgb30<PixelOrderRGB>, 0, 0, qt_rectfill_rgb30<PixelOrderRGB> @@ -7217,9 +6293,6 @@ void qt_memfill32(quint32 *dest, quint32 color, int count) void qInitDrawhelperAsm() { - CompositionFunction *functionForModeAsm = 0; - CompositionFunctionSolid *functionForModeSolidAsm = 0; - const uint features = qCpuFeatures(); Q_UNUSED(features); #ifdef __SSE2__ @@ -7304,9 +6377,15 @@ void qInitDrawhelperAsm() qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2; } #endif + extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha); + extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2; + qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2; + qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2; - functionForModeAsm = qt_functionForMode_SSE2; - functionForModeSolidAsm = qt_functionForModeSolid_SSE2; #endif // SSE2 #if defined(__ARM_NEON__) && !defined(Q_OS_IOS) @@ -7332,9 +6411,9 @@ void qInitDrawhelperAsm() qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon; - functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; - functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon; - functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon; + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon; + qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon; destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon; destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon; @@ -7354,25 +6433,25 @@ void qInitDrawhelperAsm() #if defined(QT_COMPILER_SUPPORTS_MIPS_DSP) || defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2) if (features & (DSP | DSPR2)) { // Composition functions are all DSP r1 - functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp; - functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationOver] = comp_func_DestinationOver_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceIn] = comp_func_SourceIn_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationIn] = comp_func_DestinationIn_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationOut] = comp_func_DestinationOut_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceAtop] = comp_func_SourceAtop_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationAtop] = comp_func_DestinationAtop_mips_dsp; - functionForMode_C[QPainter::CompositionMode_Xor] = comp_func_XOR_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceOut] = comp_func_SourceOut_mips_dsp; - - functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationOver] = comp_func_solid_DestinationOver_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceIn] = comp_func_solid_SourceIn_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationIn] = comp_func_solid_DestinationIn_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceAtop] = comp_func_solid_SourceAtop_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationAtop] = comp_func_solid_DestinationAtop_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationOver] = comp_func_DestinationOver_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceIn] = comp_func_SourceIn_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationIn] = comp_func_DestinationIn_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationOut] = comp_func_DestinationOut_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceAtop] = comp_func_SourceAtop_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationAtop] = comp_func_DestinationAtop_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_Xor] = comp_func_XOR_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceOut] = comp_func_SourceOut_mips_dsp; + + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationOver] = comp_func_solid_DestinationOver_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceIn] = comp_func_solid_SourceIn_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationIn] = comp_func_solid_DestinationIn_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceAtop] = comp_func_solid_SourceAtop_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationAtop] = comp_func_solid_DestinationAtop_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp; qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp; @@ -7399,20 +6478,6 @@ void qInitDrawhelperAsm() #endif // QT_COMPILER_SUPPORTS_MIPS_DSPR2 } #endif // QT_COMPILER_SUPPORTS_MIPS_DSP || QT_COMPILER_SUPPORTS_MIPS_DSPR2 - - if (functionForModeSolidAsm) { - const int destinationMode = QPainter::CompositionMode_Destination; - functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode]; - - // use the default qdrawhelper implementation for the - // extended composition modes - for (int mode = 12; mode < 24; ++mode) - functionForModeSolidAsm[mode] = functionForModeSolid_C[mode]; - - functionForModeSolid = functionForModeSolidAsm; - } - if (functionForModeAsm) - functionForMode = functionForModeAsm; } QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 36e2488a94..08e564f017 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -986,7 +986,7 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon> >(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon>,uint>(buffer, op, data, y, x, length); } QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 501f1ce033..f8865a6f7e 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -395,24 +395,24 @@ static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) return (b * b) - (4 * a * c); } -template <class RadialFetchFunc> Q_STATIC_TEMPLATE_FUNCTION -const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +template <class RadialFetchFunc, typename BlendType> static +const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffer, const Operator *op, + const QSpanData *data, int y, int x, int length) { // avoid division by zero if (qFuzzyIsNull(op->radial.a)) { - qt_memfill32(buffer, 0, length); + RadialFetchFunc::memfill(buffer, RadialFetchFunc::null(), length); return buffer; } - const uint *b = buffer; + const BlendType *b = buffer; qreal rx = data->m21 * (y + qreal(0.5)) + data->dx + data->m11 * (x + qreal(0.5)); qreal ry = data->m22 * (y + qreal(0.5)) + data->dy + data->m12 * (x + qreal(0.5)); bool affine = !data->m13 && !data->m23; - uint *end = buffer + length; + BlendType *end = buffer + length; if (affine) { rx -= data->gradient.radial.focal.x; ry -= data->gradient.radial.focal.y; @@ -459,7 +459,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + gx*op->radial.dx + gy*op->radial.dy); qreal det = qRadialDeterminant(op->radial.a, b, op->radial.sqrfr - (gx*gx + gy*gy)); - quint32 result = 0; + BlendType result = RadialFetchFunc::null(); if (det >= 0) { qreal detSqrt = qSqrt(det); @@ -469,7 +469,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O qreal s = qMax(s0, s1); if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0) - result = qt_gradient_pixel(&data->gradient, s); + result = RadialFetchFunc::fetchSingle(data->gradient, s); } *buffer = result; @@ -490,6 +490,15 @@ template <class Simd> class QRadialFetchSimd { public: + static uint null() { return 0; } + static uint fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel(&gradient, v); + } + static void memfill(uint *buffer, uint fill, int length) + { + qt_memfill32(buffer, fill, length); + } static void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) { @@ -625,6 +634,42 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) { } #endif +#ifdef __SSE2__ +static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +{ + // First interpolate right and left pixels in parallel. + __m128i vl = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tl), _mm_cvtsi32_si128(bl)); + __m128i vr = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tr), _mm_cvtsi32_si128(br)); + vl = _mm_unpacklo_epi8(vl, _mm_setzero_si128()); + vr = _mm_unpacklo_epi8(vr, _mm_setzero_si128()); + vl = _mm_mullo_epi16(vl, _mm_set1_epi16(256 - distx)); + vr = _mm_mullo_epi16(vr, _mm_set1_epi16(distx)); + __m128i vtb = _mm_add_epi16(vl, vr); + vtb = _mm_srli_epi16(vtb, 8); + // vtb now contains the result of the first two interpolate calls vtb = unpacked((xbot << 64) | xtop) + + // Now the last interpolate between top and bottom interpolations. + const __m128i vidisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(256 - disty), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vdisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(disty), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vmuly = _mm_unpacklo_epi16(vidisty, vdisty); + vtb = _mm_unpacklo_epi16(vtb, _mm_srli_si128(vtb, 8)); + // vtb now contains the colors of top and bottom interleaved { ta, ba, tr, br, tg, bg, tb, bb } + vtb = _mm_madd_epi16(vtb, vmuly); // Multiply and horizontal add. + vtb = _mm_srli_epi32(vtb, 8); + vtb = _mm_packs_epi32(vtb, _mm_setzero_si128()); + vtb = _mm_packus_epi16(vtb, _mm_setzero_si128()); + return _mm_cvtsi128_si32(vtb); +} +#else +static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +{ + uint idistx = 256 - distx; + uint idisty = 256 - disty; + uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); + uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); + return INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); +} +#endif #if Q_BYTE_ORDER == Q_BIG_ENDIAN static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { @@ -1056,89 +1101,11 @@ inline int comp_func_Plus_one_pixel(uint d, const uint s) #undef MIX #undef AMIX -// prototypes of all the composition functions -void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha); -void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint); -void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceOrDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceAndDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceXorDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceOrDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceOrNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_ClearDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SetDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotDestination(uint *dest, const uint *src, int length, uint const_alpha); -// prototypes of all the solid composition functions -void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Destination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_ClearDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SetDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotDestination(uint *dest, int length, uint color, uint const_alpha); - - struct QPixelLayout; typedef const uint *(QT_FASTCALL *ConvertFunc)(uint *buffer, const uint *src, int count, const QPixelLayout *layout, const QRgb *clut); +typedef const QRgba64 *(QT_FASTCALL *ConvertFunc64)(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *layout, const QRgb *clut); struct QPixelLayout { @@ -1168,6 +1135,7 @@ struct QPixelLayout ConvertFunc convertToARGB32PM; ConvertFunc convertFromARGB32PM; ConvertFunc convertFromRGB32; + ConvertFunc64 convertToARGB64PM; }; typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *src, int index, int count); diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index b8957fe2fb..d7f3686e54 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -311,90 +311,6 @@ void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, u } } -#ifndef QDRAWHELPER_AVX -CompositionFunctionSolid qt_functionForModeSolid_SSE2[numCompositionFunctions] = { - comp_func_solid_SourceOver_sse2, - comp_func_solid_DestinationOver, - comp_func_solid_Clear, - comp_func_solid_Source, - comp_func_solid_Destination, - comp_func_solid_SourceIn, - comp_func_solid_DestinationIn, - comp_func_solid_SourceOut, - comp_func_solid_DestinationOut, - comp_func_solid_SourceAtop, - comp_func_solid_DestinationAtop, - comp_func_solid_XOR, - comp_func_solid_Plus, - comp_func_solid_Multiply, - comp_func_solid_Screen, - comp_func_solid_Overlay, - comp_func_solid_Darken, - comp_func_solid_Lighten, - comp_func_solid_ColorDodge, - comp_func_solid_ColorBurn, - comp_func_solid_HardLight, - comp_func_solid_SoftLight, - comp_func_solid_Difference, - comp_func_solid_Exclusion, - rasterop_solid_SourceOrDestination, - rasterop_solid_SourceAndDestination, - rasterop_solid_SourceXorDestination, - rasterop_solid_NotSourceAndNotDestination, - rasterop_solid_NotSourceOrNotDestination, - rasterop_solid_NotSourceXorDestination, - rasterop_solid_NotSource, - rasterop_solid_NotSourceAndDestination, - rasterop_solid_SourceAndNotDestination, - rasterop_solid_NotSourceOrDestination, - rasterop_solid_SourceOrNotDestination, - rasterop_solid_ClearDestination, - rasterop_solid_SetDestination, - rasterop_solid_NotDestination -}; - -CompositionFunction qt_functionForMode_SSE2[numCompositionFunctions] = { - comp_func_SourceOver_sse2, - comp_func_DestinationOver, - comp_func_Clear, - comp_func_Source_sse2, - comp_func_Destination, - comp_func_SourceIn, - comp_func_DestinationIn, - comp_func_SourceOut, - comp_func_DestinationOut, - comp_func_SourceAtop, - comp_func_DestinationAtop, - comp_func_XOR, - comp_func_Plus_sse2, - comp_func_Multiply, - comp_func_Screen, - comp_func_Overlay, - comp_func_Darken, - comp_func_Lighten, - comp_func_ColorDodge, - comp_func_ColorBurn, - comp_func_HardLight, - comp_func_SoftLight, - comp_func_Difference, - comp_func_Exclusion, - rasterop_SourceOrDestination, - rasterop_SourceAndDestination, - rasterop_SourceXorDestination, - rasterop_NotSourceAndNotDestination, - rasterop_NotSourceOrNotDestination, - rasterop_NotSourceXorDestination, - rasterop_NotSource, - rasterop_NotSourceAndDestination, - rasterop_SourceAndNotDestination, - rasterop_NotSourceOrDestination, - rasterop_SourceOrNotDestination, - rasterop_ClearDestination, - rasterop_SetDestination, - rasterop_NotDestination -}; -#endif - void qt_memfill16(quint16 *dest, quint16 value, int count) { if (count < 3) { @@ -550,7 +466,7 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2> >(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2>,uint>(buffer, op, data, y, x, length); } void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h index 4d0790a502..1a7dddf0d5 100644 --- a/src/gui/painting/qdrawingprimitive_sse2_p.h +++ b/src/gui/painting/qdrawingprimitive_sse2_p.h @@ -242,6 +242,8 @@ QT_FUNCTION_TARGET(SSE4_1) inline QRgb qUnpremultiply_sse4(QRgb p) { const uint alpha = qAlpha(p); + if (alpha == 255 || alpha == 0) + return p; const uint invAlpha = qt_inv_premul_factor[alpha]; const __m128i via = _mm_set1_epi32(invAlpha); const __m128i vr = _mm_set1_epi32(0x8000); @@ -250,8 +252,8 @@ inline QRgb qUnpremultiply_sse4(QRgb p) vl = _mm_add_epi32(vl, vr); vl = _mm_srai_epi32(vl, 16); vl = _mm_insert_epi32(vl, alpha, 3); - vl = _mm_packus_epi32(vl, _mm_setzero_si128()); - vl = _mm_packus_epi16(vl, _mm_setzero_si128()); + vl = _mm_packus_epi32(vl, vl); + vl = _mm_packus_epi16(vl, vl); return _mm_cvtsi128_si32(vl); } #endif diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 58e9112dd6..5f1b25e189 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -38,10 +38,6 @@ QT_BEGIN_NAMESPACE -namespace QImageScale { - struct QImageScaleInfo; -} - typedef void (*qt_qimageScaleFunc)(QImageScale::QImageScaleInfo *isi, unsigned int *dest, int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow); @@ -105,15 +101,7 @@ qt_qimageScaleFunc qt_qimageScaleRgb = qt_qimageScaleAARGB; namespace QImageScale { - struct QImageScaleInfo { - int *xpoints; - const unsigned int **ypoints; - int *xapoints, *yapoints; - int xup_yup; - }; - - const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, - int dh); + const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh); int* qimageCalcXPoints(int sw, int dw); int* qimageCalcApoints(int s, int d, int up); QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi); @@ -134,16 +122,11 @@ using namespace QImageScale; #define G_VAL(p) (qGreen(*p)) #define B_VAL(p) (qBlue(*p)) -#define INV_XAP (256 - xapoints[x]) -#define XAP (xapoints[x]) -#define INV_YAP (256 - yapoints[dyy + y]) -#define YAP (yapoints[dyy + y]) - const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh) { const unsigned int **p; - int i, j = 0, rv = 0; + int j = 0, rv = 0; qint64 val, inc; if(dh < 0){ @@ -155,12 +138,12 @@ const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int up = qAbs(dh) >= sh; val = up ? 0x8000 * sh / dh - 0x8000 : 0; inc = (((qint64)sh) << 16) / dh; - for(i = 0; i < dh; i++){ + for (int i = 0; i < dh; i++) { p[j++] = src + qMax(0LL, val >> 16) * sw; val += inc; } - if(rv){ - for(i = dh / 2; --i >= 0; ){ + if (rv) { + for (int i = dh / 2; --i >= 0; ) { const unsigned int *tmp = p[i]; p[i] = p[dh - i - 1]; p[dh - i - 1] = tmp; @@ -171,7 +154,7 @@ const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int* QImageScale::qimageCalcXPoints(int sw, int dw) { - int *p, i, j = 0, rv = 0; + int *p, j = 0, rv = 0; qint64 val, inc; if(dw < 0){ @@ -183,13 +166,13 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) int up = qAbs(dw) >= sw; val = up ? 0x8000 * sw / dw - 0x8000 : 0; inc = (((qint64)sw) << 16) / dw; - for(i = 0; i < dw; i++){ + for (int i = 0; i < dw; i++) { p[j++] = qMax(0LL, val >> 16); val += inc; } - if(rv){ - for(i = dw / 2; --i >= 0; ){ + if (rv) { + for (int i = dw / 2; --i >= 0; ) { int tmp = p[i]; p[i] = p[dw - i - 1]; p[dw - i - 1] = tmp; @@ -200,7 +183,7 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) int* QImageScale::qimageCalcApoints(int s, int d, int up) { - int *p, i, j = 0, rv = 0; + int *p, j = 0, rv = 0; if(d < 0){ rv = 1; @@ -214,7 +197,7 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) val = 0x8000 * s / d - 0x8000; inc = (((qint64)s) << 16) / d; - for(i = 0; i < d; i++){ + for (int i = 0; i < d; i++) { int pos = val >> 16; if (pos < 0) p[j++] = 0; @@ -226,14 +209,12 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) } } /* scaling down */ - else{ - qint64 val, inc; - int ap, Cp; - val = 0; - inc = (((qint64)s) << 16) / d; - Cp = ((d << 14) / s) + 1; - for(i = 0; i < d; i++){ - ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8; + else { + qint64 val = 0; + qint64 inc = (((qint64)s) << 16) / d; + int Cp = (((d << 14) + s - 1) / s); + for (int i = 0; i < d; i++) { + int ap = ((0x10000 - (val & 0xffff)) * Cp) >> 16; p[j] = ap | (Cp << 16); j++; val += inc; @@ -241,13 +222,13 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) } if(rv){ int tmp; - for(i = d / 2; --i >= 0; ){ + for (int i = d / 2; --i >= 0; ) { tmp = p[i]; p[i] = p[d - i - 1]; p[d - i - 1] = tmp; } } - return(p); + return p; } QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi) @@ -297,700 +278,500 @@ QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, return(isi); } -/* FIXME: NEED to optimize ScaleAARGBA - currently its "ok" but needs work*/ -/* scale by area sampling */ -static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) +template<bool RGB> +void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +template<bool RGB> +void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +template<bool RGB> +void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +#endif + +static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) { - const unsigned int *sptr; - unsigned int *dptr; - int x, y, end; const unsigned int **ypoints = isi->ypoints; int *xpoints = isi->xpoints; int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - end = dxx + dw; - /* scaling up both ways */ - if(isi->xup_yup == 3){ - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - /* calculate the source line we'll scan from */ - dptr = dest + dx + ((y + dy) * dow); - sptr = ypoints[dyy + y]; - if(YAP > 0){ - for(x = dxx; x < end; x++){ - int r, g, b, a; - int rr, gg, bb, aa; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - a = A_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - a += A_VAL(pix) * XAP; - pix += sow; - rr = R_VAL(pix) * XAP; - gg = G_VAL(pix) * XAP; - bb = B_VAL(pix) * XAP; - aa = A_VAL(pix) * XAP; - pix--; - rr += R_VAL(pix) * INV_XAP; - gg += G_VAL(pix) * INV_XAP; - bb += B_VAL(pix) * INV_XAP; - aa += A_VAL(pix) * INV_XAP; - r = ((rr * YAP) + (r * INV_YAP)) >> 16; - g = ((gg * YAP) + (g * INV_YAP)) >> 16; - b = ((bb * YAP) + (b * INV_YAP)) >> 16; - a = ((aa * YAP) + (a * INV_YAP)) >> 16; - *dptr++ = qRgba(r, g, b, a); - } - else{ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_YAP; - g = G_VAL(pix) * INV_YAP; - b = B_VAL(pix) * INV_YAP; - a = A_VAL(pix) * INV_YAP; - pix += sow; - r += R_VAL(pix) * YAP; - g += G_VAL(pix) * YAP; - b += B_VAL(pix) * YAP; - a += A_VAL(pix) * YAP; - r >>= 8; - g >>= 8; - b >>= 8; - a >>= 8; - *dptr++ = qRgba(r, g, b, a); - } - } + int end = dxx + dw; + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + /* calculate the source line we'll scan from */ + const unsigned int *sptr = ypoints[dyy + y]; + unsigned int *dptr = dest + dx + ((y + dy) * dow); + const int yap = yapoints[dyy + y]; + if (yap > 0) { + for (int x = dxx; x < end; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate_4_pixels(pix[0], pix[1], pix[sow], pix[sow + 1], xap, yap); + else + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap); + dptr++; } - else{ - for(x = dxx; x < end; x++){ - int r, g, b, a; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - a = A_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - a += A_VAL(pix) * XAP; - r >>= 8; - g >>= 8; - b >>= 8; - a >>= 8; - *dptr++ = qRgba(r, g, b, a); - } - else - *dptr++ = sptr[xpoints[x] ]; - } + } else { + for (int x = dxx; x < end; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); + dptr++; } } } +} + +/* scale by area sampling */ +static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + /* scaling up both ways */ + if (isi->xup_yup == 3){ + qt_qimageScaleAARGBA_up_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } /* if we're scaling down vertically */ - else if(isi->xup_yup == 1){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cy, j; - const unsigned int *pix; - int r, g, b, a, rr, gg, bb, aa; - int yap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * yap; - g = G_VAL(pix) * yap; - b = B_VAL(pix) * yap; - a = A_VAL(pix) * yap; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix += sow; - r += R_VAL(pix) * Cy; - g += G_VAL(pix) * Cy; - b += B_VAL(pix) * Cy; - a += A_VAL(pix) * Cy; - } - if(j > 0){ - pix += sow; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - a += A_VAL(pix) * j; - } - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + 1; - rr = R_VAL(pix) * yap; - gg = G_VAL(pix) * yap; - bb = B_VAL(pix) * yap; - aa = A_VAL(pix) * yap; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix += sow; - rr += R_VAL(pix) * Cy; - gg += G_VAL(pix) * Cy; - bb += B_VAL(pix) * Cy; - aa += A_VAL(pix) * Cy; - } - if(j > 0){ - pix += sow; - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - aa += A_VAL(pix) * j; - } - r = r * INV_XAP; - g = g * INV_XAP; - b = b * INV_XAP; - a = a * INV_XAP; - r = (r + ((rr * XAP))) >> 12; - g = (g + ((gg * XAP))) >> 12; - b = (b + ((bb * XAP))) >> 12; - a = (a + ((aa * XAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - a >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10); - dptr++; - } - } + else if (isi->xup_yup == 1) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_up_x_down_y_sse4<false>(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_up_x_down_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } /* if we're scaling down horizontally */ - else if(isi->xup_yup == 2){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, j; - const unsigned int *pix; - int r, g, b, a, rr, gg, bb, aa; - int xap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * xap; - g = G_VAL(pix) * xap; - b = B_VAL(pix) * xap; - a = A_VAL(pix) * xap; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - pix++; - r += R_VAL(pix) * Cx; - g += G_VAL(pix) * Cx; - b += B_VAL(pix) * Cx; - a += A_VAL(pix) * Cx; - } - if(j > 0){ - pix++; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - a += A_VAL(pix) * j; - } - if(YAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + sow; - rr = R_VAL(pix) * xap; - gg = G_VAL(pix) * xap; - bb = B_VAL(pix) * xap; - aa = A_VAL(pix) * xap; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - pix++; - rr += R_VAL(pix) * Cx; - gg += G_VAL(pix) * Cx; - bb += B_VAL(pix) * Cx; - aa += A_VAL(pix) * Cx; - } - if(j > 0){ - pix++; - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - aa += A_VAL(pix) * j; - } - r = r * INV_YAP; - g = g * INV_YAP; - b = b * INV_YAP; - a = a * INV_YAP; - r = (r + ((rr * YAP))) >> 12; - g = (g + ((gg * YAP))) >> 12; - b = (b + ((bb * YAP))) >> 12; - a = (a + ((aa * YAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - a >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10); - dptr++; - } - } + else if (isi->xup_yup == 2) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_x_up_y_sse4<false>(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_down_x_up_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } /* if we're scaling down horizontally & vertically */ - else{ - /*\ 'Correct' version, with math units prepared for MMXification: - |*| The operation 'b = (b * c) >> 16' translates to pmulhw, - |*| so the operation 'b = (b * c) >> d' would translate to - |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb - \*/ - int Cx, Cy, i, j; - const unsigned int *pix; - int a, r, g, b, ax, rx, gx, bx; - int xap, yap; - - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - sptr = ypoints[dyy + y] + xpoints[x]; - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r = (rx >> 5) * yap; - g = (gx >> 5) * yap; - b = (bx >> 5) * yap; - a = (ax >> 5) * yap; - - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r += (rx >> 5) * Cy; - g += (gx >> 5) * Cy; - b += (bx >> 5) * Cy; - a += (ax >> 5) * Cy; - } - if(j > 0){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r += (rx >> 5) * j; - g += (gx >> 5) * j; - b += (bx >> 5) * j; - a += (ax >> 5) * j; - } - - *dptr = qRgba(r >> 23, g >> 23, b >> 23, a >> 23); - dptr++; + else { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_xy_sse4<false>(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_down_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } +} + +inline static void qt_qimageScaleAARGBA_helper_x(const unsigned int *pix, int xap, int Cx, int &r, int &g, int &b, int &a) +{ + r = R_VAL(pix) * xap; + g = G_VAL(pix) * xap; + b = B_VAL(pix) * xap; + a = A_VAL(pix) * xap; + int j; + for (j = (1 << 14) - xap; j > Cx; j -= Cx ){ + pix++; + r += R_VAL(pix) * Cx; + g += G_VAL(pix) * Cx; + b += B_VAL(pix) * Cx; + a += A_VAL(pix) * Cx; + } + pix++; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; + a += A_VAL(pix) * j; +} + +inline static void qt_qimageScaleAARGBA_helper_y(const unsigned int *pix, int yap, int Cy, int sow, int &r, int &g, int &b, int &a) +{ + r = R_VAL(pix) * yap; + g = G_VAL(pix) * yap; + b = B_VAL(pix) * yap; + a = A_VAL(pix) * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy ){ + pix += sow; + r += R_VAL(pix) * Cy; + g += G_VAL(pix) * Cy; + b += B_VAL(pix) * Cy; + a += A_VAL(pix) * Cy; + } + pix += sow; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; + a += A_VAL(pix) * j; +} + +static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper_y(sptr, yap, Cy, sow, r, g, b, a); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper_y(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + a = a * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + a = (a + (aa * xap)) >> 8; } + *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); } } } -/* scale by area sampling - IGNORE the ALPHA byte*/ -static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) { - const unsigned int *sptr; - unsigned int *dptr; - int x, y, end; const unsigned int **ypoints = isi->ypoints; int *xpoints = isi->xpoints; int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - end = dxx + dw; - /* scaling up both ways */ - if(isi->xup_yup == 3){ - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - /* calculate the source line we'll scan from */ - dptr = dest + dx + ((y + dy) * dow); - sptr = ypoints[dyy + y]; - if(YAP > 0){ - for(x = dxx; x < end; x++){ - int r = 0, g = 0, b = 0; - int rr = 0, gg = 0, bb = 0; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - pix += sow; - rr = R_VAL(pix) * XAP; - gg = G_VAL(pix) * XAP; - bb = B_VAL(pix) * XAP; - pix --; - rr += R_VAL(pix) * INV_XAP; - gg += G_VAL(pix) * INV_XAP; - bb += B_VAL(pix) * INV_XAP; - r = ((rr * YAP) + (r * INV_YAP)) >> 16; - g = ((gg * YAP) + (g * INV_YAP)) >> 16; - b = ((bb * YAP) + (b * INV_YAP)) >> 16; - *dptr++ = qRgba(r, g, b, 0xff); - } - else{ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_YAP; - g = G_VAL(pix) * INV_YAP; - b = B_VAL(pix) * INV_YAP; - pix += sow; - r += R_VAL(pix) * YAP; - g += G_VAL(pix) * YAP; - b += B_VAL(pix) * YAP; - r >>= 8; - g >>= 8; - b >>= 8; - *dptr++ = qRgba(r, g, b, 0xff); - } - } - } - else{ - for(x = dxx; x < end; x++){ - int r = 0, g = 0, b = 0; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - r >>= 8; - g >>= 8; - b >>= 8; - *dptr++ = qRgba(r, g, b, 0xff); - } - else - *dptr++ = sptr[xpoints[x] ]; - } + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, r, g, b, a); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper_x(sptr + sow, xap, Cx, rr, gg, bb, aa); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + a = a * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + a = (a + (aa * yap)) >> 8; } + *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); + dptr++; } } - /* if we're scaling down vertically */ - else if(isi->xup_yup == 1){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cy, j; - const unsigned int *pix; - int r, g, b, rr, gg, bb; - int yap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * yap; - g = G_VAL(pix) * yap; - b = B_VAL(pix) * yap; - pix += sow; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - r += R_VAL(pix) * Cy; - g += G_VAL(pix) * Cy; - b += B_VAL(pix) * Cy; - pix += sow; - } - if(j > 0){ - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - } - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + 1; - rr = R_VAL(pix) * yap; - gg = G_VAL(pix) * yap; - bb = B_VAL(pix) * yap; - pix += sow; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - rr += R_VAL(pix) * Cy; - gg += G_VAL(pix) * Cy; - bb += B_VAL(pix) * Cy; - pix += sow; - } - if(j > 0){ - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - } - r = r * INV_XAP; - g = g * INV_XAP; - b = b * INV_XAP; - r = (r + ((rr * XAP))) >> 12; - g = (g + ((gg * XAP))) >> 12; - b = (b + ((bb * XAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff); - dptr++; +} + +static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int rx, gx, bx, ax; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + + int r = ((rx>>4) * yap); + int g = ((gx>>4) * yap); + int b = ((bx>>4) * yap); + int a = ((ax>>4) * yap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + r += ((rx>>4) * Cy); + g += ((gx>>4) * Cy); + b += ((bx>>4) * Cy); + a += ((ax>>4) * Cy); } + sptr += sow; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + + r += ((rx>>4) * j); + g += ((gx>>4) * j); + b += ((bx>>4) * j); + a += ((ax>>4) * j); + + *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24); + dptr++; } } +} + +static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +/* scale by area sampling - IGNORE the ALPHA byte*/ +static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + /* scaling up both ways */ + if (isi->xup_yup == 3) { + qt_qimageScaleAARGBA_up_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } + /* if we're scaling down vertically */ + else if (isi->xup_yup == 1) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_up_x_down_y_sse4<true>(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_up_x_down_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } /* if we're scaling down horizontally */ - else if(isi->xup_yup == 2){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, j; - const unsigned int *pix; - int r, g, b, rr, gg, bb; - int xap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * xap; - g = G_VAL(pix) * xap; - b = B_VAL(pix) * xap; - pix++; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - r += R_VAL(pix) * Cx; - g += G_VAL(pix) * Cx; - b += B_VAL(pix) * Cx; - pix++; - } - if(j > 0){ - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - } - if(YAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + sow; - rr = R_VAL(pix) * xap; - gg = G_VAL(pix) * xap; - bb = B_VAL(pix) * xap; - pix++; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - rr += R_VAL(pix) * Cx; - gg += G_VAL(pix) * Cx; - bb += B_VAL(pix) * Cx; - pix++; - } - if(j > 0){ - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - } - r = r * INV_YAP; - g = g * INV_YAP; - b = b * INV_YAP; - r = (r + ((rr * YAP))) >> 12; - g = (g + ((gg * YAP))) >> 12; - b = (b + ((bb * YAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff); - dptr++; - } - } + else if (isi->xup_yup == 2) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_x_up_y_sse4<true>(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_down_x_up_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } - /* fully optimized (i think) - onyl change of algorithm can help */ /* if we're scaling down horizontally & vertically */ - else{ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, Cy, i, j; - const unsigned int *pix; - int r, g, b, rx, gx, bx; - int xap, yap; - - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - sptr = ypoints[dyy + y] + xpoints[x]; - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r = (rx >> 5) * yap; - g = (gx >> 5) * yap; - b = (bx >> 5) * yap; - - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r += (rx >> 5) * Cy; - g += (gx >> 5) * Cy; - b += (bx >> 5) * Cy; - } - if(j > 0){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r += (rx >> 5) * j; - g += (gx >> 5) * j; - b += (bx >> 5) * j; - } - - *dptr = qRgb(r >> 23, g >> 23, b >> 23); - dptr++; + else { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_xy_sse4<true>(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_down_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } +} + + +inline static void qt_qimageScaleAARGB_helper_x(const unsigned int *pix, int xap, int Cx, int &r, int &g, int &b) +{ + r = R_VAL(pix) * xap; + g = G_VAL(pix) * xap; + b = B_VAL(pix) * xap; + int j; + for (j = (1 << 14) - xap; j > Cx; j -= Cx ){ + pix++; + r += R_VAL(pix) * Cx; + g += G_VAL(pix) * Cx; + b += B_VAL(pix) * Cx; + } + pix++; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; +} + +inline static void qt_qimageScaleAARGB_helper_y(const unsigned int *pix, int yap, int Cy, int sow, int &r, int &g, int &b) +{ + r = R_VAL(pix) * yap; + g = G_VAL(pix) * yap; + b = B_VAL(pix) * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy ){ + pix += sow; + r += R_VAL(pix) * Cy; + g += G_VAL(pix) * Cy; + b += B_VAL(pix) * Cy; + } + pix += sow; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; +} + +static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper_y(sptr, yap, Cy, sow, r, g, b); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper_y(sptr + 1, yap, Cy, sow, rr, gg, bb); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } } } -#if 0 -static void qt_qimageScaleAARGBASetup(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) { - qInitDrawhelperAsm(); - qt_qimageScaleAARGBA(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, r, g, b); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper_x(sptr + sow, xap, Cx, rr, gg, bb); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); + } + } } -static void qt_qimageScaleAARGBSetup(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) { - qInitDrawhelperAsm(); - qt_qimageScaleAARGB(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int rx, gx, bx; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + int r = (rx >> 4) * yap; + int g = (gx >> 4) * yap; + int b = (bx >> 4) * yap; + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + r += (rx >> 4) * Cy; + g += (gx >> 4) * Cy; + b += (bx >> 4) * Cy; + } + sptr += sow; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + r += (rx >> 4) * j; + g += (gx >> 4) * j; + b += (bx >> 4) * j; + + *dptr = qRgb(r >> 24, g >> 24, b >> 24); + dptr++; + } + } } -#endif QImage qSmoothScaleImage(const QImage &src, int dw, int dh) { @@ -1012,7 +793,7 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh) return QImage(); } - if (src.format() == QImage::Format_ARGB32_Premultiplied || src.format() == QImage::Format_RGBA8888_Premultiplied) + if (src.hasAlphaChannel()) qt_qimageScaleArgb(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4); else diff --git a/src/gui/painting/qimagescale_p.h b/src/gui/painting/qimagescale_p.h index 512ec6488e..c35aea451a 100644 --- a/src/gui/painting/qimagescale_p.h +++ b/src/gui/painting/qimagescale_p.h @@ -53,6 +53,15 @@ QT_BEGIN_NAMESPACE */ QImage qSmoothScaleImage(const QImage &img, int w, int h); +namespace QImageScale { + struct QImageScaleInfo { + int *xpoints; + const unsigned int **ypoints; + int *xapoints, *yapoints; + int xup_yup; + }; +} + QT_END_NAMESPACE #endif diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp new file mode 100644 index 0000000000..565ea4daa1 --- /dev/null +++ b/src/gui/painting/qimagescale_sse4.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qimagescale_p.h" +#include "qimage.h" +#include <private/qsimd_p.h> + +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) + +QT_BEGIN_NAMESPACE + +using namespace QImageScale; + +inline static __m128i qt_qimageScaleAARGBA_helper_x(const unsigned int *pix, int xap, int Cx, const __m128i vxap, const __m128i vCx) +{ + __m128i vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + __m128i vx = _mm_mullo_epi32(vpix, vxap); + int i; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) { + pix++; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCx)); + } + pix++; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, _mm_set1_epi32(i))); + return vx; +} + +inline static __m128i qt_qimageScaleAARGBA_helper_y(const unsigned int *pix, int yap, int Cy, int sow, const __m128i vyap, const __m128i vCy) +{ + __m128i vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + __m128i vx = _mm_mullo_epi32(vpix, vyap); + int i; + for (i = (1 << 14) - yap; i > Cy; i -= Cy) { + pix += sow; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCy)); + } + pix += sow; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, _mm_set1_epi32(i))); + return vx; +} + +template<bool RGB> +void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + const __m128i v256 = _mm_set1_epi32(256); + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + const __m128i vCy = _mm_set1_epi32(Cy); + const __m128i vyap = _mm_set1_epi32(yap); + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_y(sptr, yap, Cy, sow, vyap, vCy); + + int xap = xapoints[x]; + if (xap > 0) { + const __m128i vxap = _mm_set1_epi32(xap); + const __m128i vinvxap = _mm_sub_epi32(v256, vxap); + __m128i vr = qt_qimageScaleAARGBA_helper_y(sptr + 1, yap, Cy, sow, vyap, vCy); + + vx = _mm_mullo_epi32(vx, vinvxap); + vr = _mm_mullo_epi32(vr, vxap); + vx = _mm_add_epi32(vx, vr); + vx = _mm_srli_epi32(vx, 8); + } + vx = _mm_srli_epi32(vx, 14); + vx = _mm_packus_epi32(vx, _mm_setzero_si128()); + vx = _mm_packus_epi16(vx, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vx); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template<bool RGB> +void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + const __m128i v256 = _mm_set1_epi32(256); + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + const __m128i vCx = _mm_set1_epi32(Cx); + const __m128i vxap = _mm_set1_epi32(xap); + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + const __m128i vyap = _mm_set1_epi32(yap); + const __m128i vinvyap = _mm_sub_epi32(v256, vyap); + __m128i vr = qt_qimageScaleAARGBA_helper_x(sptr + sow, xap, Cx, vxap, vCx); + + vx = _mm_mullo_epi32(vx, vinvyap); + vr = _mm_mullo_epi32(vr, vyap); + vx = _mm_add_epi32(vx, vr); + vx = _mm_srli_epi32(vx, 8); + } + vx = _mm_srli_epi32(vx, 14); + vx = _mm_packus_epi32(vx, _mm_setzero_si128()); + vx = _mm_packus_epi16(vx, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vx); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template<bool RGB> +void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + const __m128i vCy = _mm_set1_epi32(Cy); + const __m128i vyap = _mm_set1_epi32(yap); + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + int end = dxx + dw; + for (int x = dxx; x < end; x++) { + const int Cx = xapoints[x] >> 16; + const int xap = xapoints[x] & 0xffff; + const __m128i vCx = _mm_set1_epi32(Cx); + const __m128i vxap = _mm_set1_epi32(xap); + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy)); + } + sptr += sow; + vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j))); + + vr = _mm_srli_epi32(vr, 24); + vr = _mm_packus_epi32(vr, _mm_setzero_si128()); + vr = _mm_packus_epi16(vr, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vr); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template void qt_qimageScaleAARGBA_up_x_down_y_sse4<false>(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_up_x_down_y_sse4<true>(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_x_up_y_sse4<false>(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_x_up_y_sse4<true>(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_xy_sse4<false>(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_xy_sse4<true>(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/painting/qmatrix.cpp b/src/gui/painting/qmatrix.cpp index acedc6a7ba..e4d756c18d 100644 --- a/src/gui/painting/qmatrix.cpp +++ b/src/gui/painting/qmatrix.cpp @@ -31,9 +31,11 @@ ** ****************************************************************************/ +#include "qmatrix.h" + #include "qdatastream.h" #include "qdebug.h" -#include "qmatrix.h" +#include "qhashfunctions.h" #include "qregion.h" #include "qpainterpath.h" #include "qpainterpath_p.h" @@ -972,6 +974,26 @@ bool QMatrix::operator==(const QMatrix &m) const _dy == m._dy; } + +/*! + \since 5.6 + \relates QMatrix + + Returns the hash value for \a key, using + \a seed to seed the calculation. +*/ +uint qHash(const QMatrix &key, uint seed) Q_DECL_NOTHROW +{ + QtPrivate::QHashCombine hash; + seed = hash(key.m11(), seed); + seed = hash(key.m12(), seed); + seed = hash(key.m21(), seed); + seed = hash(key.m22(), seed); + seed = hash(key.dx(), seed); + seed = hash(key.dy(), seed); + return seed; +} + /*! \fn bool QMatrix::operator!=(const QMatrix &matrix) const diff --git a/src/gui/painting/qmatrix.h b/src/gui/painting/qmatrix.h index ddffa8a8b9..c036e4df93 100644 --- a/src/gui/painting/qmatrix.h +++ b/src/gui/painting/qmatrix.h @@ -126,6 +126,8 @@ private: }; Q_DECLARE_TYPEINFO(QMatrix, Q_MOVABLE_TYPE); +Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QMatrix &key, uint seed = 0) Q_DECL_NOTHROW; + // mathematical semantics inline QPoint operator*(const QPoint &p, const QMatrix &m) { return m.map(p); } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 3be6e0f1f4..882a088d5c 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -42,7 +42,6 @@ #include <qpainterpath.h> #include <qdebug.h> -#include <qhash.h> #include <qbitmap.h> #include <qmath.h> diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index fdad8e2460..e8b675365f 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -53,7 +53,6 @@ #include "QtGui/qpainter.h" #include "QtGui/qpainterpath.h" #include "QtGui/qpaintengine.h" -#include <QtCore/qhash.h> #include <private/qpen_p.h> diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index ebb0e5f142..9b1f5e334a 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -66,12 +66,9 @@ QT_BEGIN_NAMESPACE inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features() { QPaintEngine::PaintEngineFeatures f = QPaintEngine::AllFeatures; - f &= ~(QPaintEngine::PorterDuff | QPaintEngine::PerspectiveTransform + f &= ~(QPaintEngine::PorterDuff + | QPaintEngine::PerspectiveTransform | QPaintEngine::ObjectBoundingModeGradients -#ifndef USE_NATIVE_GRADIENTS - | QPaintEngine::LinearGradientFill -#endif - | QPaintEngine::RadialGradientFill | QPaintEngine::ConicalGradientFill); return f; } @@ -548,189 +545,6 @@ QByteArray QPdf::patternForBrush(const QBrush &b) return pattern_for_brush[style]; } -#ifdef USE_NATIVE_GRADIENTS -static void writeTriangleLine(uchar *&data, int xpos, int ypos, int xoff, int yoff, uint rgb, uchar flag, bool alpha) -{ - data[0] = flag; - data[1] = (uchar)(xpos >> 16); - data[2] = (uchar)(xpos >> 8); - data[3] = (uchar)(xpos >> 0); - data[4] = (uchar)(ypos >> 16); - data[5] = (uchar)(ypos >> 8); - data[6] = (uchar)(ypos >> 0); - data += 7; - if (alpha) { - *data++ = (uchar)qAlpha(rgb); - } else { - *data++ = (uchar)qRed(rgb); - *data++ = (uchar)qGreen(rgb); - *data++ = (uchar)qBlue(rgb); - } - xpos += xoff; - ypos += yoff; - data[0] = flag; - data[1] = (uchar)(xpos >> 16); - data[2] = (uchar)(xpos >> 8); - data[3] = (uchar)(xpos >> 0); - data[4] = (uchar)(ypos >> 16); - data[5] = (uchar)(ypos >> 8); - data[6] = (uchar)(ypos >> 0); - data += 7; - if (alpha) { - *data++ = (uchar)qAlpha(rgb); - } else { - *data++ = (uchar)qRed(rgb); - *data++ = (uchar)qGreen(rgb); - *data++ = (uchar)qBlue(rgb); - } -} - - -QByteArray QPdf::generateLinearGradientShader(const QLinearGradient *gradient, const QPointF *page_rect, bool alpha) -{ - // generate list of triangles with colors - QPointF start = gradient->start(); - QPointF stop = gradient->finalStop(); - QGradientStops stops = gradient->stops(); - QPointF offset = stop - start; - QGradient::Spread spread = gradient->spread(); - - if (gradient->spread() == QGradient::ReflectSpread) { - offset *= 2; - for (int i = stops.size() - 2; i >= 0; --i) { - QGradientStop stop = stops.at(i); - stop.first = 2. - stop.first; - stops.append(stop); - } - for (int i = 0 ; i < stops.size(); ++i) - stops[i].first /= 2.; - } - - QPointF orthogonal(offset.y(), -offset.x()); - qreal length = offset.x()*offset.x() + offset.y()*offset.y(); - - // find the max and min values in offset and orth direction that are needed to cover - // the whole page - int off_min = INT_MAX; - int off_max = INT_MIN; - qreal ort_min = INT_MAX; - qreal ort_max = INT_MIN; - for (int i = 0; i < 4; ++i) { - qreal off = ((page_rect[i].x() - start.x()) * offset.x() + (page_rect[i].y() - start.y()) * offset.y())/length; - qreal ort = ((page_rect[i].x() - start.x()) * orthogonal.x() + (page_rect[i].y() - start.y()) * orthogonal.y())/length; - off_min = qMin(off_min, qFloor(off)); - off_max = qMax(off_max, qCeil(off)); - ort_min = qMin(ort_min, ort); - ort_max = qMax(ort_max, ort); - } - ort_min -= 1; - ort_max += 1; - - start += off_min * offset + ort_min * orthogonal; - orthogonal *= (ort_max - ort_min); - int num = off_max - off_min; - - QPointF gradient_rect[4] = { start, - start + orthogonal, - start + num*offset, - start + num*offset + orthogonal }; - qreal xmin = gradient_rect[0].x(); - qreal xmax = gradient_rect[0].x(); - qreal ymin = gradient_rect[0].y(); - qreal ymax = gradient_rect[0].y(); - for (int i = 1; i < 4; ++i) { - xmin = qMin(xmin, gradient_rect[i].x()); - xmax = qMax(xmax, gradient_rect[i].x()); - ymin = qMin(ymin, gradient_rect[i].y()); - ymax = qMax(ymax, gradient_rect[i].y()); - } - xmin -= 1000; - xmax += 1000; - ymin -= 1000; - ymax += 1000; - start -= QPointF(xmin, ymin); - qreal factor_x = qreal(1<<24)/(xmax - xmin); - qreal factor_y = qreal(1<<24)/(ymax - ymin); - int xoff = (int)(orthogonal.x()*factor_x); - int yoff = (int)(orthogonal.y()*factor_y); - - QByteArray triangles; - triangles.resize(spread == QGradient::PadSpread ? 20*(stops.size()+2) : 20*num*stops.size()); - uchar *data = (uchar *) triangles.data(); - if (spread == QGradient::PadSpread) { - if (off_min > 0 || off_max < 1) { - // linear gradient outside of page - const QGradientStop ¤t_stop = off_min > 0 ? stops.at(stops.size()-1) : stops.at(0); - uint rgb = current_stop.second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, 0, alpha); - start += num*offset; - xpos = (int)(start.x()*factor_x); - ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, 1, alpha); - } else { - int flag = 0; - if (off_min < 0) { - uint rgb = stops.at(0).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - start -= off_min*offset; - flag = 1; - } - for (int s = 0; s < stops.size(); ++s) { - const QGradientStop ¤t_stop = stops.at(s); - uint rgb = current_stop.second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - if (s < stops.size()-1) - start += offset*(stops.at(s+1).first - stops.at(s).first); - flag = 1; - } - if (off_max > 1) { - start += (off_max - 1)*offset; - uint rgb = stops.at(stops.size()-1).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - } - } - } else { - for (int i = 0; i < num; ++i) { - uchar flag = 0; - for (int s = 0; s < stops.size(); ++s) { - uint rgb = stops.at(s).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - if (s < stops.size()-1) - start += offset*(stops.at(s+1).first - stops.at(s).first); - flag = 1; - } - } - } - triangles.resize((char *)data - triangles.constData()); - - QByteArray shader; - QPdf::ByteStream s(&shader); - s << "<<\n" - "/ShadingType 4\n" - "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << - "/AntiAlias true\n" - "/BitsPerCoordinate 24\n" - "/BitsPerComponent 8\n" - "/BitsPerFlag 8\n" - "/Decode [" << xmin << xmax << ymin << ymax << (alpha ? "0 1]\n" : "0 1 0 1 0 1]\n") << - "/AntiAlias true\n" - "/Length " << triangles.length() << "\n" - ">>\n" - "stream\n" << triangles << "endstream\n" - "endobj\n"; - return shader; -} -#endif static void moveToHook(qfixed x, qfixed y, void *data) { @@ -1381,6 +1195,8 @@ void QPdfEngine::setBrush() bool specifyColor; int gStateObject = 0; int patternObject = d->addBrushPattern(d->stroker.matrix, &specifyColor, &gStateObject); + if (!patternObject && !specifyColor) + return; *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs "); if (specifyColor) { @@ -2119,34 +1935,263 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, return image; } -#ifdef USE_NATIVE_GRADIENTS -int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject) +struct QGradientBound { + qreal start; + qreal stop; + int function; + bool reverse; +}; + +int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha) { - const QGradient *gradient = b.gradient(); - if (!gradient) - return 0; + QGradientStops stops = gradient->stops(); + if (stops.isEmpty()) { + stops << QGradientStop(0, Qt::black); + stops << QGradientStop(1, Qt::white); + } + if (stops.at(0).first > 0) + stops.prepend(QGradientStop(0, stops.at(0).second)); + if (stops.at(stops.size() - 1).first < 1) + stops.append(QGradientStop(1, stops.at(stops.size() - 1).second)); + + QVector<int> functions; + for (int i = 0; i < stops.size() - 1; ++i) { + int f = addXrefEntry(-1); + QByteArray data; + QPdf::ByteStream s(&data); + s << "<<\n" + "/FunctionType 2\n" + "/Domain [0 1]\n" + "/N 1\n"; + if (alpha) { + s << "/C0 [" << stops.at(i).second.alphaF() << "]\n" + "/C1 [" << stops.at(i + 1).second.alphaF() << "]\n"; + } else { + s << "/C0 [" << stops.at(i).second.redF() << stops.at(i).second.greenF() << stops.at(i).second.blueF() << "]\n" + "/C1 [" << stops.at(i + 1).second.redF() << stops.at(i + 1).second.greenF() << stops.at(i + 1).second.blueF() << "]\n"; + } + s << ">>\n" + "endobj\n"; + write(data); + functions << f; + } + + QVector<QGradientBound> gradientBounds; - QTransform inv = matrix.inverted(); - QPointF page_rect[4] = { inv.map(QPointF(0, 0)), - inv.map(QPointF(width_, 0)), - inv.map(QPointF(0, height_)), - inv.map(QPointF(width_, height_)) }; + for (int step = from; step < to; ++step) { + if (reflect && step % 2) { + for (int i = stops.size() - 1; i > 0; --i) { + QGradientBound b; + b.start = step + 1 - qBound(0., stops.at(i).first, 1.); + b.stop = step + 1 - qBound(0., stops.at(i - 1).first, 1.); + b.function = functions.at(i - 1); + b.reverse = true; + gradientBounds << b; + } + } else { + for (int i = 0; i < stops.size() - 1; ++i) { + QGradientBound b; + b.start = step + qBound(0., stops.at(i).first, 1.); + b.stop = step + qBound(0., stops.at(i + 1).first, 1.); + b.function = functions.at(i); + b.reverse = false; + gradientBounds << b; + } + } + } - bool opaque = b.isOpaque(); + // normalize bounds to [0..1] + qreal bstart = gradientBounds.at(0).start; + qreal bend = gradientBounds.at(gradientBounds.size() - 1).stop; + qreal norm = 1./(bend - bstart); + for (int i = 0; i < gradientBounds.size(); ++i) { + gradientBounds[i].start = (gradientBounds[i].start - bstart)*norm; + gradientBounds[i].stop = (gradientBounds[i].stop - bstart)*norm; + } - QByteArray shader; - QByteArray alphaShader; - if (gradient->type() == QGradient::LinearGradient) { - const QLinearGradient *lg = static_cast<const QLinearGradient *>(gradient); - shader = QPdf::generateLinearGradientShader(lg, page_rect); - if (!opaque) - alphaShader = QPdf::generateLinearGradientShader(lg, page_rect, true); + int function; + if (gradientBounds.size() > 1) { + function = addXrefEntry(-1); + QByteArray data; + QPdf::ByteStream s(&data); + s << "<<\n" + "/FunctionType 3\n" + "/Domain [0 1]\n" + "/Bounds ["; + for (int i = 1; i < gradientBounds.size(); ++i) + s << gradientBounds.at(i).start; + s << "]\n" + "/Encode ["; + for (int i = 0; i < gradientBounds.size(); ++i) + s << (gradientBounds.at(i).reverse ? "1 0 " : "0 1 "); + s << "]\n" + "/Functions ["; + for (int i = 0; i < gradientBounds.size(); ++i) + s << gradientBounds.at(i).function << "0 R "; + s << "]\n" + ">>\n"; + write(data); } else { - // ############# - return 0; + function = functions.at(0); + } + return function; +} + +int QPdfEnginePrivate::generateLinearGradientShader(const QLinearGradient *gradient, const QTransform &matrix, bool alpha) +{ + QPointF start = gradient->start(); + QPointF stop = gradient->finalStop(); + QPointF offset = stop - start; + Q_ASSERT(gradient->coordinateMode() == QGradient::LogicalMode); + + int from = 0; + int to = 1; + bool reflect = false; + switch (gradient->spread()) { + case QGradient::PadSpread: + break; + case QGradient::ReflectSpread: + reflect = true; + // fall through + case QGradient::RepeatSpread: { + // calculate required bounds + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + QTransform inv = matrix.inverted(); + QPointF page_rect[4] = { inv.map(pageRect.topLeft()), + inv.map(pageRect.topRight()), + inv.map(pageRect.bottomLeft()), + inv.map(pageRect.bottomRight()) }; + + qreal length = offset.x()*offset.x() + offset.y()*offset.y(); + + // find the max and min values in offset and orth direction that are needed to cover + // the whole page + from = INT_MAX; + to = INT_MIN; + for (int i = 0; i < 4; ++i) { + qreal off = ((page_rect[i].x() - start.x()) * offset.x() + (page_rect[i].y() - start.y()) * offset.y())/length; + from = qMin(from, qFloor(off)); + to = qMax(to, qCeil(off)); + } + + stop = start + to * offset; + start = start + from * offset;\ + break; + } + } + + int function = createShadingFunction(gradient, from, to, reflect, alpha); + + QByteArray shader; + QPdf::ByteStream s(&shader); + s << "<<\n" + "/ShadingType 2\n" + "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << + "/AntiAlias true\n" + "/Coords [" << start.x() << start.y() << stop.x() << stop.y() << "]\n" + "/Extend [true true]\n" + "/Function " << function << "0 R\n" + ">>\n" + "endobj\n"; + int shaderObject = addXrefEntry(-1); + write(shader); + return shaderObject; +} + +int QPdfEnginePrivate::generateRadialGradientShader(const QRadialGradient *gradient, const QTransform &matrix, bool alpha) +{ + QPointF p1 = gradient->center(); + double r1 = gradient->centerRadius(); + QPointF p0 = gradient->focalPoint(); + double r0 = gradient->focalRadius(); + + Q_ASSERT(gradient->coordinateMode() == QGradient::LogicalMode); + + int from = 0; + int to = 1; + bool reflect = false; + switch (gradient->spread()) { + case QGradient::PadSpread: + break; + case QGradient::ReflectSpread: + reflect = true; + // fall through + case QGradient::RepeatSpread: { + Q_ASSERT(qFuzzyIsNull(r0)); // QPainter emulates if this is not 0 + + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + QTransform inv = matrix.inverted(); + QPointF page_rect[4] = { inv.map(pageRect.topLeft()), + inv.map(pageRect.topRight()), + inv.map(pageRect.bottomLeft()), + inv.map(pageRect.bottomRight()) }; + + // increase to until the whole page fits into it + bool done = false; + while (!done) { + QPointF center = QPointF(p0.x() + to*(p1.x() - p0.x()), p0.y() + to*(p1.y() - p0.y())); + double radius = r0 + to*(r1 - r0); + double r2 = radius*radius; + done = true; + for (int i = 0; i < 4; ++i) { + QPointF off = page_rect[i] - center; + if (off.x()*off.x() + off.y()*off.y() > r2) { + ++to; + done = false; + break; + } + } + } + p1 = QPointF(p0.x() + to*(p1.x() - p0.x()), p0.y() + to*(p1.y() - p0.y())); + r1 = r0 + to*(r1 - r0); + break; + } } + + int function = createShadingFunction(gradient, from, to, reflect, alpha); + + QByteArray shader; + QPdf::ByteStream s(&shader); + s << "<<\n" + "/ShadingType 3\n" + "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << + "/AntiAlias true\n" + "/Domain [0 1]\n" + "/Coords [" << p0.x() << p0.y() << r0 << p1.x() << p1.y() << r1 << "]\n" + "/Extend [true true]\n" + "/Function " << function << "0 R\n" + ">>\n" + "endobj\n"; int shaderObject = addXrefEntry(-1); write(shader); + return shaderObject; +} + +int QPdfEnginePrivate::generateGradientShader(const QGradient *gradient, const QTransform &matrix, bool alpha) +{ + switch (gradient->type()) { + case QGradient::LinearGradient: + return generateLinearGradientShader(static_cast<const QLinearGradient *>(gradient), matrix, alpha); + case QGradient::RadialGradient: + return generateRadialGradientShader(static_cast<const QRadialGradient *>(gradient), matrix, alpha); + case QGradient::ConicalGradient: + default: + qWarning() << "Implement me!"; + } + return 0; +} + +int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QTransform &matrix, int *gStateObject) +{ + const QGradient *gradient = b.gradient(); + + if (!gradient || gradient->coordinateMode() != QGradient::LogicalMode) + return 0; + + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + + QTransform m = b.transform() * matrix; + int shaderObject = generateGradientShader(gradient, m); QByteArray str; QPdf::ByteStream s(&str); @@ -2155,12 +2200,12 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int "/PatternType 2\n" "/Shading " << shaderObject << "0 R\n" "/Matrix [" - << matrix.m11() - << matrix.m12() - << matrix.m21() - << matrix.m22() - << matrix.dx() - << matrix.dy() << "]\n"; + << m.m11() + << m.m12() + << m.m21() + << m.m22() + << m.dx() + << m.dy() << "]\n"; s << ">>\n" "endobj\n"; @@ -2168,7 +2213,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int write(str); currentPage->patterns.append(patternObj); - if (!opaque) { + if (!b.isOpaque()) { bool ca = true; QGradientStops stops = gradient->stops(); int a = stops.at(0).second.alpha(); @@ -2181,8 +2226,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int if (ca) { *gStateObject = addConstantAlphaObject(stops.at(0).second.alpha()); } else { - int alphaShaderObject = addXrefEntry(-1); - write(alphaShader); + int alphaShaderObject = generateGradientShader(gradient, m, true); QByteArray content; QPdf::ByteStream c(&content); @@ -2193,7 +2237,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int f << "<<\n" "/Type /XObject\n" "/Subtype /Form\n" - "/BBox [0 0 " << width_ << height_ << "]\n" + "/BBox [0 0 " << pageRect.width() << pageRect.height() << "]\n" "/Group <</S /Transparency >>\n" "/Resources <<\n" "/Shading << /Shader" << alphaShaderObject << alphaShaderObject << "0 R >>\n" @@ -2217,7 +2261,6 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int return patternObj; } -#endif int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha) { @@ -2239,6 +2282,7 @@ int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha) return object; } + int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, int *gStateObject) { int paintType = 2; // Uncolored tiling @@ -2254,13 +2298,9 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, //qDebug() << brushOrigin << matrix; Qt::BrushStyle style = brush.style(); - if (style == Qt::LinearGradientPattern) {// && style <= Qt::ConicalGradientPattern) { -#ifdef USE_NATIVE_GRADIENTS + if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern) {// && style <= Qt::ConicalGradientPattern) { *specifyColor = false; - return gradientBrush(b, matrix, gStateObject); -#else - return 0; -#endif + return gradientBrush(brush, matrix, gStateObject); } if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0) diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h index e7ff09cd3b..94e74f30b9 100644 --- a/src/gui/painting/qpdf_p.h +++ b/src/gui/painting/qpdf_p.h @@ -58,8 +58,6 @@ #include "private/qfontsubset_p.h" #include "qpagelayout.h" -// #define USE_NATIVE_GRADIENTS - QT_BEGIN_NAMESPACE const char *qt_real_to_string(qreal val, char *buf); @@ -116,9 +114,6 @@ namespace QPdf { QByteArray generateMatrix(const QTransform &matrix); QByteArray generateDashes(const QPen &pen); QByteArray patternForBrush(const QBrush &b); -#ifdef USE_NATIVE_GRADIENTS - QByteArray generateLinearGradientShader(const QLinearGradient *lg, const QPointF *page_rect, bool alpha = false); -#endif struct Stroker { Stroker(); @@ -276,9 +271,11 @@ public: QPageLayout m_pageLayout; private: -#ifdef USE_NATIVE_GRADIENTS - int gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject); -#endif + int gradientBrush(const QBrush &b, const QTransform &matrix, int *gStateObject); + int generateGradientShader(const QGradient *gradient, const QTransform &matrix, bool alpha = false); + int generateLinearGradientShader(const QLinearGradient *lg, const QTransform &matrix, bool alpha); + int generateRadialGradientShader(const QRadialGradient *gradient, const QTransform &matrix, bool alpha); + int createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha); void writeInfo(); void writePageRoot(); diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h index 51ce4ab10d..290501047d 100644 --- a/src/gui/painting/qrgba64.h +++ b/src/gui/painting/qrgba64.h @@ -40,13 +40,15 @@ QT_BEGIN_NAMESPACE class QRgba64 { + struct qrgba_t { + quint16 red; + quint16 green; + quint16 blue; + quint16 alpha; + }; + union { - struct { - quint16 red; - quint16 green; - quint16 blue; - quint16 alpha; - } c; + struct qrgba_t c; quint64 rgba; }; public: @@ -167,6 +169,8 @@ private: } }; +Q_DECLARE_TYPEINFO(QRgba64, Q_PRIMITIVE_TYPE); + Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a) { return QRgba64::fromRgba64(r, g, b, a); diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h index a1452af8d9..c6cbe666ac 100644 --- a/src/gui/painting/qrgba64_p.h +++ b/src/gui/painting/qrgba64_p.h @@ -36,6 +36,7 @@ #include <QtGui/qrgba64.h> #include <QtGui/private/qdrawhelper_p.h> +#include <private/qsimd_p.h> QT_BEGIN_NAMESPACE @@ -52,20 +53,36 @@ inline QRgba64 multiplyAlpha256(QRgba64 rgba64, uint alpha256) (rgba64.alpha() * alpha256) >> 8); } -inline QRgba64 multiplyAlpha255(QRgba64 rgba64, uint alpha255) -{ - return QRgba64::fromRgba64(qt_div_255(rgba64.red() * alpha255), - qt_div_255(rgba64.green() * alpha255), - qt_div_255(rgba64.blue() * alpha255), - qt_div_255(rgba64.alpha() * alpha255)); -} - inline QRgba64 multiplyAlpha65535(QRgba64 rgba64, uint alpha65535) { +#ifdef __SSE2__ + const __m128i va = _mm_shufflelo_epi16(_mm_cvtsi32_si128(alpha65535), _MM_SHUFFLE(0, 0, 0, 0)); + __m128i vs = _mm_loadl_epi64((__m128i*)&rgba64); + vs = _mm_unpacklo_epi16(_mm_mullo_epi16(vs, va), _mm_mulhi_epu16(vs, va)); + vs = _mm_add_epi32(vs, _mm_srli_epi32(vs, 16)); + vs = _mm_add_epi32(vs, _mm_set1_epi32(0x8000)); + vs = _mm_srai_epi32(vs, 16); + vs = _mm_packs_epi32(vs, _mm_setzero_si128()); + _mm_storel_epi64((__m128i*)&rgba64, vs); + return rgba64; +#else return QRgba64::fromRgba64(qt_div_65535(rgba64.red() * alpha65535), qt_div_65535(rgba64.green() * alpha65535), qt_div_65535(rgba64.blue() * alpha65535), qt_div_65535(rgba64.alpha() * alpha65535)); +#endif +} + +inline QRgba64 multiplyAlpha255(QRgba64 rgba64, uint alpha255) +{ +#ifdef __SSE2__ + return multiplyAlpha65535(rgba64, alpha255 * 257); +#else + return QRgba64::fromRgba64(qt_div_255(rgba64.red() * alpha255), + qt_div_255(rgba64.green() * alpha255), + qt_div_255(rgba64.blue() * alpha255), + qt_div_255(rgba64.alpha() * alpha255)); +#endif } inline QRgba64 interpolate256(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) @@ -78,6 +95,26 @@ inline QRgba64 interpolate255(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) return QRgba64::fromRgba64(multiplyAlpha255(x, alpha1) + multiplyAlpha255(y, alpha2)); } +inline QRgba64 interpolate65535(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) +{ + return QRgba64::fromRgba64(multiplyAlpha65535(x, alpha1) + multiplyAlpha65535(y, alpha2)); +} + +inline QRgba64 addWithSaturation(QRgba64 a, QRgba64 b) +{ +#if defined(__SSE2__) && defined(Q_PROCESSOR_X86_64) + __m128i va = _mm_cvtsi64_si128((quint64)a); + __m128i vb = _mm_cvtsi64_si128((quint64)b); + va = _mm_adds_epu16(va, vb); + return QRgba64::fromRgba64(_mm_cvtsi128_si64(va)); +#else + return QRgba64::fromRgba64(qMin(a.red() + b.red(), 65535), + qMin(a.green() + b.green(), 65535), + qMin(a.blue() + b.blue(), 65535), + qMin(a.alpha() + b.alpha(), 65535)); +#endif +} + QT_END_NAMESPACE #endif // QRGBA64_P_H diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 31d7a2300b..4b3f0b30dc 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -34,6 +34,7 @@ #include "qdatastream.h" #include "qdebug.h" +#include "qhashfunctions.h" #include "qmatrix.h" #include "qregion.h" #include "qpainterpath.h" @@ -776,6 +777,29 @@ bool QTransform::operator==(const QTransform &o) const } /*! + \since 5.6 + \relates QTransform + + Returns the hash value for \a key, using + \a seed to seed the calculation. +*/ +uint qHash(const QTransform &key, uint seed) Q_DECL_NOTHROW +{ + QtPrivate::QHashCombine hash; + seed = hash(key.m11(), seed); + seed = hash(key.m12(), seed); + seed = hash(key.m21(), seed); + seed = hash(key.m22(), seed); + seed = hash(key.dx(), seed); + seed = hash(key.dy(), seed); + seed = hash(key.m13(), seed); + seed = hash(key.m23(), seed); + seed = hash(key.m33(), seed); + return seed; +} + + +/*! \fn bool QTransform::operator!=(const QTransform &matrix) const Returns \c true if this matrix is not equal to the given \a matrix, otherwise returns \c false. diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h index cf8d4d1970..65f543144d 100644 --- a/src/gui/painting/qtransform.h +++ b/src/gui/painting/qtransform.h @@ -180,6 +180,8 @@ private: }; Q_DECLARE_TYPEINFO(QTransform, Q_MOVABLE_TYPE); +Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QTransform &key, uint seed = 0) Q_DECL_NOTHROW; + /******* inlines *****/ inline QTransform::TransformationType QTransform::inline_type() const { |