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) <ogoffart@woboq.com>
This commit is contained in:
parent
38a446b69e
commit
ffd316ebe3
@ -39,6 +39,7 @@
|
||||
|
||||
#include <private/qdrawhelper_p.h>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <private/qcolorprofile_p.h>
|
||||
#include <private/qsimd_p.h>
|
||||
#include <private/qimage_p.h>
|
||||
#include <qendian.h>
|
||||
@ -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; y<h; ++y) {
|
||||
uint *pixels = (uint *) image->scanLine(y);
|
||||
for (int x=0; x<w; ++x) {
|
||||
uint p = pixels[x];
|
||||
uint r = gamma[qRed(p)];
|
||||
uint g = gamma[qGreen(p)];
|
||||
uint b = gamma[qBlue(p)];
|
||||
pixels[x] = (r << 16) | (g << 8) | b | 0xff000000;
|
||||
}
|
||||
QRgb *pixels = reinterpret_cast<QRgb *>(image->scanLine(y));
|
||||
for (int x=0; x<w; ++x)
|
||||
pixels[x] = cp->toLinear(pixels[x]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,8 @@
|
||||
#include <qpalette.h>
|
||||
#include <qscreen.h>
|
||||
#include "qsessionmanager.h"
|
||||
#include <private/qcolorprofile_p.h>
|
||||
#include <private/qscreen_p.h>
|
||||
#include <private/qdrawhelper_p.h>
|
||||
|
||||
#include <QtGui/qgenericpluginfactory.h>
|
||||
#include <QtGui/qstylehints.h>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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<QDrawHelperGammaTables> m_gammaTables;
|
||||
QAtomicPointer<QColorProfile> m_a8ColorProfile;
|
||||
QAtomicPointer<QColorProfile> m_a32ColorProfile;
|
||||
|
||||
bool ownGlobalShareContext;
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -37,28 +37,51 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <private/qdrawhelper_p.h>
|
||||
#include "qcolorprofile_p.h"
|
||||
#include <qmath.h>
|
||||
|
||||
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
|
157
src/gui/painting/qcolorprofile_p.h
Normal file
157
src/gui/painting/qcolorprofile_p.h
Normal file
@ -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 <QtGui/private/qtguiglobal_p.h>
|
||||
#include <QtGui/qrgb.h>
|
||||
#include <QtGui/qrgba64.h>
|
||||
|
||||
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
|
@ -43,6 +43,7 @@
|
||||
#include <qstylehints.h>
|
||||
#include <qguiapplication.h>
|
||||
#include <qatomic.h>
|
||||
#include <private/qcolorprofile_p.h>
|
||||
#include <private/qdrawhelper_p.h>
|
||||
#include <private/qpaintengine_raster_p.h>
|
||||
#include <private/qpainter_p.h>
|
||||
@ -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<quint32*>(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)
|
||||
|
@ -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) {
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include <qcolor.h>
|
||||
#include <qdebug.h>
|
||||
#include <private/qcolorprofile_p.h>
|
||||
#include <private/qdrawingprimitive_sse2_p.h>
|
||||
#include <qrgba64.h>
|
||||
|
||||
@ -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<qreal>("gammaC");
|
||||
QTest::addColumn<int>("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"
|
||||
|
Loading…
Reference in New Issue
Block a user