From ffd316ebe3963b7ff8d94a3484ac85de793b8299 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 21 Nov 2016 15:10:39 +0100 Subject: [PATCH] Replace QDrawHelperGammaTables with QColorProfile Turns the two set of tables in QDrawHelperGammaTables into two QColorProfile classes that use similar structures and can be reused for other gamma correction. At the same time clean-up and improve the comma-correct blending code to use the new profiles and QRgba64 precision. Change-Id: I302bd87a5c836e1010fff6d633eeb56fd4ae2ff0 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/gui/image/qimage_conversions.cpp | 17 +- src/gui/kernel/qguiapplication.cpp | 33 +++- src/gui/kernel/qguiapplication_p.h | 8 +- src/gui/painting/painting.pri | 3 +- .../{qgammatables.cpp => qcolorprofile.cpp} | 49 ++++-- src/gui/painting/qcolorprofile_p.h | 157 ++++++++++++++++++ src/gui/painting/qdrawhelper.cpp | 146 ++++++---------- src/gui/painting/qdrawhelper_p.h | 12 -- tests/auto/gui/painting/qcolor/tst_qcolor.cpp | 35 ++++ 9 files changed, 314 insertions(+), 146 deletions(-) rename src/gui/painting/{qgammatables.cpp => qcolorprofile.cpp} (63%) create mode 100644 src/gui/painting/qcolorprofile_p.h diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index c646ee96b4..d685d50d49 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -82,23 +83,17 @@ const uchar *qt_get_bitflip_array() void qGamma_correct_back_to_linear_cs(QImage *image) { - const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables(); - if (!tables) + const QColorProfile *cp = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); + if (!cp) return; - const uchar *gamma = tables->qt_pow_rgb_gamma; // gamma correct the pixels back to linear color space... int h = image->height(); int w = image->width(); for (int y=0; yscanLine(y); - for (int x=0; x(image->scanLine(y)); + for (int x=0; xtoLinear(pixels[x]); } } diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index ccb392f968..e0eff166a8 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -68,8 +68,8 @@ #include #include #include "qsessionmanager.h" +#include #include -#include #include #include @@ -1530,7 +1530,8 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() platform_theme = 0; delete platform_integration; platform_integration = 0; - delete m_gammaTables.load(); + delete m_a8ColorProfile.load(); + delete m_a32ColorProfile.load(); window_list.clear(); } @@ -3683,14 +3684,30 @@ void QGuiApplicationPrivate::notifyDragStarted(const QDrag *drag) } #endif -const QDrawHelperGammaTables *QGuiApplicationPrivate::gammaTables() +const QColorProfile *QGuiApplicationPrivate::colorProfileForA8Text() { - QDrawHelperGammaTables *result = m_gammaTables.load(); +#ifdef Q_OS_WIN + QColorProfile *result = m_a8ColorProfile.load(); if (!result){ - QDrawHelperGammaTables *tables = new QDrawHelperGammaTables(fontSmoothingGamma); - if (!m_gammaTables.testAndSetRelease(0, tables)) - delete tables; - result = m_gammaTables.load(); + QColorProfile *cs = QColorProfile::fromGamma(2.31); // This is a hard-coded thing for Windows text rendering + if (!m_a8ColorProfile.testAndSetRelease(0, cs)) + delete cs; + result = m_a8ColorProfile.load(); + } + return result; +#else + return colorProfileForA32Text(); +#endif +} + +const QColorProfile *QGuiApplicationPrivate::colorProfileForA32Text() +{ + QColorProfile *result = m_a32ColorProfile.load(); + if (!result){ + QColorProfile *cs = QColorProfile::fromGamma(fontSmoothingGamma); + if (!m_a32ColorProfile.testAndSetRelease(0, cs)) + delete cs; + result = m_a32ColorProfile.load(); } return result; } diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index e1a35e048c..996ea748b0 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -66,10 +66,10 @@ QT_BEGIN_NAMESPACE +class QColorProfile; class QPlatformIntegration; class QPlatformTheme; class QPlatformDragQtResponse; -struct QDrawHelperGammaTables; #ifndef QT_NO_DRAGANDDROP class QDrag; #endif // QT_NO_DRAGANDDROP @@ -292,7 +292,8 @@ public: static QInputDeviceManager *inputDeviceManager(); - const QDrawHelperGammaTables *gammaTables(); + const QColorProfile *colorProfileForA8Text(); + const QColorProfile *colorProfileForA32Text(); // hook reimplemented in QApplication to apply the QStyle function on the QIcon virtual QPixmap applyQIconStyleHelper(QIcon::Mode, const QPixmap &basePixmap) const { return basePixmap; } @@ -316,7 +317,8 @@ private: static QGuiApplicationPrivate *self; static QTouchDevice *m_fakeTouchDevice; static int m_fakeMouseSourcePointId; - QAtomicPointer m_gammaTables; + QAtomicPointer m_a8ColorProfile; + QAtomicPointer m_a32ColorProfile; bool ownGlobalShareContext; diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 86e35c39f8..63e345545c 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -8,6 +8,7 @@ HEADERS += \ painting/qbrush.h \ painting/qcolor.h \ painting/qcolor_p.h \ + painting/qcolorprofile_p.h \ painting/qcosmeticstroker_p.h \ painting/qdatabuffer_p.h \ painting/qdrawhelper_p.h \ @@ -63,11 +64,11 @@ SOURCES += \ painting/qblittable.cpp \ painting/qbrush.cpp \ painting/qcolor.cpp \ + painting/qcolorprofile.cpp \ painting/qcompositionfunctions.cpp \ painting/qcosmeticstroker.cpp \ painting/qdrawhelper.cpp \ painting/qemulationpaintengine.cpp \ - painting/qgammatables.cpp \ painting/qgrayraster.c \ painting/qimagescale.cpp \ painting/qmatrix.cpp \ diff --git a/src/gui/painting/qgammatables.cpp b/src/gui/painting/qcolorprofile.cpp similarity index 63% rename from src/gui/painting/qgammatables.cpp rename to src/gui/painting/qcolorprofile.cpp index 1d76f7ee3c..3b7b0a248b 100644 --- a/src/gui/painting/qgammatables.cpp +++ b/src/gui/painting/qcolorprofile.cpp @@ -37,28 +37,51 @@ ** ****************************************************************************/ -#include +#include "qcolorprofile_p.h" +#include QT_BEGIN_NAMESPACE - -QDrawHelperGammaTables::QDrawHelperGammaTables(qreal smoothing) +QColorProfile *QColorProfile::fromGamma(qreal gamma) { - const qreal gray_gamma = 2.31; - for (int i=0; i<256; ++i) - qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); - for (int i=0; i<2048; ++i) - qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255)); + QColorProfile *cp = new QColorProfile; - refresh(smoothing); + for (int i = 0; i <= (255 * 16); ++i) { + cp->m_toLinear[i] = ushort(qRound(qPow(i / qreal(255 * 16), gamma) * (255 * 256))); + cp->m_fromLinear[i] = ushort(qRound(qPow(i / qreal(255 * 16), qreal(1) / gamma) * (255 * 256))); + } + + return cp; } -void QDrawHelperGammaTables::refresh(qreal smoothing) +static qreal srgbToLinear(qreal v) { - for (int i=0; i<256; ++i) { - qt_pow_rgb_gamma[i] = uchar(qRound(qPow(i / qreal(255.0), smoothing) * 255)); - qt_pow_rgb_invgamma[i] = uchar(qRound(qPow(i / qreal(255.), 1 / smoothing) * 255)); + const qreal a = 0.055; + if (v <= qreal(0.04045)) + return v / qreal(12.92); + else + return qPow((v + a) / (qreal(1) + a), qreal(2.4)); +} + +static qreal linearToSrgb(qreal v) +{ + const qreal a = 0.055; + if (v <= qreal(0.0031308)) + return v * qreal(12.92); + else + return (qreal(1) + a) * qPow(v, qreal(1.0 / 2.4)) - a; +} + +QColorProfile *QColorProfile::fromSRgb() +{ + QColorProfile *cp = new QColorProfile; + + for (int i = 0; i <= (255 * 16); ++i) { + cp->m_toLinear[i] = ushort(qRound(srgbToLinear(i / qreal(255 * 16)) * (255 * 256))); + cp->m_fromLinear[i] = ushort(qRound(linearToSrgb(i / qreal(255 * 16)) * (255 * 256))); } + + return cp; } QT_END_NAMESPACE diff --git a/src/gui/painting/qcolorprofile_p.h b/src/gui/painting/qcolorprofile_p.h new file mode 100644 index 0000000000..ca1786ee6d --- /dev/null +++ b/src/gui/painting/qcolorprofile_p.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOLORPROFILE_P_H +#define QCOLORPROFILE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QColorProfile +{ +public: + static QColorProfile *fromGamma(qreal gamma); + static QColorProfile *fromSRgb(); + + // The following methods all convert opaque or unpremultiplied colors: + + QRgba64 toLinear64(QRgb rgb32) const + { + ushort r = m_toLinear[qRed(rgb32) << 4]; + ushort g = m_toLinear[qGreen(rgb32) << 4]; + ushort b = m_toLinear[qBlue(rgb32) << 4]; + r = r + (r >> 8); + g = g + (g >> 8); + b = b + (b >> 8); + return QRgba64::fromRgba64(r, g, b, qAlpha(rgb32) * 257); + } + + QRgb toLinear(QRgb rgb32) const + { + uchar r = (m_toLinear[qRed(rgb32) << 4] + 0x80) >> 8; + uchar g = (m_toLinear[qGreen(rgb32) << 4] + 0x80) >> 8; + uchar b = (m_toLinear[qBlue(rgb32) << 4] + 0x80) >> 8; + return qRgba(r, g, b, qAlpha(rgb32)); + } + + QRgba64 toLinear(QRgba64 rgb64) const + { + ushort r = rgb64.red(); + ushort g = rgb64.green(); + ushort b = rgb64.blue(); + r = r - (r >> 8); + g = g - (g >> 8); + b = b - (b >> 8); + r = m_toLinear[r >> 4]; + g = m_toLinear[g >> 4]; + b = m_toLinear[b >> 4]; + r = r + (r >> 8); + g = g + (g >> 8); + b = b + (b >> 8); + return QRgba64::fromRgba64(r, g, b, rgb64.alpha()); + } + + QRgb fromLinear64(QRgba64 rgb64) const + { + ushort r = rgb64.red(); + ushort g = rgb64.green(); + ushort b = rgb64.blue(); + r = r - (r >> 8); + g = g - (g >> 8); + b = b - (b >> 8); + r = (m_fromLinear[r >> 4] + 0x80) >> 8; + g = (m_fromLinear[g >> 4] + 0x80) >> 8; + b = (m_fromLinear[b >> 4] + 0x80) >> 8; + return qRgba(r, g, b, rgb64.alpha8()); + } + + QRgb fromLinear(QRgb rgb32) const + { + uchar r = (m_fromLinear[qRed(rgb32) << 4] + 0x80) >> 8; + uchar g = (m_fromLinear[qGreen(rgb32) << 4] + 0x80) >> 8; + uchar b = (m_fromLinear[qBlue(rgb32) << 4] + 0x80) >> 8; + return qRgba(r, g, b, qAlpha(rgb32)); + } + + QRgba64 fromLinear(QRgba64 rgb64) const + { + ushort r = rgb64.red(); + ushort g = rgb64.green(); + ushort b = rgb64.blue(); + r = r - (r >> 8); + g = g - (g >> 8); + b = b - (b >> 8); + r = m_fromLinear[r >> 4]; + g = m_fromLinear[g >> 4]; + b = m_fromLinear[b >> 4]; + r = r + (r >> 8); + g = g + (g >> 8); + b = b + (b >> 8); + return QRgba64::fromRgba64(r, g, b, rgb64.alpha()); + } + +private: + QColorProfile() { } + + // We translate to 0-65280 (255*256) instead to 0-65535 to make simple + // shifting an accurate conversion. + // We translate from 0-4080 (255*16) for the same speed up, and to keep + // the tables small enough to fit in most inner caches. + ushort m_toLinear[(255 * 16) + 1]; // [0-4080] -> [0-65280] + ushort m_fromLinear[(255 * 16) + 1]; // [0-4080] -> [0-65280] + +}; + +QT_END_NAMESPACE + +#endif // QCOLORPROFILE_P_H diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index fe1ff6603d..bd853ad934 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -5508,80 +5509,35 @@ static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer, } } -static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb, const uchar *gamma, const uchar *invgamma) +static inline void rgbBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorProfile *colorProfile) { - // Do a gray alphablend... - int da = qAlpha(*dst); - int dr = qRed(*dst); - int dg = qGreen(*dst); - int db = qBlue(*dst); + // Do a gammacorrected RGB alphablend... + const int mr = qRed(coverage); + const int mg = qGreen(coverage); + const int mb = qBlue(coverage); - if (da != 255 - ) { + const QRgba64 dlinear = colorProfile->toLinear64(*dst); - int a = qGray(coverage); - sr = qt_div_255(invgamma[sr] * a); - sg = qt_div_255(invgamma[sg] * a); - sb = qt_div_255(invgamma[sb] * a); + QRgba64 blend; + blend.setAlpha(65535); + blend.setRed (qt_div_255(slinear.red() * mr + dlinear.red() * (255 - mr))); + blend.setGreen(qt_div_255(slinear.green() * mg + dlinear.green() * (255 - mg))); + blend.setBlue (qt_div_255(slinear.blue() * mb + dlinear.blue() * (255 - mb))); - int ia = 255 - a; - dr = qt_div_255(dr * ia); - dg = qt_div_255(dg * ia); - db = qt_div_255(db * ia); - - *dst = ((a + qt_div_255((255 - a) * da)) << 24) - | ((sr + dr) << 16) - | ((sg + dg) << 8) - | ((sb + db)); - return; - } - - int mr = qRed(coverage); - int mg = qGreen(coverage); - int mb = qBlue(coverage); - - dr = gamma[dr]; - dg = gamma[dg]; - db = gamma[db]; - - int nr = qt_div_255(sr * mr + dr * (255 - mr)); - int ng = qt_div_255(sg * mg + dg * (255 - mg)); - int nb = qt_div_255(sb * mb + db * (255 - mb)); - - nr = invgamma[nr]; - ng = invgamma[ng]; - nb = invgamma[nb]; - - *dst = qRgb(nr, ng, nb); + *dst = colorProfile->fromLinear64(blend); } -#if defined(Q_OS_WIN) Q_GUI_EXPORT bool qt_needs_a8_gamma_correction = false; -static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb, const uint *gamma, const uchar *invgamma) +static inline void grayBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorProfile *colorProfile) { // Do a gammacorrected gray alphablend... - int dr = qRed(*dst); - int dg = qGreen(*dst); - int db = qBlue(*dst); + const QRgba64 dlinear = colorProfile->toLinear64(*dst); - dr = gamma[dr]; - dg = gamma[dg]; - db = gamma[db]; + QRgba64 blend = interpolate255(slinear, coverage, dlinear, 255 - coverage); - int alpha = coverage; - int ialpha = 255 - alpha; - int nr = qt_div_255(sr * alpha + dr * ialpha); - int ng = qt_div_255(sg * alpha + dg * ialpha); - int nb = qt_div_255(sb * alpha + db * ialpha); - - nr = invgamma[nr]; - ng = invgamma[ng]; - nb = invgamma[nb]; - - *dst = qRgb(nr, ng, nb); + *dst = colorProfile->fromLinear64(blend); } -#endif static void qt_alphamapblit_uint32(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, @@ -5592,21 +5548,14 @@ static void qt_alphamapblit_uint32(QRasterBuffer *rasterBuffer, const quint32 c = color; const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32); -#if defined(Q_OS_WIN) - const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables(); - if (!tables) + const QColorProfile *colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); + if (!colorProfile) return; - const uint *gamma = tables->qt_pow_gamma; - const uchar *invgamma = tables->qt_pow_invgamma; - - int sr = gamma[qRed(color)]; - int sg = gamma[qGreen(color)]; - int sb = gamma[qBlue(color)]; + const QRgba64 slinear = colorProfile->toLinear64(c); bool opaque_src = (qAlpha(color) == 255); bool doGrayBlendPixel = opaque_src && qt_needs_a8_gamma_correction; -#endif if (!clip) { quint32 *dest = reinterpret_cast(rasterBuffer->scanLine(y)) + x; @@ -5619,13 +5568,9 @@ static void qt_alphamapblit_uint32(QRasterBuffer *rasterBuffer, } else if (coverage == 255) { dest[i] = c; } else { -#if defined(Q_OS_WIN) - if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && doGrayBlendPixel - && qAlpha(dest[i]) == 255) { - grayBlendPixel(dest+i, coverage, sr, sg, sb, gamma, invgamma); - } else -#endif - { + if (doGrayBlendPixel && qAlpha(dest[i]) == 255) { + grayBlendPixel(dest+i, coverage, slinear, colorProfile); + } else { int ialpha = 255 - coverage; dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha); } @@ -5660,13 +5605,9 @@ static void qt_alphamapblit_uint32(QRasterBuffer *rasterBuffer, } else if (coverage == 255) { dest[xp] = c; } else { -#if defined(Q_OS_WIN) - if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && doGrayBlendPixel - && qAlpha(dest[xp]) == 255) { - grayBlendPixel(dest+xp, coverage, sr, sg, sb, gamma, invgamma); - } else -#endif - { + if (doGrayBlendPixel && qAlpha(dest[xp]) == 255) { + grayBlendPixel(dest+xp, coverage, slinear, colorProfile); + } else { int ialpha = 255 - coverage; dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha); } @@ -5700,6 +5641,11 @@ static void qt_alphamapblit_rgba8888(QRasterBuffer *rasterBuffer, } #endif +inline static int qRgbAvg(QRgb rgb) +{ + return (qRed(rgb) * 5 + qGreen(rgb) * 6 + qBlue(rgb) * 5) / 16; +} + static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uint *src, int mapWidth, int mapHeight, int srcStride, @@ -5707,21 +5653,13 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, { const quint32 c = color.toArgb32(); - int sr = qRed(c); - int sg = qGreen(c); - int sb = qBlue(c); int sa = qAlpha(c); - const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables(); - if (!tables) + const QColorProfile *colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); + if (!colorProfile) return; - const uchar *gamma = tables->qt_pow_rgb_gamma; - const uchar *invgamma = tables->qt_pow_rgb_invgamma; - - sr = gamma[sr]; - sg = gamma[sg]; - sb = gamma[sb]; + const QRgba64 slinear = colorProfile->toLinear64(c); if (sa == 0) return; @@ -5735,7 +5673,13 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, if (coverage == 0xffffffff) { dst[i] = c; } else if (coverage != 0xff000000) { - rgbBlendPixel(dst+i, coverage, sr, sg, sb, gamma, invgamma); + if (dst[i] >= 0xff000000) { + rgbBlendPixel(dst+i, coverage, slinear, colorProfile); + } else { + // Give up and do a naive blend. + const int a = qRgbAvg(coverage); + dst[i] = INTERPOLATE_PIXEL_255(c, a, dst[i], 255 - a); + } } } @@ -5765,7 +5709,13 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, if (coverage == 0xffffffff) { dst[xp] = c; } else if (coverage != 0xff000000) { - rgbBlendPixel(dst+xp, coverage, sr, sg, sb, gamma, invgamma); + if (dst[xp] >= 0xff000000) { + rgbBlendPixel(dst+xp, coverage, slinear, colorProfile); + } else { + // Give up and do a naive blend. + const int a = qRgbAvg(coverage); + dst[xp] = INTERPOLATE_PIXEL_255(c, a, dst[xp], 255 - coverage); + } } } } // for (i -> line.count) diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index e537c343bb..f28b2821d6 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -345,18 +345,6 @@ struct QSpanData void adjustSpanMethods(); }; -struct QDrawHelperGammaTables -{ - explicit QDrawHelperGammaTables(qreal smoothing); - - void refresh(qreal smoothing); - - uchar qt_pow_rgb_gamma[256]; - uchar qt_pow_rgb_invgamma[256]; - uint qt_pow_gamma[256]; - uchar qt_pow_invgamma[2048]; -}; - static inline uint qt_gradient_clamp(const QGradientData *data, int ipos) { if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp index 9dd9ab05e8..1ce7e797fc 100644 --- a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp +++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -107,6 +108,9 @@ private slots: void qrgba64Premultiply(); void qrgba64Equivalence(); + void qcolorprofile_data(); + void qcolorprofile(); + #if 0 // Used to be included in Qt4 for Q_WS_X11 void setallowX11ColorNames(); #endif @@ -1587,5 +1591,36 @@ void tst_QColor::qrgba64Equivalence() } } +void tst_QColor::qcolorprofile_data() +{ + QTest::addColumn("gammaC"); + QTest::addColumn("tolerance"); + + QTest::newRow("gamma=1.0") << qreal(1.0) << 0; + QTest::newRow("gamma=1.5") << qreal(1.5) << 1; + QTest::newRow("gamma=1.7") << qreal(1.7) << 2; + QTest::newRow("gamma=2.0") << qreal(2.0) << 8; + QTest::newRow("gamma=2.31") << qreal(2.31) << 33; + QTest::newRow("SRgb") << qreal(0.0) << 7; +} + +void tst_QColor::qcolorprofile() +{ + QFETCH(qreal, gammaC); + QFETCH(int, tolerance); + QColorProfile *cp = (gammaC == 0) ? QColorProfile::fromSRgb(): QColorProfile::fromGamma(gammaC); + + // Test we are accurate for most values after converting through gamma-correction. + int error = 0; + for (uint i = 0; i < 256; i++) { + QRgb cin = qRgb(i, i, i); + QRgba64 tmp = cp->toLinear64(cin); + QRgb cout = cp->fromLinear64(tmp); + error += qAbs(qRed(cin) - qRed(cout)); + } + QVERIFY(error <= tolerance); + delete cp; +} + QTEST_MAIN(tst_QColor) #include "tst_qcolor.moc"