diff options
Diffstat (limited to 'src/gui/painting')
62 files changed, 4820 insertions, 909 deletions
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index a90abed4c0..972cf387ff 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -8,7 +8,15 @@ HEADERS += \ painting/qbrush.h \ painting/qcolor.h \ painting/qcolor_p.h \ - painting/qcolorprofile_p.h \ + painting/qcolormatrix_p.h \ + painting/qcolorspace.h \ + painting/qcolorspace_p.h \ + painting/qcolortransferfunction_p.h \ + painting/qcolortransfertable_p.h \ + painting/qcolortransform.h \ + painting/qcolortransform_p.h \ + painting/qcolortrc_p.h \ + painting/qcolortrclut_p.h \ painting/qcosmeticstroker_p.h \ painting/qdatabuffer_p.h \ painting/qdrawhelper_p.h \ @@ -17,6 +25,7 @@ HEADERS += \ painting/qemulationpaintengine_p.h \ painting/qfixed_p.h \ painting/qgrayraster_p.h \ + painting/qicc_p.h \ painting/qmatrix.h \ painting/qmemrotate_p.h \ painting/qoutlinemapper_p.h \ @@ -64,12 +73,15 @@ SOURCES += \ painting/qblittable.cpp \ painting/qbrush.cpp \ painting/qcolor.cpp \ - painting/qcolorprofile.cpp \ + painting/qcolorspace.cpp \ + painting/qcolortransform.cpp \ + painting/qcolortrclut.cpp \ painting/qcompositionfunctions.cpp \ painting/qcosmeticstroker.cpp \ painting/qdrawhelper.cpp \ painting/qemulationpaintengine.cpp \ painting/qgrayraster.c \ + painting/qicc.cpp \ painting/qimagescale.cpp \ painting/qmatrix.cpp \ painting/qmemrotate.cpp \ diff --git a/src/gui/painting/qblendfunctions_p.h b/src/gui/painting/qblendfunctions_p.h index 5ea78cdde2..080da98ec4 100644 --- a/src/gui/painting/qblendfunctions_p.h +++ b/src/gui/painting/qblendfunctions_p.h @@ -71,10 +71,10 @@ void qt_scale_image_16bit(uchar *destPixels, int dbpl, const int ix = 0x00010000 * sx; const int iy = 0x00010000 * sy; -// qDebug() << "scale:" << endl -// << " - target" << targetRect << endl -// << " - source" << srcRect << endl -// << " - clip" << clip << endl +// qDebug() << "scale:" << Qt::endl +// << " - target" << targetRect << Qt::endl +// << " - source" << srcRect << Qt::endl +// << " - clip" << clip << Qt::endl // << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy; QRect tr = targetRect.normalized().toRect(); @@ -162,10 +162,10 @@ template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl, const int ix = 0x00010000 * sx; const int iy = 0x00010000 * sy; -// qDebug() << "scale:" << endl -// << " - target" << targetRect << endl -// << " - source" << srcRect << endl -// << " - clip" << clip << endl +// qDebug() << "scale:" << Qt::endl +// << " - target" << targetRect << Qt::endl +// << " - source" << srcRect << Qt::endl +// << " - clip" << clip << Qt::endl // << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy; QRect tr = targetRect.normalized().toRect(); diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index f56be55325..13d986073e 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -1140,11 +1140,11 @@ QDataStream &operator>>(QDataStream &s, QBrush &b) if (s.version() >= QDataStream::Qt_5_5) { QImage img; s >> img; - b.setTextureImage(qMove(img)); + b.setTextureImage(std::move(img)); } else { QPixmap pm; s >> pm; - b.setTexture(qMove(pm)); + b.setTexture(std::move(pm)); } } else if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern @@ -1401,6 +1401,13 @@ QGradient::QGradient(Preset preset) } } +/*! + \internal +*/ +QGradient::~QGradient() +{ +} + QT_END_NAMESPACE static void initGradientPresets() { Q_INIT_RESOURCE(qmake_webgradients); } Q_CONSTRUCTOR_FUNCTION(initGradientPresets); @@ -1785,6 +1792,12 @@ QLinearGradient::QLinearGradient(qreal xStart, qreal yStart, qreal xFinalStop, q { } +/*! + \internal +*/ +QLinearGradient::~QLinearGradient() +{ +} /*! Returns the start point of this linear gradient in logical coordinates. @@ -2056,6 +2069,13 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal f } /*! + \internal +*/ +QRadialGradient::~QRadialGradient() +{ +} + +/*! Returns the center of this radial gradient in logical coordinates. \sa QGradient::stops() @@ -2301,6 +2321,13 @@ QConicalGradient::QConicalGradient(qreal cx, qreal cy, qreal angle) { } +/*! + \internal +*/ +QConicalGradient::~QConicalGradient() +{ +} + /*! Constructs a conical with center at (0, 0) starting the diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h index aee51c526d..ca51430cf4 100644 --- a/src/gui/painting/qbrush.h +++ b/src/gui/painting/qbrush.h @@ -79,11 +79,9 @@ public: ~QBrush(); QBrush &operator=(const QBrush &brush); -#ifdef Q_COMPILER_RVALUE_REFS - inline QBrush &operator=(QBrush &&other) Q_DECL_NOEXCEPT + inline QBrush &operator=(QBrush &&other) noexcept { qSwap(d, other.d); return *this; } -#endif - inline void swap(QBrush &other) Q_DECL_NOEXCEPT + inline void swap(QBrush &other) noexcept { qSwap(d, other.d); } operator QVariant() const; @@ -378,6 +376,7 @@ public: QGradient(); QGradient(Preset); + ~QGradient(); Type type() const { return m_type; } @@ -431,6 +430,7 @@ public: QLinearGradient(); QLinearGradient(const QPointF &start, const QPointF &finalStop); QLinearGradient(qreal xStart, qreal yStart, qreal xFinalStop, qreal yFinalStop); + ~QLinearGradient(); QPointF start() const; void setStart(const QPointF &start); @@ -455,6 +455,8 @@ public: QRadialGradient(const QPointF ¢er, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius); QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius); + ~QRadialGradient(); + QPointF center() const; void setCenter(const QPointF ¢er); inline void setCenter(qreal x, qreal y) { setCenter(QPointF(x, y)); } @@ -480,6 +482,7 @@ public: QConicalGradient(); QConicalGradient(const QPointF ¢er, qreal startAngle); QConicalGradient(qreal cx, qreal cy, qreal startAngle); + ~QConicalGradient(); QPointF center() const; void setCenter(const QPointF ¢er); diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 07202f5b1c..174350d884 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -39,6 +39,7 @@ #include "qcolor.h" #include "qcolor_p.h" +#include "qfloat16.h" #include "qnamespace.h" #include "qdatastream.h" #include "qvariant.h" @@ -494,6 +495,14 @@ static QStringList get_colornames() with this value, a pixel value will be used that is appropriate for the underlying pixel format in use. + \section1 The Extended RGB Color Model + + The extended RGB color model, also known as the scRGB color space, + is the same the RGB color model except it allows values under 0.0, + and over 1.0. This makes it possible to represent colors that would + otherwise be outside the range of the RGB colorspace but still use + the same values for colors inside the RGB colorspace. + \section1 The HSV Color Model The RGB model is hardware-oriented. Its representation is close to @@ -603,12 +612,13 @@ static QStringList get_colornames() /*! \enum QColor::Spec - The type of color specified, either RGB, HSV, CMYK or HSL. + The type of color specified, either RGB, extended RGB, HSV, CMYK or HSL. \value Rgb \value Hsv \value Cmyk \value Hsl + \value ExtendedRgb \value Invalid \sa spec(), convertTo() @@ -653,7 +663,7 @@ static QStringList get_colornames() \sa isValid(), {QColor#Predefined Colors}{Predefined Colors} */ -QColor::QColor(Qt::GlobalColor color) Q_DECL_NOTHROW +QColor::QColor(Qt::GlobalColor color) noexcept { #define QRGB(r, g, b) \ QRgb(((0xffu << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff))) @@ -728,7 +738,7 @@ QColor::QColor(Qt::GlobalColor color) Q_DECL_NOTHROW \sa fromRgb(), isValid() */ -QColor::QColor(QRgb color) Q_DECL_NOTHROW +QColor::QColor(QRgb color) noexcept { cspec = Rgb; ct.argb.alpha = 0xffff; @@ -746,7 +756,7 @@ QColor::QColor(QRgb color) Q_DECL_NOTHROW \sa fromRgba64() */ -QColor::QColor(QRgba64 rgba64) Q_DECL_NOTHROW +QColor::QColor(QRgba64 rgba64) noexcept { setRgba64(rgba64); } @@ -760,7 +770,7 @@ QColor::QColor(QRgba64 rgba64) Q_DECL_NOTHROW becomes a valid color by accident. */ -QColor::QColor(Spec spec) Q_DECL_NOTHROW +QColor::QColor(Spec spec) noexcept { switch (spec) { case Invalid: @@ -778,6 +788,10 @@ QColor::QColor(Spec spec) Q_DECL_NOTHROW case Hsl: setHsl(0, 0, 0, 0); break; + case ExtendedRgb: + cspec = spec; + setRgbF(0, 0, 0, 0); + break; } } @@ -933,7 +947,7 @@ bool QColor::isValidColor(const QString &name) \overload \since 5.10 */ -bool QColor::isValidColor(QStringView name) Q_DECL_NOTHROW +bool QColor::isValidColor(QStringView name) noexcept { return name.size() && QColor().setColorFromString(name); } @@ -942,7 +956,7 @@ bool QColor::isValidColor(QStringView name) Q_DECL_NOTHROW \overload \since 5.8 */ -bool QColor::isValidColor(QLatin1String name) Q_DECL_NOTHROW +bool QColor::isValidColor(QLatin1String name) noexcept { return name.size() && QColor().setColorFromString(name); } @@ -1211,6 +1225,17 @@ void QColor::setHsl(int h, int s, int l, int a) ct.ahsl.pad = 0; } +static inline qfloat16 &castF16(quint16 &v) +{ + // this works because qfloat16 internally is a quint16 + return *reinterpret_cast<qfloat16 *>(&v); +} + +static inline const qfloat16 &castF16(const quint16 &v) +{ + return *reinterpret_cast<const qfloat16 *>(&v); +} + /*! Sets the contents pointed to by \a r, \a g, \a b, and \a a, to the red, green, blue, and alpha-channel (transparency) components of the color's @@ -1226,18 +1251,27 @@ void QColor::getRgbF(qreal *r, qreal *g, qreal *b, qreal *a) const if (!r || !g || !b) return; - if (cspec != Invalid && cspec != Rgb) { + if (cspec == Invalid) + return; + + if (cspec != Rgb && cspec != ExtendedRgb) { toRgb().getRgbF(r, g, b, a); return; } - *r = ct.argb.red / qreal(USHRT_MAX); - *g = ct.argb.green / qreal(USHRT_MAX); - *b = ct.argb.blue / qreal(USHRT_MAX); - - if (a) - *a = ct.argb.alpha / qreal(USHRT_MAX); - + if (cspec == Rgb) { + *r = ct.argb.red / qreal(USHRT_MAX); + *g = ct.argb.green / qreal(USHRT_MAX); + *b = ct.argb.blue / qreal(USHRT_MAX); + if (a) + *a = ct.argb.alpha / qreal(USHRT_MAX); + } else { + *r = castF16(ct.argbExtended.redF16); + *g = castF16(ct.argbExtended.greenF16); + *b = castF16(ct.argbExtended.blueF16); + if (a) + *a = castF16(ct.argbExtended.alphaF16); + } } /*! @@ -1274,26 +1308,35 @@ void QColor::getRgb(int *r, int *g, int *b, int *a) const Sets the color channels of this color to \a r (red), \a g (green), \a b (blue) and \a a (alpha, transparency). - All values must be in the range 0.0-1.0. + The alpha value must be in the range 0.0-1.0. + If any of the other values are outside the range of 0.0-1.0 the + color model will be set as \c ExtendedRgb. \sa rgb(), getRgbF(), setRgb() */ void QColor::setRgbF(qreal r, qreal g, qreal b, qreal a) { - if (r < qreal(0.0) || r > qreal(1.0) - || g < qreal(0.0) || g > qreal(1.0) - || b < qreal(0.0) || b > qreal(1.0) - || a < qreal(0.0) || a > qreal(1.0)) { - qWarning("QColor::setRgbF: RGB parameters out of range"); + if (a < qreal(0.0) || a > qreal(1.0)) { + qWarning("QColor::setRgbF: Alpha parameter is out of range"); invalidate(); return; } - + if (r < qreal(0.0) || r > qreal(1.0) || + g < qreal(0.0) || g > qreal(1.0) || + b < qreal(0.0) || b > qreal(1.0) || cspec == ExtendedRgb) { + cspec = ExtendedRgb; + castF16(ct.argbExtended.redF16) = qfloat16(r); + castF16(ct.argbExtended.greenF16) = qfloat16(g); + castF16(ct.argbExtended.blueF16) = qfloat16(b); + castF16(ct.argbExtended.alphaF16) = qfloat16(a); + ct.argbExtended.pad = 0; + return; + } cspec = Rgb; - ct.argb.alpha = qRound(a * USHRT_MAX); ct.argb.red = qRound(r * USHRT_MAX); ct.argb.green = qRound(g * USHRT_MAX); ct.argb.blue = qRound(b * USHRT_MAX); + ct.argb.alpha = qRound(a * USHRT_MAX); ct.argb.pad = 0; } @@ -1330,7 +1373,7 @@ void QColor::setRgb(int r, int g, int b, int a) \sa setRgba(), rgb(), rgba64() */ -QRgb QColor::rgba() const Q_DECL_NOTHROW +QRgb QColor::rgba() const noexcept { if (cspec != Invalid && cspec != Rgb) return toRgb().rgba(); @@ -1342,7 +1385,7 @@ QRgb QColor::rgba() const Q_DECL_NOTHROW \sa rgba(), rgb(), setRgba64() */ -void QColor::setRgba(QRgb rgba) Q_DECL_NOTHROW +void QColor::setRgba(QRgb rgba) noexcept { cspec = Rgb; ct.argb.alpha = qAlpha(rgba) * 0x101; @@ -1362,7 +1405,7 @@ void QColor::setRgba(QRgb rgba) Q_DECL_NOTHROW \sa setRgba64(), rgba(), rgb() */ -QRgba64 QColor::rgba64() const Q_DECL_NOTHROW +QRgba64 QColor::rgba64() const noexcept { if (cspec != Invalid && cspec != Rgb) return toRgb().rgba64(); @@ -1376,7 +1419,7 @@ QRgba64 QColor::rgba64() const Q_DECL_NOTHROW \sa setRgba(), rgba64() */ -void QColor::setRgba64(QRgba64 rgba) Q_DECL_NOTHROW +void QColor::setRgba64(QRgba64 rgba) noexcept { cspec = Rgb; ct.argb.alpha = rgba.alpha(); @@ -1393,7 +1436,7 @@ void QColor::setRgba64(QRgba64 rgba) Q_DECL_NOTHROW \sa getRgb(), rgba() */ -QRgb QColor::rgb() const Q_DECL_NOTHROW +QRgb QColor::rgb() const noexcept { if (cspec != Invalid && cspec != Rgb) return toRgb().rgb(); @@ -1405,7 +1448,7 @@ QRgb QColor::rgb() const Q_DECL_NOTHROW Sets the RGB value to \a rgb. The alpha value is set to opaque. */ -void QColor::setRgb(QRgb rgb) Q_DECL_NOTHROW +void QColor::setRgb(QRgb rgb) noexcept { cspec = Rgb; ct.argb.alpha = 0xffff; @@ -1420,8 +1463,12 @@ void QColor::setRgb(QRgb rgb) Q_DECL_NOTHROW \sa setAlpha(), alphaF(), {QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing} */ -int QColor::alpha() const Q_DECL_NOTHROW -{ return ct.argb.alpha >> 8; } +int QColor::alpha() const noexcept +{ + if (cspec == ExtendedRgb) + return qRound(qreal(castF16(ct.argbExtended.alphaF16)) * 255); + return ct.argb.alpha >> 8; +} /*! @@ -1434,6 +1481,11 @@ int QColor::alpha() const Q_DECL_NOTHROW void QColor::setAlpha(int alpha) { QCOLOR_INT_RANGE_CHECK("QColor::setAlpha", alpha); + if (cspec == ExtendedRgb) { + constexpr qreal f = qreal(1.0) / 255; + castF16(ct.argbExtended.alphaF16) = alpha * f; + return; + } ct.argb.alpha = alpha * 0x101; } @@ -1442,8 +1494,12 @@ void QColor::setAlpha(int alpha) \sa setAlphaF(), alpha(), {QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing} */ -qreal QColor::alphaF() const Q_DECL_NOTHROW -{ return ct.argb.alpha / qreal(USHRT_MAX); } +qreal QColor::alphaF() const noexcept +{ + if (cspec == ExtendedRgb) + return castF16(ct.argbExtended.alphaF16); + return ct.argb.alpha / qreal(USHRT_MAX); +} /*! Sets the alpha of this color to \a alpha. qreal alpha is specified in the @@ -1455,6 +1511,10 @@ qreal QColor::alphaF() const Q_DECL_NOTHROW void QColor::setAlphaF(qreal alpha) { QCOLOR_REAL_RANGE_CHECK("QColor::setAlphaF", alpha); + if (cspec == ExtendedRgb) { + castF16(ct.argbExtended.alphaF16) = alpha; + return; + } qreal tmp = alpha * USHRT_MAX; ct.argb.alpha = qRound(tmp); } @@ -1465,7 +1525,7 @@ void QColor::setAlphaF(qreal alpha) \sa setRed(), redF(), getRgb() */ -int QColor::red() const Q_DECL_NOTHROW +int QColor::red() const noexcept { if (cspec != Invalid && cspec != Rgb) return toRgb().red(); @@ -1492,7 +1552,7 @@ void QColor::setRed(int red) \sa setGreen(), greenF(), getRgb() */ -int QColor::green() const Q_DECL_NOTHROW +int QColor::green() const noexcept { if (cspec != Invalid && cspec != Rgb) return toRgb().green(); @@ -1520,7 +1580,7 @@ void QColor::setGreen(int green) \sa setBlue(), blueF(), getRgb() */ -int QColor::blue() const Q_DECL_NOTHROW +int QColor::blue() const noexcept { if (cspec != Invalid && cspec != Rgb) return toRgb().blue(); @@ -1548,27 +1608,31 @@ void QColor::setBlue(int blue) \sa setRedF(), red(), getRgbF() */ -qreal QColor::redF() const Q_DECL_NOTHROW +qreal QColor::redF() const noexcept { - if (cspec != Invalid && cspec != Rgb) - return toRgb().redF(); - return ct.argb.red / qreal(USHRT_MAX); + if (cspec == Rgb || cspec == Invalid) + return ct.argb.red / qreal(USHRT_MAX); + if (cspec == ExtendedRgb) + return castF16(ct.argbExtended.redF16); + + return toRgb().redF(); } /*! - Sets the red color component of this color to \a red. Float components - are specified in the range 0.0-1.0. + Sets the red color component of this color to \a red. If \a red lies outside + the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb. \sa redF(), red(), setRgbF() */ void QColor::setRedF(qreal red) { - QCOLOR_REAL_RANGE_CHECK("QColor::setRedF", red); - if (cspec != Rgb) - setRgbF(red, greenF(), blueF(), alphaF()); - else + if (cspec == Rgb && red >= qreal(0.0) && red <= qreal(1.0)) ct.argb.red = qRound(red * USHRT_MAX); + else if (cspec == ExtendedRgb) + castF16(ct.argbExtended.redF16) = red; + else + setRgbF(red, greenF(), blueF(), alphaF()); } /*! @@ -1576,27 +1640,31 @@ void QColor::setRedF(qreal red) \sa setGreenF(), green(), getRgbF() */ -qreal QColor::greenF() const Q_DECL_NOTHROW +qreal QColor::greenF() const noexcept { - if (cspec != Invalid && cspec != Rgb) - return toRgb().greenF(); - return ct.argb.green / qreal(USHRT_MAX); + if (cspec == Rgb || cspec == Invalid) + return ct.argb.green / qreal(USHRT_MAX); + if (cspec == ExtendedRgb) + return castF16(ct.argbExtended.greenF16); + + return toRgb().greenF(); } /*! - Sets the green color component of this color to \a green. Float components - are specified in the range 0.0-1.0. + Sets the green color component of this color to \a green. If \a green lies outside + the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb. \sa greenF(), green(), setRgbF() */ void QColor::setGreenF(qreal green) { - QCOLOR_REAL_RANGE_CHECK("QColor::setGreenF", green); - if (cspec != Rgb) - setRgbF(redF(), green, blueF(), alphaF()); - else + if (cspec == Rgb && green >= qreal(0.0) && green <= qreal(1.0)) ct.argb.green = qRound(green * USHRT_MAX); + else if (cspec == ExtendedRgb) + castF16(ct.argbExtended.greenF16) = green; + else + setRgbF(redF(), green, blueF(), alphaF()); } /*! @@ -1604,26 +1672,29 @@ void QColor::setGreenF(qreal green) \sa setBlueF(), blue(), getRgbF() */ -qreal QColor::blueF() const Q_DECL_NOTHROW +qreal QColor::blueF() const noexcept { - if (cspec != Invalid && cspec != Rgb) - return toRgb().blueF(); - return ct.argb.blue / qreal(USHRT_MAX); + if (cspec == Rgb || cspec == Invalid) + return ct.argb.blue / qreal(USHRT_MAX); + if (cspec == ExtendedRgb) + return castF16(ct.argbExtended.blueF16); + + return toRgb().blueF(); } /*! - Sets the blue color component of this color to \a blue. Float components - are specified in the range 0.0-1.0. - + Sets the blue color component of this color to \a blue. If \a blue lies outside + the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb. \sa blueF(), blue(), setRgbF() */ void QColor::setBlueF(qreal blue) { - QCOLOR_REAL_RANGE_CHECK("QColor::setBlueF", blue); - if (cspec != Rgb) - setRgbF(redF(), greenF(), blue, alphaF()); - else + if (cspec == Rgb && blue >= qreal(0.0) && blue <= qreal(1.0)) ct.argb.blue = qRound(blue * USHRT_MAX); + else if (cspec == ExtendedRgb) + castF16(ct.argbExtended.blueF16) = blue; + else + setRgbF(redF(), greenF(), blue, alphaF()); } /*! @@ -1634,7 +1705,7 @@ void QColor::setBlueF(qreal blue) \sa hsvHue(), hslHue(), hueF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color Model} */ -int QColor::hue() const Q_DECL_NOTHROW +int QColor::hue() const noexcept { return hsvHue(); } @@ -1644,7 +1715,7 @@ int QColor::hue() const Q_DECL_NOTHROW \sa hueF(), hslHue(), getHsv(), {QColor#The HSV Color Model}{The HSV Color Model} */ -int QColor::hsvHue() const Q_DECL_NOTHROW +int QColor::hsvHue() const noexcept { if (cspec != Invalid && cspec != Hsv) return toHsv().hue(); @@ -1660,7 +1731,7 @@ int QColor::hsvHue() const Q_DECL_NOTHROW Model} */ -int QColor::saturation() const Q_DECL_NOTHROW +int QColor::saturation() const noexcept { return hsvSaturation(); } @@ -1670,7 +1741,7 @@ int QColor::saturation() const Q_DECL_NOTHROW \sa saturationF(), hslSaturation(), getHsv(), {QColor#The HSV Color Model}{The HSV Color Model} */ -int QColor::hsvSaturation() const Q_DECL_NOTHROW +int QColor::hsvSaturation() const noexcept { if (cspec != Invalid && cspec != Hsv) return toHsv().saturation(); @@ -1682,7 +1753,7 @@ int QColor::hsvSaturation() const Q_DECL_NOTHROW \sa valueF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color Model} */ -int QColor::value() const Q_DECL_NOTHROW +int QColor::value() const noexcept { if (cspec != Invalid && cspec != Hsv) return toHsv().value(); @@ -1696,7 +1767,7 @@ int QColor::value() const Q_DECL_NOTHROW \sa hsvHueF(), hslHueF(), hue(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model} */ -qreal QColor::hueF() const Q_DECL_NOTHROW +qreal QColor::hueF() const noexcept { return hsvHueF(); } @@ -1707,7 +1778,7 @@ qreal QColor::hueF() const Q_DECL_NOTHROW \sa hue(), hslHueF(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model} */ -qreal QColor::hsvHueF() const Q_DECL_NOTHROW +qreal QColor::hsvHueF() const noexcept { if (cspec != Invalid && cspec != Hsv) return toHsv().hueF(); @@ -1722,7 +1793,7 @@ qreal QColor::hsvHueF() const Q_DECL_NOTHROW \sa hsvSaturationF(), hslSaturationF(), saturation(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model} */ -qreal QColor::saturationF() const Q_DECL_NOTHROW +qreal QColor::saturationF() const noexcept { return hsvSaturationF(); } @@ -1732,7 +1803,7 @@ qreal QColor::saturationF() const Q_DECL_NOTHROW \sa saturation(), hslSaturationF(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model} */ -qreal QColor::hsvSaturationF() const Q_DECL_NOTHROW +qreal QColor::hsvSaturationF() const noexcept { if (cspec != Invalid && cspec != Hsv) return toHsv().saturationF(); @@ -1744,7 +1815,7 @@ qreal QColor::hsvSaturationF() const Q_DECL_NOTHROW \sa value(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model} */ -qreal QColor::valueF() const Q_DECL_NOTHROW +qreal QColor::valueF() const noexcept { if (cspec != Invalid && cspec != Hsv) return toHsv().valueF(); @@ -1758,7 +1829,7 @@ qreal QColor::valueF() const Q_DECL_NOTHROW \sa hslHueF(), hsvHue(), getHsl(), {QColor#The HSL Color Model}{The HSL Color Model} */ -int QColor::hslHue() const Q_DECL_NOTHROW +int QColor::hslHue() const noexcept { if (cspec != Invalid && cspec != Hsl) return toHsl().hslHue(); @@ -1772,7 +1843,7 @@ int QColor::hslHue() const Q_DECL_NOTHROW \sa hslSaturationF(), hsvSaturation(), getHsl(), {QColor#The HSL Color Model}{The HSL Color Model} */ -int QColor::hslSaturation() const Q_DECL_NOTHROW +int QColor::hslSaturation() const noexcept { if (cspec != Invalid && cspec != Hsl) return toHsl().hslSaturation(); @@ -1786,7 +1857,7 @@ int QColor::hslSaturation() const Q_DECL_NOTHROW \sa lightnessF(), getHsl() */ -int QColor::lightness() const Q_DECL_NOTHROW +int QColor::lightness() const noexcept { if (cspec != Invalid && cspec != Hsl) return toHsl().lightness(); @@ -1800,7 +1871,7 @@ int QColor::lightness() const Q_DECL_NOTHROW \sa hslHue(), hsvHueF(), getHslF() */ -qreal QColor::hslHueF() const Q_DECL_NOTHROW +qreal QColor::hslHueF() const noexcept { if (cspec != Invalid && cspec != Hsl) return toHsl().hslHueF(); @@ -1814,7 +1885,7 @@ qreal QColor::hslHueF() const Q_DECL_NOTHROW \sa hslSaturation(), hsvSaturationF(), getHslF(), {QColor#The HSL Color Model}{The HSL Color Model} */ -qreal QColor::hslSaturationF() const Q_DECL_NOTHROW +qreal QColor::hslSaturationF() const noexcept { if (cspec != Invalid && cspec != Hsl) return toHsl().hslSaturationF(); @@ -1828,7 +1899,7 @@ qreal QColor::hslSaturationF() const Q_DECL_NOTHROW \sa value(), getHslF() */ -qreal QColor::lightnessF() const Q_DECL_NOTHROW +qreal QColor::lightnessF() const noexcept { if (cspec != Invalid && cspec != Hsl) return toHsl().lightnessF(); @@ -1840,7 +1911,7 @@ qreal QColor::lightnessF() const Q_DECL_NOTHROW \sa cyanF(), getCmyk(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -int QColor::cyan() const Q_DECL_NOTHROW +int QColor::cyan() const noexcept { if (cspec != Invalid && cspec != Cmyk) return toCmyk().cyan(); @@ -1852,7 +1923,7 @@ int QColor::cyan() const Q_DECL_NOTHROW \sa magentaF(), getCmyk(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -int QColor::magenta() const Q_DECL_NOTHROW +int QColor::magenta() const noexcept { if (cspec != Invalid && cspec != Cmyk) return toCmyk().magenta(); @@ -1864,7 +1935,7 @@ int QColor::magenta() const Q_DECL_NOTHROW \sa yellowF(), getCmyk(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -int QColor::yellow() const Q_DECL_NOTHROW +int QColor::yellow() const noexcept { if (cspec != Invalid && cspec != Cmyk) return toCmyk().yellow(); @@ -1877,7 +1948,7 @@ int QColor::yellow() const Q_DECL_NOTHROW \sa blackF(), getCmyk(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -int QColor::black() const Q_DECL_NOTHROW +int QColor::black() const noexcept { if (cspec != Invalid && cspec != Cmyk) return toCmyk().black(); @@ -1889,7 +1960,7 @@ int QColor::black() const Q_DECL_NOTHROW \sa cyan(), getCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -qreal QColor::cyanF() const Q_DECL_NOTHROW +qreal QColor::cyanF() const noexcept { if (cspec != Invalid && cspec != Cmyk) return toCmyk().cyanF(); @@ -1901,7 +1972,7 @@ qreal QColor::cyanF() const Q_DECL_NOTHROW \sa magenta(), getCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -qreal QColor::magentaF() const Q_DECL_NOTHROW +qreal QColor::magentaF() const noexcept { if (cspec != Invalid && cspec != Cmyk) return toCmyk().magentaF(); @@ -1913,7 +1984,7 @@ qreal QColor::magentaF() const Q_DECL_NOTHROW \sa yellow(), getCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -qreal QColor::yellowF() const Q_DECL_NOTHROW +qreal QColor::yellowF() const noexcept { if (cspec != Invalid && cspec != Cmyk) return toCmyk().yellowF(); @@ -1925,7 +1996,7 @@ qreal QColor::yellowF() const Q_DECL_NOTHROW \sa black(), getCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -qreal QColor::blackF() const Q_DECL_NOTHROW +qreal QColor::blackF() const noexcept { if (cspec != Invalid && cspec != Cmyk) return toCmyk().blackF(); @@ -1933,18 +2004,43 @@ qreal QColor::blackF() const Q_DECL_NOTHROW } /*! + Create and returns an extended RGB QColor based on this color. + \since 5.14 + + \sa toRgb, convertTo() +*/ +QColor QColor::toExtendedRgb() const noexcept +{ + if (!isValid() || cspec == ExtendedRgb) + return *this; + if (cspec != Rgb) + return toRgb().toExtendedRgb(); + + constexpr qreal f = qreal(1.0) / USHRT_MAX; + QColor color; + color.cspec = ExtendedRgb; + castF16(color.ct.argbExtended.alphaF16) = qfloat16(ct.argb.alpha * f); + castF16(color.ct.argbExtended.redF16) = qfloat16(ct.argb.red * f); + castF16(color.ct.argbExtended.greenF16) = qfloat16(ct.argb.green * f); + castF16(color.ct.argbExtended.blueF16) = qfloat16(ct.argb.blue * f); + color.ct.argbExtended.pad = 0; + return color; +} + +/*! Create and returns an RGB QColor based on this color. \sa fromRgb(), convertTo(), isValid() */ -QColor QColor::toRgb() const Q_DECL_NOTHROW +QColor QColor::toRgb() const noexcept { if (!isValid() || cspec == Rgb) return *this; QColor color; color.cspec = Rgb; - color.ct.argb.alpha = ct.argb.alpha; + if (cspec != ExtendedRgb) + color.ct.argb.alpha = ct.argb.alpha; color.ct.argb.pad = 0; switch (cspec) { @@ -2066,6 +2162,12 @@ QColor QColor::toRgb() const Q_DECL_NOTHROW color.ct.argb.blue = qRound((qreal(1.0) - (y * (qreal(1.0) - k) + k)) * USHRT_MAX); break; } + case ExtendedRgb: + color.ct.argb.alpha = qRound(USHRT_MAX * qreal(castF16(ct.argbExtended.alphaF16))); + color.ct.argb.red = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.redF16)), qreal(1.0))); + color.ct.argb.green = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.greenF16)), qreal(1.0))); + color.ct.argb.blue = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.blueF16)), qreal(1.0))); + break; default: break; } @@ -2083,7 +2185,7 @@ QColor QColor::toRgb() const Q_DECL_NOTHROW \sa fromHsv(), convertTo(), isValid(), {QColor#The HSV Color Model}{The HSV Color Model} */ -QColor QColor::toHsv() const Q_DECL_NOTHROW +QColor QColor::toHsv() const noexcept { if (!isValid() || cspec == Hsv) return *this; @@ -2134,7 +2236,7 @@ QColor QColor::toHsv() const Q_DECL_NOTHROW \sa fromHsl(), convertTo(), isValid(), {QColor#The HSL Color Model}{The HSL Color Model} */ -QColor QColor::toHsl() const Q_DECL_NOTHROW +QColor QColor::toHsl() const noexcept { if (!isValid() || cspec == Hsl) return *this; @@ -2190,7 +2292,7 @@ QColor QColor::toHsl() const Q_DECL_NOTHROW \sa fromCmyk(), convertTo(), isValid(), {QColor#The CMYK Color Model}{The CMYK Color Model} */ -QColor QColor::toCmyk() const Q_DECL_NOTHROW +QColor QColor::toCmyk() const noexcept { if (!isValid() || cspec == Cmyk) return *this; @@ -2231,13 +2333,15 @@ QColor QColor::toCmyk() const Q_DECL_NOTHROW return color; } -QColor QColor::convertTo(QColor::Spec colorSpec) const Q_DECL_NOTHROW +QColor QColor::convertTo(QColor::Spec colorSpec) const noexcept { if (colorSpec == cspec) return *this; switch (colorSpec) { case Rgb: return toRgb(); + case ExtendedRgb: + return toExtendedRgb(); case Hsv: return toHsv(); case Cmyk: @@ -2262,7 +2366,7 @@ QColor QColor::convertTo(QColor::Spec colorSpec) const Q_DECL_NOTHROW \sa fromRgba(), fromRgbF(), toRgb(), isValid() */ -QColor QColor::fromRgb(QRgb rgb) Q_DECL_NOTHROW +QColor QColor::fromRgb(QRgb rgb) noexcept { return fromRgb(qRed(rgb), qGreen(rgb), qBlue(rgb)); } @@ -2278,7 +2382,7 @@ QColor QColor::fromRgb(QRgb rgb) Q_DECL_NOTHROW \sa fromRgb(), fromRgba64(), isValid() */ -QColor QColor::fromRgba(QRgb rgba) Q_DECL_NOTHROW +QColor QColor::fromRgba(QRgb rgba) noexcept { return fromRgb(qRed(rgba), qGreen(rgba), qBlue(rgba), qAlpha(rgba)); } @@ -2317,20 +2421,32 @@ QColor QColor::fromRgb(int r, int g, int b, int a) color values, \a r (red), \a g (green), \a b (blue), and \a a (alpha-channel, i.e. transparency). - All the values must be in the range 0.0-1.0. + The alpha value must be in the range 0.0-1.0. + If any of the other values are outside the range of 0.0-1.0 the + color model will be set as \c ExtendedRgb. \sa fromRgb(), fromRgba64(), toRgb(), isValid() */ QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a) { - if (r < qreal(0.0) || r > qreal(1.0) - || g < qreal(0.0) || g > qreal(1.0) - || b < qreal(0.0) || b > qreal(1.0) - || a < qreal(0.0) || a > qreal(1.0)) { - qWarning("QColor::fromRgbF: RGB parameters out of range"); + if (a < qreal(0.0) || a > qreal(1.0)) { + qWarning("QColor::fromRgbF: Alpha parameter out of range"); return QColor(); } + if (r < qreal(0.0) || r > qreal(1.0) + || g < qreal(0.0) || g > qreal(1.0) + || b < qreal(0.0) || b > qreal(1.0)) { + QColor color; + color.cspec = ExtendedRgb; + castF16(color.ct.argbExtended.alphaF16) = qfloat16(a); + castF16(color.ct.argbExtended.redF16) = qfloat16(r); + castF16(color.ct.argbExtended.greenF16) = qfloat16(g); + castF16(color.ct.argbExtended.blueF16) = qfloat16(b); + color.ct.argbExtended.pad = 0; + return color; + } + QColor color; color.cspec = Rgb; color.ct.argb.alpha = qRound(a * USHRT_MAX); @@ -2351,7 +2467,7 @@ QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a) \sa fromRgb(), fromRgbF(), toRgb(), isValid() */ -QColor QColor::fromRgba64(ushort r, ushort g, ushort b, ushort a) Q_DECL_NOTHROW +QColor QColor::fromRgba64(ushort r, ushort g, ushort b, ushort a) noexcept { QColor color; color.setRgba64(qRgba64(r, g, b, a)); @@ -2366,7 +2482,7 @@ QColor QColor::fromRgba64(ushort r, ushort g, ushort b, ushort a) Q_DECL_NOTHROW \sa fromRgb(), fromRgbF(), toRgb(), isValid() */ -QColor QColor::fromRgba64(QRgba64 rgba64) Q_DECL_NOTHROW +QColor QColor::fromRgba64(QRgba64 rgba64) noexcept { QColor color; color.setRgba64(rgba64); @@ -2714,7 +2830,7 @@ QColor QColor::fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a) \sa darker(), isValid() */ -QColor QColor::lighter(int factor) const Q_DECL_NOTHROW +QColor QColor::lighter(int factor) const noexcept { if (factor <= 0) // invalid lightness factor return *this; @@ -2759,7 +2875,7 @@ QColor QColor::lighter(int factor) const Q_DECL_NOTHROW \sa lighter(), isValid() */ -QColor QColor::darker(int factor) const Q_DECL_NOTHROW +QColor QColor::darker(int factor) const noexcept { if (factor <= 0) // invalid darkness factor return *this; @@ -2779,7 +2895,7 @@ QColor QColor::darker(int factor) const Q_DECL_NOTHROW Use lighter(\a factor) instead. */ -QColor QColor::light(int factor) const Q_DECL_NOTHROW +QColor QColor::light(int factor) const noexcept { return lighter(factor); } @@ -2789,7 +2905,7 @@ QColor QColor::light(int factor) const Q_DECL_NOTHROW Use darker(\a factor) instead. */ -QColor QColor::dark(int factor) const Q_DECL_NOTHROW +QColor QColor::dark(int factor) const noexcept { return darker(factor); } @@ -2799,7 +2915,7 @@ QColor QColor::dark(int factor) const Q_DECL_NOTHROW /*! Assigns a copy of \a color to this color, and returns a reference to it. */ -QColor &QColor::operator=(const QColor &color) Q_DECL_NOTHROW +QColor &QColor::operator=(const QColor &color) noexcept { cspec = color.cspec; ct.argb = color.ct.argb; @@ -2810,7 +2926,7 @@ QColor &QColor::operator=(const QColor &color) Q_DECL_NOTHROW /*! \overload Assigns a copy of \a color and returns a reference to this color. */ -QColor &QColor::operator=(Qt::GlobalColor color) Q_DECL_NOTHROW +QColor &QColor::operator=(Qt::GlobalColor color) noexcept { return operator=(QColor(color)); } @@ -2819,7 +2935,7 @@ QColor &QColor::operator=(Qt::GlobalColor color) Q_DECL_NOTHROW Returns \c true if this color has the same RGB and alpha values as \a color; otherwise returns \c false. */ -bool QColor::operator==(const QColor &color) const Q_DECL_NOTHROW +bool QColor::operator==(const QColor &color) const noexcept { if (cspec == Hsl && cspec == color.cspec) { return (ct.argb.alpha == color.ct.argb.alpha @@ -2846,7 +2962,7 @@ bool QColor::operator==(const QColor &color) const Q_DECL_NOTHROW Returns \c true if this color has a different RGB and alpha values from \a color; otherwise returns \c false. */ -bool QColor::operator!=(const QColor &color) const Q_DECL_NOTHROW +bool QColor::operator!=(const QColor &color) const noexcept { return !operator==(color); } @@ -2863,7 +2979,7 @@ QColor::operator QVariant() const Marks the color as invalid and sets all components to zero (alpha is set to fully opaque for compatibility with Qt 3). */ -void QColor::invalidate() Q_DECL_NOTHROW +void QColor::invalidate() noexcept { cspec = Invalid; ct.argb.alpha = USHRT_MAX; @@ -2885,6 +3001,8 @@ QDebug operator<<(QDebug dbg, const QColor &c) dbg.nospace() << "QColor(Invalid)"; else if (c.spec() == QColor::Rgb) dbg.nospace() << "QColor(ARGB " << c.alphaF() << ", " << c.redF() << ", " << c.greenF() << ", " << c.blueF() << ')'; + else if (c.spec() == QColor::ExtendedRgb) + dbg.nospace() << "QColor(Ext. ARGB " << c.alphaF() << ", " << c.redF() << ", " << c.greenF() << ", " << c.blueF() << ')'; else if (c.spec() == QColor::Hsv) dbg.nospace() << "QColor(AHSV " << c.alphaF() << ", " << c.hueF() << ", " << c.saturationF() << ", " << c.valueF() << ')'; else if (c.spec() == QColor::Cmyk) diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h index 4822612cf8..e3c267f97d 100644 --- a/src/gui/painting/qcolor.h +++ b/src/gui/painting/qcolor.h @@ -64,35 +64,33 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QColor &); class Q_GUI_EXPORT QColor { public: - enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl }; + enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl, ExtendedRgb }; enum NameFormat { HexRgb, HexArgb }; - inline QColor() Q_DECL_NOTHROW; - QColor(Qt::GlobalColor color) Q_DECL_NOTHROW; + inline QColor() noexcept; + QColor(Qt::GlobalColor color) noexcept; inline QColor(int r, int g, int b, int a = 255); - QColor(QRgb rgb) Q_DECL_NOTHROW; - QColor(QRgba64 rgba64) Q_DECL_NOTHROW; + QColor(QRgb rgb) noexcept; + QColor(QRgba64 rgba64) noexcept; #if QT_STRINGVIEW_LEVEL < 2 inline QColor(const QString& name); #endif explicit inline QColor(QStringView name); inline QColor(const char *aname) : QColor(QLatin1String(aname)) {} inline QColor(QLatin1String name); - QColor(Spec spec) Q_DECL_NOTHROW; + QColor(Spec spec) noexcept; #if QT_VERSION < QT_VERSION_CHECK(6,0,0) - inline QColor(const QColor &color) Q_DECL_NOTHROW; // ### Qt 6: remove all of these, the trivial ones are fine. -# ifdef Q_COMPILER_RVALUE_REFS - QColor(QColor &&other) Q_DECL_NOTHROW : cspec(other.cspec), ct(other.ct) {} - QColor &operator=(QColor &&other) Q_DECL_NOTHROW + inline QColor(const QColor &color) noexcept; // ### Qt 6: remove all of these, the trivial ones are fine. + QColor(QColor &&other) noexcept : cspec(other.cspec), ct(other.ct) {} + QColor &operator=(QColor &&other) noexcept { cspec = other.cspec; ct = other.ct; return *this; } -# endif - QColor &operator=(const QColor &) Q_DECL_NOTHROW; + QColor &operator=(const QColor &) noexcept; #endif // Qt < 6 - QColor &operator=(Qt::GlobalColor color) Q_DECL_NOTHROW; + QColor &operator=(Qt::GlobalColor color) noexcept; - bool isValid() const Q_DECL_NOTHROW; + bool isValid() const noexcept; // ### Qt 6: merge overloads QString name() const; @@ -106,25 +104,25 @@ public: static QStringList colorNames(); - inline Spec spec() const Q_DECL_NOTHROW + inline Spec spec() const noexcept { return cspec; } - int alpha() const Q_DECL_NOTHROW; + int alpha() const noexcept; void setAlpha(int alpha); - qreal alphaF() const Q_DECL_NOTHROW; + qreal alphaF() const noexcept; void setAlphaF(qreal alpha); - int red() const Q_DECL_NOTHROW; - int green() const Q_DECL_NOTHROW; - int blue() const Q_DECL_NOTHROW; + int red() const noexcept; + int green() const noexcept; + int blue() const noexcept; void setRed(int red); void setGreen(int green); void setBlue(int blue); - qreal redF() const Q_DECL_NOTHROW; - qreal greenF() const Q_DECL_NOTHROW; - qreal blueF() const Q_DECL_NOTHROW; + qreal redF() const noexcept; + qreal greenF() const noexcept; + qreal blueF() const noexcept; void setRedF(qreal red); void setGreenF(qreal green); void setBlueF(qreal blue); @@ -135,26 +133,26 @@ public: void getRgbF(qreal *r, qreal *g, qreal *b, qreal *a = nullptr) const; void setRgbF(qreal r, qreal g, qreal b, qreal a = 1.0); - QRgba64 rgba64() const Q_DECL_NOTHROW; - void setRgba64(QRgba64 rgba) Q_DECL_NOTHROW; + QRgba64 rgba64() const noexcept; + void setRgba64(QRgba64 rgba) noexcept; - QRgb rgba() const Q_DECL_NOTHROW; - void setRgba(QRgb rgba) Q_DECL_NOTHROW; + QRgb rgba() const noexcept; + void setRgba(QRgb rgba) noexcept; - QRgb rgb() const Q_DECL_NOTHROW; - void setRgb(QRgb rgb) Q_DECL_NOTHROW; + QRgb rgb() const noexcept; + void setRgb(QRgb rgb) noexcept; - int hue() const Q_DECL_NOTHROW; // 0 <= hue < 360 - int saturation() const Q_DECL_NOTHROW; - int hsvHue() const Q_DECL_NOTHROW; // 0 <= hue < 360 - int hsvSaturation() const Q_DECL_NOTHROW; - int value() const Q_DECL_NOTHROW; + int hue() const noexcept; // 0 <= hue < 360 + int saturation() const noexcept; + int hsvHue() const noexcept; // 0 <= hue < 360 + int hsvSaturation() const noexcept; + int value() const noexcept; - qreal hueF() const Q_DECL_NOTHROW; // 0.0 <= hueF < 360.0 - qreal saturationF() const Q_DECL_NOTHROW; - qreal hsvHueF() const Q_DECL_NOTHROW; // 0.0 <= hueF < 360.0 - qreal hsvSaturationF() const Q_DECL_NOTHROW; - qreal valueF() const Q_DECL_NOTHROW; + qreal hueF() const noexcept; // 0.0 <= hueF < 360.0 + qreal saturationF() const noexcept; + qreal hsvHueF() const noexcept; // 0.0 <= hueF < 360.0 + qreal hsvSaturationF() const noexcept; + qreal valueF() const noexcept; void getHsv(int *h, int *s, int *v, int *a = nullptr) const; void setHsv(int h, int s, int v, int a = 255); @@ -162,15 +160,15 @@ public: void getHsvF(qreal *h, qreal *s, qreal *v, qreal *a = nullptr) const; void setHsvF(qreal h, qreal s, qreal v, qreal a = 1.0); - int cyan() const Q_DECL_NOTHROW; - int magenta() const Q_DECL_NOTHROW; - int yellow() const Q_DECL_NOTHROW; - int black() const Q_DECL_NOTHROW; + int cyan() const noexcept; + int magenta() const noexcept; + int yellow() const noexcept; + int black() const noexcept; - qreal cyanF() const Q_DECL_NOTHROW; - qreal magentaF() const Q_DECL_NOTHROW; - qreal yellowF() const Q_DECL_NOTHROW; - qreal blackF() const Q_DECL_NOTHROW; + qreal cyanF() const noexcept; + qreal magentaF() const noexcept; + qreal yellowF() const noexcept; + qreal blackF() const noexcept; void getCmyk(int *c, int *m, int *y, int *k, int *a = nullptr); // ### Qt 6: remove void getCmyk(int *c, int *m, int *y, int *k, int *a = nullptr) const; @@ -180,13 +178,13 @@ public: void getCmykF(qreal *c, qreal *m, qreal *y, qreal *k, qreal *a = nullptr) const; void setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a = 1.0); - int hslHue() const Q_DECL_NOTHROW; // 0 <= hue < 360 - int hslSaturation() const Q_DECL_NOTHROW; - int lightness() const Q_DECL_NOTHROW; + int hslHue() const noexcept; // 0 <= hue < 360 + int hslSaturation() const noexcept; + int lightness() const noexcept; - qreal hslHueF() const Q_DECL_NOTHROW; // 0.0 <= hueF < 360.0 - qreal hslSaturationF() const Q_DECL_NOTHROW; - qreal lightnessF() const Q_DECL_NOTHROW; + qreal hslHueF() const noexcept; // 0.0 <= hueF < 360.0 + qreal hslSaturationF() const noexcept; + qreal lightnessF() const noexcept; void getHsl(int *h, int *s, int *l, int *a = nullptr) const; void setHsl(int h, int s, int l, int a = 255); @@ -194,21 +192,22 @@ public: void getHslF(qreal *h, qreal *s, qreal *l, qreal *a = nullptr) const; void setHslF(qreal h, qreal s, qreal l, qreal a = 1.0); - QColor toRgb() const Q_DECL_NOTHROW; - QColor toHsv() const Q_DECL_NOTHROW; - QColor toCmyk() const Q_DECL_NOTHROW; - QColor toHsl() const Q_DECL_NOTHROW; + QColor toRgb() const noexcept; + QColor toHsv() const noexcept; + QColor toCmyk() const noexcept; + QColor toHsl() const noexcept; + QColor toExtendedRgb() const noexcept; - Q_REQUIRED_RESULT QColor convertTo(Spec colorSpec) const Q_DECL_NOTHROW; + Q_REQUIRED_RESULT QColor convertTo(Spec colorSpec) const noexcept; - static QColor fromRgb(QRgb rgb) Q_DECL_NOTHROW; - static QColor fromRgba(QRgb rgba) Q_DECL_NOTHROW; + static QColor fromRgb(QRgb rgb) noexcept; + static QColor fromRgba(QRgb rgba) noexcept; static QColor fromRgb(int r, int g, int b, int a = 255); static QColor fromRgbF(qreal r, qreal g, qreal b, qreal a = 1.0); - static QColor fromRgba64(ushort r, ushort g, ushort b, ushort a = USHRT_MAX) Q_DECL_NOTHROW; - static QColor fromRgba64(QRgba64 rgba) Q_DECL_NOTHROW; + static QColor fromRgba64(ushort r, ushort g, ushort b, ushort a = USHRT_MAX) noexcept; + static QColor fromRgba64(QRgba64 rgba) noexcept; static QColor fromHsv(int h, int s, int v, int a = 255); static QColor fromHsvF(qreal h, qreal s, qreal v, qreal a = 1.0); @@ -221,27 +220,27 @@ public: #if QT_DEPRECATED_SINCE(5, 13) QT_DEPRECATED_X("Use QColor::lighter() instead") - Q_REQUIRED_RESULT QColor light(int f = 150) const Q_DECL_NOTHROW; + Q_REQUIRED_RESULT QColor light(int f = 150) const noexcept; QT_DEPRECATED_X("Use QColor::darker() instead") - Q_REQUIRED_RESULT QColor dark(int f = 200) const Q_DECL_NOTHROW; + Q_REQUIRED_RESULT QColor dark(int f = 200) const noexcept; #endif - Q_REQUIRED_RESULT QColor lighter(int f = 150) const Q_DECL_NOTHROW; - Q_REQUIRED_RESULT QColor darker(int f = 200) const Q_DECL_NOTHROW; + Q_REQUIRED_RESULT QColor lighter(int f = 150) const noexcept; + Q_REQUIRED_RESULT QColor darker(int f = 200) const noexcept; - bool operator==(const QColor &c) const Q_DECL_NOTHROW; - bool operator!=(const QColor &c) const Q_DECL_NOTHROW; + bool operator==(const QColor &c) const noexcept; + bool operator!=(const QColor &c) const noexcept; operator QVariant() const; #if QT_STRINGVIEW_LEVEL < 2 static bool isValidColor(const QString &name); #endif - static bool isValidColor(QStringView) Q_DECL_NOTHROW; - static bool isValidColor(QLatin1String) Q_DECL_NOTHROW; + static bool isValidColor(QStringView) noexcept; + static bool isValidColor(QLatin1String) noexcept; private: - void invalidate() Q_DECL_NOTHROW; + void invalidate() noexcept; template <typename String> bool setColorFromString(String name); @@ -275,6 +274,13 @@ private: ushort lightness; ushort pad; } ahsl; + struct { + ushort alphaF16; + ushort redF16; + ushort greenF16; + ushort blueF16; + ushort pad; + } argbExtended; ushort array[5]; } ct; @@ -286,7 +292,7 @@ private: }; Q_DECLARE_TYPEINFO(QColor, QT_VERSION >= QT_VERSION_CHECK(6,0,0) ? Q_MOVABLE_TYPE : Q_RELOCATABLE_TYPE); -inline QColor::QColor() Q_DECL_NOTHROW +inline QColor::QColor() noexcept { invalidate(); } inline QColor::QColor(int r, int g, int b, int a) @@ -304,12 +310,12 @@ inline QColor::QColor(const QString& aname) #endif #if QT_VERSION < QT_VERSION_CHECK(6,0,0) -inline QColor::QColor(const QColor &acolor) Q_DECL_NOTHROW +inline QColor::QColor(const QColor &acolor) noexcept : cspec(acolor.cspec) { ct.argb = acolor.ct.argb; } #endif -inline bool QColor::isValid() const Q_DECL_NOTHROW +inline bool QColor::isValid() const noexcept { return cspec != Invalid; } QT_END_NAMESPACE diff --git a/src/gui/painting/qcolormatrix_p.h b/src/gui/painting/qcolormatrix_p.h new file mode 100644 index 0000000000..66db95df7e --- /dev/null +++ b/src/gui/painting/qcolormatrix_p.h @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QCOLORMATRIX_H +#define QCOLORMATRIX_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/qtguiglobal.h> +#include <QtCore/qpoint.h> +#include <cmath> + +QT_BEGIN_NAMESPACE + +// An abstract 3 value color +class QColorVector +{ +public: + QColorVector() = default; + Q_DECL_CONSTEXPR QColorVector(float x, float y, float z) : x(x), y(y), z(z), _unused(0.0f) { } + explicit Q_DECL_CONSTEXPR QColorVector(const QPointF &chr) // from XY chromaticity + : x(chr.x() / chr.y()) + , y(1.0f) + , z((1.0 - chr.x() - chr.y()) / chr.y()) + , _unused(0.0f) + { } + float x; // X, x or red + float y; // Y, y or green + float z; // Z, Y or blue + float _unused; + + friend inline bool operator==(const QColorVector &v1, const QColorVector &v2); + friend inline bool operator!=(const QColorVector &v1, const QColorVector &v2); + bool isNull() const + { + return !x && !y && !z; + } + + static Q_DECL_CONSTEXPR QColorVector null() { return QColorVector(0.0f, 0.0f, 0.0f); } + static bool isValidChromaticity(const QPointF &chr) + { + if (chr.x() < qreal(0.0) || chr.x() > qreal(1.0)) + return false; + if (chr.y() <= qreal(0.0) || chr.y() > qreal(1.0)) + return false; + if (chr.x() + chr.y() > qreal(1.0)) + return false; + return true; + } + + // Common whitepoints: + static Q_DECL_CONSTEXPR QPointF D50Chromaticity() { return QPointF(0.34567, 0.35850); } + static Q_DECL_CONSTEXPR QPointF D65Chromaticity() { return QPointF(0.31271, 0.32902); } + static Q_DECL_CONSTEXPR QColorVector D50() { return QColorVector(D50Chromaticity()); } + static Q_DECL_CONSTEXPR QColorVector D65() { return QColorVector(D65Chromaticity()); } +}; + +inline bool operator==(const QColorVector &v1, const QColorVector &v2) +{ + return (std::abs(v1.x - v2.x) < (1.0f / 2048.0f)) + && (std::abs(v1.y - v2.y) < (1.0f / 2048.0f)) + && (std::abs(v1.z - v2.z) < (1.0f / 2048.0f)); +} + +inline bool operator!=(const QColorVector &v1, const QColorVector &v2) +{ + return !(v1 == v2); +} + + +// A matrix mapping 3 value colors. +// Not using QMatrix because only floats are needed and performance is critical. +class QColorMatrix +{ +public: + // We are storing the matrix transposed as that is more convenient: + QColorVector r; + QColorVector g; + QColorVector b; + + friend inline bool operator==(const QColorMatrix &m1, const QColorMatrix &m2); + friend inline bool operator!=(const QColorMatrix &m1, const QColorMatrix &m2); + + bool isNull() const + { + return r.isNull() && g.isNull() && b.isNull(); + } + bool isValid() const + { + // A color matrix must be invertible + float det = r.x * (b.z * g.y - g.z * b.y) - + r.y * (b.z * g.x - g.z * b.x) + + r.z * (b.y * g.x - g.y * b.x); + return !qFuzzyIsNull(det); + } + + QColorMatrix inverted() const + { + float det = r.x * (b.z * g.y - g.z * b.y) - + r.y * (b.z * g.x - g.z * b.x) + + r.z * (b.y * g.x - g.y * b.x); + det = 1.0f / det; + QColorMatrix inv; + inv.r.x = (g.y * b.z - b.y * g.z) * det; + inv.r.y = (b.y * r.z - r.y * b.z) * det; + inv.r.z = (r.y * g.z - g.y * r.z) * det; + inv.g.x = (b.x * g.z - g.x * b.z) * det; + inv.g.y = (r.x * b.z - b.x * r.z) * det; + inv.g.z = (g.x * r.z - r.x * g.z) * det; + inv.b.x = (g.x * b.y - b.x * g.y) * det; + inv.b.y = (b.x * r.y - r.x * b.y) * det; + inv.b.z = (r.x * g.y - g.x * r.y) * det; + return inv; + } + QColorMatrix operator*(const QColorMatrix &o) const + { + QColorMatrix comb; + comb.r.x = r.x * o.r.x + g.x * o.r.y + b.x * o.r.z; + comb.g.x = r.x * o.g.x + g.x * o.g.y + b.x * o.g.z; + comb.b.x = r.x * o.b.x + g.x * o.b.y + b.x * o.b.z; + + comb.r.y = r.y * o.r.x + g.y * o.r.y + b.y * o.r.z; + comb.g.y = r.y * o.g.x + g.y * o.g.y + b.y * o.g.z; + comb.b.y = r.y * o.b.x + g.y * o.b.y + b.y * o.b.z; + + comb.r.z = r.z * o.r.x + g.z * o.r.y + b.z * o.r.z; + comb.g.z = r.z * o.g.x + g.z * o.g.y + b.z * o.g.z; + comb.b.z = r.z * o.b.x + g.z * o.b.y + b.z * o.b.z; + return comb; + + } + QColorVector map(const QColorVector &c) const + { + return QColorVector { c.x * r.x + c.y * g.x + c.z * b.x, + c.x * r.y + c.y * g.y + c.z * b.y, + c.x * r.z + c.y * g.z + c.z * b.z }; + } + QColorMatrix transposed() const + { + return QColorMatrix { { r.x, g.x, b.x }, + { r.y, g.y, b.y }, + { r.z, g.z, b.z } }; + } + + static QColorMatrix null() + { + return { QColorVector::null(), QColorVector::null(), QColorVector::null() }; + } + static QColorMatrix identity() + { + return { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } }; + } + static QColorMatrix fromScale(QColorVector v) + { + return QColorMatrix { { v.x, 0.0f, 0.0f }, + { 0.0f, v.y, 0.0f }, + { 0.0f, 0.0f, v.z } }; + } + // These are used to recognize matrices from ICC profiles: + static QColorMatrix toXyzFromSRgb() + { + return QColorMatrix { { 0.4360217452f, 0.2224751115f, 0.0139281144f }, + { 0.3851087987f, 0.7169067264f, 0.0971015394f }, + { 0.1430812478f, 0.0606181994f, 0.7141585946f } }; + } + static QColorMatrix toXyzFromAdobeRgb() + { + return QColorMatrix { { 0.6097189188f, 0.3111021519f, 0.0194766335f }, + { 0.2052682191f, 0.6256770492f, 0.0608891509f }, + { 0.1492247432f, 0.0632209629f, 0.7448224425f } }; + } + static QColorMatrix toXyzFromDciP3D65() + { + return QColorMatrix { { 0.5150973201f, 0.2411795557f, -0.0010491034f }, + { 0.2919696569f, 0.6922441125f, 0.0418830328f }, + { 0.1571449190f, 0.0665764511f, 0.7843542695f } }; + } + static QColorMatrix toXyzFromProPhotoRgb() + { + return QColorMatrix { { 0.7976672649f, 0.2880374491f, 0.0000000000f }, + { 0.1351922452f, 0.7118769884f, 0.0000000000f }, + { 0.0313525312f, 0.0000856627f, 0.8251883388f } }; + } + static QColorMatrix toXyzFromBt2020() + { + return QColorMatrix { { 0.6506130099f, 0.2695676684f, -0.0018652577f }, + { 0.1865101457f, 0.6840794086f, 0.0172256753f }, + { 0.1270887405f, 0.0463530831f, 0.8098278046f } }; + } +}; + +inline bool operator==(const QColorMatrix &m1, const QColorMatrix &m2) +{ + return (m1.r == m2.r) && (m1.g == m2.g) && (m1.b == m2.b); +} + +inline bool operator!=(const QColorMatrix &m1, const QColorMatrix &m2) +{ + return !(m1 == m2); +} + +QT_END_NAMESPACE + +#endif // QCOLORMATRIX_P_H diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp new file mode 100644 index 0000000000..c98c31fe05 --- /dev/null +++ b/src/gui/painting/qcolorspace.cpp @@ -0,0 +1,742 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#include "qcolorspace.h" +#include "qcolorspace_p.h" + +#include "qcolortransform.h" +#include "qcolormatrix_p.h" +#include "qcolortransferfunction_p.h" +#include "qcolortransform_p.h" +#include "qicc_p.h" + +#include <qmath.h> +#include <qtransform.h> + +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Gamut gamut) +{ + switch (gamut) { + case QColorSpace::Gamut::SRgb: + redPoint = QPointF(0.640, 0.330); + greenPoint = QPointF(0.300, 0.600); + bluePoint = QPointF(0.150, 0.060); + whitePoint = QColorVector::D65Chromaticity(); + break; + case QColorSpace::Gamut::DciP3D65: + redPoint = QPointF(0.680, 0.320); + greenPoint = QPointF(0.265, 0.690); + bluePoint = QPointF(0.150, 0.060); + whitePoint = QColorVector::D65Chromaticity(); + break; + case QColorSpace::Gamut::Bt2020: + redPoint = QPointF(0.708, 0.292); + greenPoint = QPointF(0.190, 0.797); + bluePoint = QPointF(0.131, 0.046); + whitePoint = QColorVector::D65Chromaticity(); + break; + case QColorSpace::Gamut::AdobeRgb: + redPoint = QPointF(0.640, 0.330); + greenPoint = QPointF(0.210, 0.710); + bluePoint = QPointF(0.150, 0.060); + whitePoint = QColorVector::D65Chromaticity(); + break; + case QColorSpace::Gamut::ProPhotoRgb: + redPoint = QPointF(0.7347, 0.2653); + greenPoint = QPointF(0.1596, 0.8404); + bluePoint = QPointF(0.0366, 0.0001); + whitePoint = QColorVector::D50Chromaticity(); + break; + default: + Q_UNREACHABLE(); + } +} + +bool QColorSpacePrimaries::areValid() const +{ + if (!QColorVector::isValidChromaticity(redPoint)) + return false; + if (!QColorVector::isValidChromaticity(greenPoint)) + return false; + if (!QColorVector::isValidChromaticity(bluePoint)) + return false; + if (!QColorVector::isValidChromaticity(whitePoint)) + return false; + return true; +} + +QColorMatrix QColorSpacePrimaries::toXyzMatrix() const +{ + // This converts to XYZ in some undefined scale. + QColorMatrix toXyz = { QColorVector(redPoint), + QColorVector(greenPoint), + QColorVector(bluePoint) }; + + // Since the white point should be (1.0, 1.0, 1.0) in the + // input, we can figure out the scale by using the + // inverse conversion on the white point. + QColorVector wXyz(whitePoint); + QColorVector whiteScale = toXyz.inverted().map(wXyz); + + // Now we have scaled conversion to XYZ relative to the given whitepoint + toXyz = toXyz * QColorMatrix::fromScale(whiteScale); + + // But we want a conversion to XYZ relative to D50 + QColorVector wXyzD50 = QColorVector::D50(); + + if (wXyz != wXyzD50) { + // Do chromatic adaptation to map our white point to XYZ D50. + + // The Bradford method chromatic adaptation matrix: + QColorMatrix abrad = { { 0.8951f, -0.7502f, 0.0389f }, + { 0.2664f, 1.7135f, -0.0685f }, + { -0.1614f, 0.0367f, 1.0296f } }; + QColorMatrix abradinv = { { 0.9869929f, 0.4323053f, -0.0085287f }, + { -0.1470543f, 0.5183603f, 0.0400428f }, + { 0.1599627f, 0.0492912f, 0.9684867f } }; + + QColorVector srcCone = abrad.map(wXyz); + QColorVector dstCone = abrad.map(wXyzD50); + + QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 }, + { 0, dstCone.y / srcCone.y, 0 }, + { 0, 0, dstCone.z / srcCone.z } }; + + + QColorMatrix chromaticAdaptation = abradinv * (wToD50 * abrad); + toXyz = chromaticAdaptation * toXyz; + } + + return toXyz; +} + +QColorSpacePrivate::QColorSpacePrivate() + : id(QColorSpace::Unknown) + , gamut(QColorSpace::Gamut::Custom) + , transferFunction(QColorSpace::TransferFunction::Custom) + , gamma(0.0f) + , whitePoint(QColorVector::null()) + , toXyz(QColorMatrix::null()) +{ +} + +QColorSpacePrivate::QColorSpacePrivate(QColorSpace::ColorSpaceId colorSpaceId) + : id(colorSpaceId) +{ + switch (colorSpaceId) { + case QColorSpace::Undefined: + gamut = QColorSpace::Gamut::Custom; + transferFunction = QColorSpace::TransferFunction::Custom; + gamma = 0.0f; + description = QStringLiteral("Undefined"); + break; + case QColorSpace::SRgb: + gamut = QColorSpace::Gamut::SRgb; + transferFunction = QColorSpace::TransferFunction::SRgb; + gamma = 2.31f; // ? + description = QStringLiteral("sRGB"); + break; + case QColorSpace::SRgbLinear: + gamut = QColorSpace::Gamut::SRgb; + transferFunction = QColorSpace::TransferFunction::Linear; + gamma = 1.0f; + description = QStringLiteral("Linear sRGB"); + break; + case QColorSpace::AdobeRgb: + gamut = QColorSpace::Gamut::AdobeRgb; + transferFunction = QColorSpace::TransferFunction::Gamma; + gamma = 2.19921875f; // Not quite 2.2, see https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + description = QStringLiteral("Adobe RGB"); + break; + case QColorSpace::DisplayP3: + gamut = QColorSpace::Gamut::DciP3D65; + transferFunction = QColorSpace::TransferFunction::SRgb; + gamma = 2.31f; // ? + description = QStringLiteral("Display P3"); + break; + case QColorSpace::ProPhotoRgb: + gamut = QColorSpace::Gamut::ProPhotoRgb; + transferFunction = QColorSpace::TransferFunction::ProPhotoRgb; + gamma = 1.8f; + description = QStringLiteral("ProPhoto RGB"); + break; + case QColorSpace::Bt2020: + gamut = QColorSpace::Gamut::Bt2020; + transferFunction = QColorSpace::TransferFunction::Bt2020; + gamma = 2.1f; // ? + description = QStringLiteral("BT.2020"); + break; + case QColorSpace::Unknown: + qWarning("Can not create an unknown color space"); + Q_FALLTHROUGH(); + default: + Q_UNREACHABLE(); + } + initialize(); +} + +QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Gamut gamut, QColorSpace::TransferFunction fun, float gamma) + : gamut(gamut) + , transferFunction(fun) + , gamma(gamma) +{ + if (!identifyColorSpace()) + id = QColorSpace::Unknown; + initialize(); +} + +QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries, + QColorSpace::TransferFunction fun, + float gamma) + : gamut(QColorSpace::Gamut::Custom) + , transferFunction(fun) + , gamma(gamma) +{ + Q_ASSERT(primaries.areValid()); + toXyz = primaries.toXyzMatrix(); + whitePoint = QColorVector(primaries.whitePoint); + if (!identifyColorSpace()) + id = QColorSpace::Unknown; + setTransferFunction(); +} + +bool QColorSpacePrivate::identifyColorSpace() +{ + switch (gamut) { + case QColorSpace::Gamut::SRgb: + if (transferFunction == QColorSpace::TransferFunction::SRgb) { + id = QColorSpace::SRgb; + description = QStringLiteral("sRGB"); + return true; + } + if (transferFunction == QColorSpace::TransferFunction::Linear) { + id = QColorSpace::SRgbLinear; + description = QStringLiteral("Linear sRGB"); + return true; + } + break; + case QColorSpace::Gamut::AdobeRgb: + if (transferFunction == QColorSpace::TransferFunction::Gamma) { + if (qAbs(gamma - 2.19921875f) < (1/1024.0f)) { + id = QColorSpace::AdobeRgb; + description = QStringLiteral("Adobe RGB"); + return true; + } + } + break; + case QColorSpace::Gamut::DciP3D65: + if (transferFunction == QColorSpace::TransferFunction::SRgb) { + id = QColorSpace::DisplayP3; + description = QStringLiteral("Display P3"); + return true; + } + break; + case QColorSpace::Gamut::ProPhotoRgb: + if (transferFunction == QColorSpace::TransferFunction::ProPhotoRgb) { + id = QColorSpace::ProPhotoRgb; + description = QStringLiteral("ProPhoto RGB"); + return true; + } + if (transferFunction == QColorSpace::TransferFunction::Gamma) { + // ProPhoto RGB's curve is effectively gamma 1.8 for 8bit precision. + if (qAbs(gamma - 1.8f) < (1/1024.0f)) { + id = QColorSpace::ProPhotoRgb; + description = QStringLiteral("ProPhoto RGB"); + return true; + } + } + break; + case QColorSpace::Gamut::Bt2020: + if (transferFunction == QColorSpace::TransferFunction::Bt2020) { + id = QColorSpace::Bt2020; + description = QStringLiteral("BT.2020"); + return true; + } + break; + default: + break; + } + return false; +} + +void QColorSpacePrivate::initialize() +{ + setToXyzMatrix(); + setTransferFunction(); +} + +void QColorSpacePrivate::setToXyzMatrix() +{ + if (gamut == QColorSpace::Gamut::Custom) { + toXyz = QColorMatrix::null(); + whitePoint = QColorVector::D50(); + return; + } + QColorSpacePrimaries primaries(gamut); + toXyz = primaries.toXyzMatrix(); + whitePoint = QColorVector(primaries.whitePoint); +} + +void QColorSpacePrivate::setTransferFunction() +{ + switch (transferFunction) { + case QColorSpace::TransferFunction::Linear: + trc[0].m_type = QColorTrc::Type::Function; + trc[0].m_fun = QColorTransferFunction(); + break; + case QColorSpace::TransferFunction::Gamma: + trc[0].m_type = QColorTrc::Type::Function; + trc[0].m_fun = QColorTransferFunction::fromGamma(gamma); + break; + case QColorSpace::TransferFunction::SRgb: + trc[0].m_type = QColorTrc::Type::Function; + trc[0].m_fun = QColorTransferFunction::fromSRgb(); + break; + case QColorSpace::TransferFunction::ProPhotoRgb: + trc[0].m_type = QColorTrc::Type::Function; + trc[0].m_fun = QColorTransferFunction::fromProPhotoRgb(); + break; + case QColorSpace::TransferFunction::Bt2020: + trc[0].m_type = QColorTrc::Type::Function; + trc[0].m_fun = QColorTransferFunction::fromBt2020(); + break; + case QColorSpace::TransferFunction::Custom: + break; + default: + Q_UNREACHABLE(); + break; + } + trc[1] = trc[0]; + trc[2] = trc[0]; +} + +QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpacePrivate *out) const +{ + Q_ASSERT(out); + QColorTransform combined; + combined.d_ptr.reset(new QColorTransformPrivate); + combined.d_ptr->colorSpaceIn = this; + combined.d_ptr->colorSpaceOut = out; + combined.d_ptr->colorMatrix = out->toXyz.inverted() * toXyz; + return combined; +} + +/*! + \class QColorSpace + \brief The QColorSpace class provides a color space abstraction. + \since 5.14 + + \ingroup painting + \ingroup appearance + \inmodule QtGui + + Color values can be interpreted in different ways, and based on the interpretation + can live in different spaces. We call this \e {color spaces}. + + QColorSpace provides access to creating several predefined color spaces and + can generate QColorTransforms for converting colors from one color space to + another. + + QColorSpace can also represent color spaces defined by ICC profiles or embedded + in images, that do not otherwise fit the predefined color spaces. + + A color space can generally speaking be conceived as a combination of a transfer + function and a gamut. The gamut defines which colors the color space can represent. + A color space that can represent a wider range of colors is also known as a + wide-gamut color space. The gamut is defined by three primary colors that represent + exactly how red, green, and blue look in this particular color space, and a white + color that represents where and how bright pure white is. + + The transfer function or gamma curve determines how each component in the + color space is encoded. These are used because human perception does not operate + linearly, and the transfer functions try to ensure that colors will seem evenly + spaced to human eyes. +*/ + + +/*! + \enum QColorSpace::ColorSpaceId + + Predefined color spaces. + + \value Undefined An empty, invalid or unsupported color space. + \value Unknown A valid color space that doesn't match any of the predefined color spaces. + \value SRgb The sRGB color space, which Qt operates in by default. It is a close approximation + of how most classic monitors operate, and a mode most software and hardware support. + \l{http://www.color.org/chardata/rgb/srgb.xalter}{ICC registration of sRGB}. + \value SRgbLinear The sRGB color space with linear gamma. Useful for gamma-corrected blending. + \value AdobeRgb The Adobe RGB color space is a classic wide-gamut color space, using a gamma of 2.2. + \l{http://www.color.org/chardata/rgb/adobergb.xalter}{ICC registration of Adobe RGB (1998)} + \value DisplayP3 A color-space using the primaries of DCI-P3, but with the whitepoint and transfer + function of sRGB. Common in modern wide-gamut screens. + \l{http://www.color.org/chardata/rgb/DCIP3.xalter}{ICC registration of DCI-P3} + \value ProPhotoRgb The Pro Photo RGB color space, also known as ROMM RGB is a very wide gamut color space. + \l{http://www.color.org/chardata/rgb/rommrgb.xalter}{ICC registration of ROMM RGB} + \value Bt2020 BT.2020 also known as Rec.2020 is the color space of HDR TVs. + \l{http://www.color.org/chardata/rgb/BT2020.xalter}{ICC registration of BT.2020} +*/ + +/*! + \enum QColorSpace::Gamut + + Predefined gamuts, or sets of primary colors. + + \value Custom The gamut is undefined or does not match any predefined sets. + \value SRgb The sRGB gamut + \value AdobeRgb The Adobe RGB gamut + \value DciP3D65 The DCI-P3 gamut with the D65 whitepoint + \value ProPhotoRgb The ProPhoto RGB gamut with the D50 whitepoint + \value Bt2020 The BT.2020 gamut +*/ + +/*! + \enum QColorSpace::TransferFunction + + Predefined transfer functions or gamma curves. + + \value Custom The custom or null transfer function + \value Linear The linear transfer functions + \value Gamma A transfer function that is a real gamma curve based on the value of gamma() + \value SRgb The sRGB transfer function, composed of linear and gamma parts + \value ProPhotoRgb The ProPhoto RGB transfer function, composed of linear and gamma parts + \value Bt2020 The BT.2020 transfer function, composed of linear and gamma parts +*/ + +/*! + Creates a new colorspace object that represents \a colorSpaceId. + */ +QColorSpace::QColorSpace(QColorSpace::ColorSpaceId colorSpaceId) +{ + static QExplicitlySharedDataPointer<QColorSpacePrivate> predefinedColorspacePrivates[QColorSpace::Bt2020]; + if (colorSpaceId <= QColorSpace::Unknown) { + if (!predefinedColorspacePrivates[0]) + predefinedColorspacePrivates[0] = new QColorSpacePrivate(QColorSpace::Undefined); + d_ptr = predefinedColorspacePrivates[0]; // unknown and undefined both returns the static undefined colorspace. + } else { + if (!predefinedColorspacePrivates[colorSpaceId - 1]) + predefinedColorspacePrivates[colorSpaceId - 1] = new QColorSpacePrivate(colorSpaceId); + d_ptr = predefinedColorspacePrivates[colorSpaceId - 1]; + } + + Q_ASSERT(colorSpaceId == QColorSpace::Undefined || isValid()); +} + +/*! + Creates a custom color space with the gamut \a gamut, using the transfer function \a fun and + optionally \a gamma. + */ +QColorSpace::QColorSpace(QColorSpace::Gamut gamut, QColorSpace::TransferFunction fun, float gamma) + : d_ptr(new QColorSpacePrivate(gamut, fun, gamma)) +{ +} + +/*! + Creates a custom color space with the gamut \a gamut, using a gamma transfer function of + \a gamma. + */ +QColorSpace::QColorSpace(QColorSpace::Gamut gamut, float gamma) + : d_ptr(new QColorSpacePrivate(gamut, TransferFunction::Gamma, gamma)) +{ +} + +/*! + Creates a custom colorspace with a gamut based on the chromaticities of the primary colors \a whitePoint, + \a redPoint, \a greenPoint and \a bluePoint, and using the transfer function \a fun and optionally \a gamma. + */ +QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint, + const QPointF &greenPoint, const QPointF &bluePoint, + QColorSpace::TransferFunction fun, float gamma) +{ + QColorSpacePrimaries primaries(whitePoint, redPoint, greenPoint, bluePoint); + if (!primaries.areValid()) { + qWarning() << "QColorSpace attempted constructed from invalid primaries:" << whitePoint << redPoint << greenPoint << bluePoint; + d_ptr = QColorSpace(QColorSpace::Undefined).d_ptr; + return; + } + d_ptr = new QColorSpacePrivate(primaries, fun, gamma); +} + +QColorSpace::~QColorSpace() +{ +} + +QColorSpace::QColorSpace(QColorSpace &&colorSpace) + : d_ptr(std::move(colorSpace.d_ptr)) +{ +} + +QColorSpace::QColorSpace(const QColorSpace &colorSpace) + : d_ptr(colorSpace.d_ptr) +{ +} + +QColorSpace &QColorSpace::operator=(QColorSpace &&colorSpace) +{ + d_ptr = std::move(colorSpace.d_ptr); + return *this; +} + +QColorSpace &QColorSpace::operator=(const QColorSpace &colorSpace) +{ + d_ptr = colorSpace.d_ptr; + return *this; +} + +/*! + Returns the id of the predefined color space this object + represents or \c Unknown if it doesn't match any of them. +*/ +QColorSpace::ColorSpaceId QColorSpace::colorSpaceId() const noexcept +{ + return d_ptr->id; +} + +/*! + Returns the predefined gamut of the color space + or \c Gamut::Custom if it doesn't match any of them. +*/ +QColorSpace::Gamut QColorSpace::gamut() const noexcept +{ + return d_ptr->gamut; +} + +/*! + Returns the predefined transfer function of the color space + or \c TransferFunction::Custom if it doesn't match any of them. + + \sa gamma() +*/ +QColorSpace::TransferFunction QColorSpace::transferFunction() const noexcept +{ + return d_ptr->transferFunction; +} + +/*! + Returns the gamma value of color spaces with \c TransferFunction::Gamma, + an approximate gamma value for other predefined color spaces, or + 0.0 if no approximate gamma is known. + + \sa transferFunction() +*/ +float QColorSpace::gamma() const noexcept +{ + return d_ptr->gamma; +} + +/*! + Returns an ICC profile representing the color space. + + If the color space was generated from an ICC profile, that profile + is returned, otherwise one is generated. + + \note Even invalid color spaces may return the ICC profile if they + were generated from one, to allow applications to implement wider + support themselves. + + \sa fromIccProfile() +*/ +QByteArray QColorSpace::iccProfile() const +{ + if (!d_ptr->iccProfile.isEmpty()) + return d_ptr->iccProfile; + if (!isValid()) + return QByteArray(); + return QIcc::toIccProfile(*this); +} + +/*! + Creates a QColorSpace from ICC profile \a iccProfile. + + \note Not all ICC profiles are supported. QColorSpace only supports + RGB-XYZ ICC profiles that are three-component matrix-based. + + If the ICC profile is not supported an invalid QColorSpace is returned + where you can still read the original ICC profile using iccProfile(). + + \sa iccProfile() +*/ +QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile) +{ + QColorSpace colorSpace; + if (QIcc::fromIccProfile(iccProfile, &colorSpace)) + return colorSpace; + colorSpace.d_ptr->id = QColorSpace::Undefined; + colorSpace.d_ptr->iccProfile = iccProfile; + return colorSpace; +} + +/*! + Returns \c true if the color space is valid. +*/ +bool QColorSpace::isValid() const noexcept +{ + return d_ptr->id != QColorSpace::Undefined && d_ptr->toXyz.isValid() + && d_ptr->trc[0].isValid() && d_ptr->trc[1].isValid() && d_ptr->trc[2].isValid(); +} + +/*! + \relates QColorSpace + Returns \c true if colorspace \a colorSpace1 is equal to colorspace \a colorSpace2; + otherwise returns \c false +*/ +bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2) +{ + if (colorSpace1.d_ptr == colorSpace2.d_ptr) + return true; + + if (colorSpace1.colorSpaceId() == QColorSpace::Undefined && colorSpace2.colorSpaceId() == QColorSpace::Undefined) + return colorSpace1.d_ptr->iccProfile == colorSpace2.d_ptr->iccProfile; + + if (colorSpace1.colorSpaceId() != QColorSpace::Unknown && colorSpace2.colorSpaceId() != QColorSpace::Unknown) + return colorSpace1.colorSpaceId() == colorSpace2.colorSpaceId(); + + if (colorSpace1.gamut() != QColorSpace::Gamut::Custom && colorSpace2.gamut() != QColorSpace::Gamut::Custom) { + if (colorSpace1.gamut() != colorSpace2.gamut()) + return false; + } else { + if (colorSpace1.d_ptr->toXyz != colorSpace2.d_ptr->toXyz) + return false; + } + + if (colorSpace1.transferFunction() != QColorSpace::TransferFunction::Custom && + colorSpace2.transferFunction() != QColorSpace::TransferFunction::Custom) { + if (colorSpace1.transferFunction() != colorSpace2.transferFunction()) + return false; + if (colorSpace1.transferFunction() == QColorSpace::TransferFunction::Gamma) + return colorSpace1.gamma() == colorSpace2.gamma(); + return true; + } + + if (colorSpace1.d_ptr->trc[0] != colorSpace2.d_ptr->trc[0] || + colorSpace1.d_ptr->trc[1] != colorSpace2.d_ptr->trc[1] || + colorSpace1.d_ptr->trc[2] != colorSpace2.d_ptr->trc[2]) + return false; + + return true; +} + +/*! + \fn bool operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2) + \relates QColorSpace + + Returns \c true if colorspace \a colorspace1 is not equal to colorspace \a colorspace2; + otherwise returns \c false +*/ + +/*! + Generates and returns a color space transformation from this color space to + \a colorspace. +*/ +QColorTransform QColorSpace::transformationToColorSpace(const QColorSpace &colorspace) const +{ + if (!isValid() || !colorspace.isValid()) + return QColorTransform(); + + return d_ptr->transformationToColorSpace(colorspace.d_ptr.constData()); +} + +/*! + \internal +*/ +QColorSpacePrivate *QColorSpace::d_func() +{ + d_ptr.detach(); + return d_ptr.data(); +} + +/*! + \fn const QColorSpacePrivate* QColorSpacePrivate::d_func() const + \internal +*/ + +/***************************************************************************** + QColorSpace stream functions + *****************************************************************************/ +#if !defined(QT_NO_DATASTREAM) +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QColorSpace &colorSpace) + \relates QColorSpace + + Writes the given \a colorSpace to the given \a stream as an ICC profile. + + \sa QColorSpace::iccProfile(), {Serializing Qt Data Types} +*/ + +QDataStream &operator<<(QDataStream &s, const QColorSpace &image) +{ + s << image.iccProfile(); + return s; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QColorSpace &colorSpace) + \relates QColorSpace + + Reads a color space from the given \a stream and stores it in the given + \a colorSpace. + + \sa QColorSpace::fromIccProfile(), {Serializing Qt Data Types} +*/ + +QDataStream &operator>>(QDataStream &s, QColorSpace &colorSpace) +{ + QByteArray iccProfile; + s >> iccProfile; + colorSpace = QColorSpace::fromIccProfile(iccProfile); + return s; +} +#endif // QT_NO_DATASTREAM + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace) +{ + QDebugStateSaver saver(dbg); + dbg.nospace(); + dbg << "QColorSpace("; + dbg << colorSpace.colorSpaceId() << ", " << colorSpace.gamut() << ", " << colorSpace.transferFunction(); + dbg << ", gamma=" << colorSpace.gamma(); + dbg << ')'; + return dbg; +} +#endif + +QT_END_NAMESPACE diff --git a/src/gui/painting/qcolorspace.h b/src/gui/painting/qcolorspace.h new file mode 100644 index 0000000000..56676826a9 --- /dev/null +++ b/src/gui/painting/qcolorspace.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QCOLORSPACE_H +#define QCOLORSPACE_H + +#include <QtGui/qtguiglobal.h> +#include <QtGui/qcolortransform.h> +#include <QtCore/qshareddata.h> + +QT_BEGIN_NAMESPACE + +class QColorSpacePrivate; + +class Q_GUI_EXPORT QColorSpace +{ + Q_GADGET +public: + enum ColorSpaceId { + Undefined = 0, + Unknown = 1, + SRgb, + SRgbLinear, + AdobeRgb, + DisplayP3, + ProPhotoRgb, + Bt2020, + }; + Q_ENUM(ColorSpaceId) + enum class Gamut { + Custom = 0, + SRgb, + AdobeRgb, + DciP3D65, + ProPhotoRgb, + Bt2020, + }; + Q_ENUM(Gamut) + enum class TransferFunction { + Custom = 0, + Linear, + Gamma, + SRgb, + ProPhotoRgb, + Bt2020, + }; + Q_ENUM(TransferFunction) + + QColorSpace(ColorSpaceId colorSpaceId = Undefined); + QColorSpace(Gamut gamut, TransferFunction fun, float gamma = 0.0f); + QColorSpace(Gamut gamut, float gamma); + QColorSpace(const QPointF &whitePoint, const QPointF &redPoint, + const QPointF &greenPoint, const QPointF &bluePoint, + TransferFunction fun, float gamma = 0.0f); + ~QColorSpace(); + + QColorSpace(QColorSpace &&colorSpace); + QColorSpace(const QColorSpace &colorSpace); + QColorSpace &operator=(QColorSpace &&colorSpace); + QColorSpace &operator=(const QColorSpace &colorSpace); + + ColorSpaceId colorSpaceId() const noexcept; + Gamut gamut() const noexcept; + TransferFunction transferFunction() const noexcept; + float gamma() const noexcept; + + bool isValid() const noexcept; + + friend Q_GUI_EXPORT bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2); + friend inline bool operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2); + + static QColorSpace fromIccProfile(const QByteArray &iccProfile); + QByteArray iccProfile() const; + + QColorTransform transformationToColorSpace(const QColorSpace &colorspace) const; + + QColorSpacePrivate *d_func(); + inline const QColorSpacePrivate *d_func() const { return d_ptr.constData(); } + +private: + friend class QColorSpacePrivate; + QExplicitlySharedDataPointer<QColorSpacePrivate> d_ptr; +}; + +bool Q_GUI_EXPORT operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2); +inline bool operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2) +{ + return !(colorSpace1 == colorSpace2); +} + +// QColorSpace stream functions +#if !defined(QT_NO_DATASTREAM) +Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QColorSpace &); +Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QColorSpace &); +#endif + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug, const QColorSpace &); +#endif + +QT_END_NAMESPACE + +#endif // QCOLORSPACE_P_H diff --git a/src/gui/painting/qcolorspace_p.h b/src/gui/painting/qcolorspace_p.h new file mode 100644 index 0000000000..a6ab2ab5cd --- /dev/null +++ b/src/gui/painting/qcolorspace_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QCOLORSPACE_P_H +#define QCOLORSPACE_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 "qcolorspace.h" +#include "qcolormatrix_p.h" +#include "qcolortrc_p.h" +#include "qcolortrclut_p.h" + +#include <QtCore/qshareddata.h> +#include <QtCore/qpoint.h> + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QColorSpacePrimaries +{ +public: + QColorSpacePrimaries() = default; + QColorSpacePrimaries(QColorSpace::Gamut gamut); + QColorSpacePrimaries(QPointF whitePoint, + QPointF redPoint, + QPointF greenPoint, + QPointF bluePoint) + : whitePoint(whitePoint) + , redPoint(redPoint) + , greenPoint(greenPoint) + , bluePoint(bluePoint) + { } + + QColorMatrix toXyzMatrix() const; + bool areValid() const; + + QPointF whitePoint; + QPointF redPoint; + QPointF greenPoint; + QPointF bluePoint; +}; + +class QColorSpacePrivate : public QSharedData +{ +public: + QColorSpacePrivate(); + QColorSpacePrivate(QColorSpace::ColorSpaceId colorSpaceId); + QColorSpacePrivate(QColorSpace::Gamut gamut, QColorSpace::TransferFunction fun, float gamma); + QColorSpacePrivate(const QColorSpacePrimaries &primaries, QColorSpace::TransferFunction fun, float gamma); + QColorSpacePrivate(const QColorSpacePrivate &other) = default; + + void initialize(); + void setToXyzMatrix(); + void setTransferFunction(); + bool identifyColorSpace(); + QColorTransform transformationToColorSpace(const QColorSpacePrivate *out) const; + + QColorSpace::ColorSpaceId id; + QColorSpace::Gamut gamut; + QColorSpace::TransferFunction transferFunction; + float gamma; + QColorVector whitePoint; + + QColorTrc trc[3]; + QColorMatrix toXyz; + + QString description; + QByteArray iccProfile; + + mutable QSharedPointer<QColorTrcLut> lut[3]; + mutable QAtomicInt lutsGenerated; +}; + +QT_END_NAMESPACE + +#endif // QCOLORSPACE_P_H diff --git a/src/gui/painting/qcolortransferfunction_p.h b/src/gui/painting/qcolortransferfunction_p.h new file mode 100644 index 0000000000..fd7cfa2b2b --- /dev/null +++ b/src/gui/painting/qcolortransferfunction_p.h @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QCOLORTRANSFERFUNCTION_P_H +#define QCOLORTRANSFERFUNCTION_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 <cmath> + +QT_BEGIN_NAMESPACE + +// Defines a ICC parametric curve type 4 +class Q_GUI_EXPORT QColorTransferFunction +{ +public: + QColorTransferFunction() noexcept + : m_a(1.0f), m_b(0.0f), m_c(1.0f), m_d(0.0f), m_e(0.0f), m_f(0.0f), m_g(1.0f), m_flags(0) + { } + QColorTransferFunction(float a, float b, float c, float d, float e, float f, float g) noexcept + : m_a(a), m_b(b), m_c(c), m_d(d), m_e(e), m_f(f), m_g(g), m_flags(0) + { } + + bool isGamma() const + { + updateHints(); + return m_flags & quint32(Hints::IsGamma); + } + bool isLinear() const + { + updateHints(); + return m_flags & quint32(Hints::IsLinear); + } + bool isSRgb() const + { + updateHints(); + return m_flags & quint32(Hints::IsSRgb); + } + + float apply(float x) const + { + if (x < m_d) + return m_c * x + m_f; + else + return std::pow(m_a * x + m_b, m_g) + m_e; + } + + QColorTransferFunction inverted() const + { + float a, b, c, d, e, f, g; + + d = m_c * m_d + m_f; + + if (!qFuzzyIsNull(m_c)) { + c = 1.0f / m_c; + f = -m_f / m_c; + } else { + c = 0.0f; + f = 0.0f; + } + + if (!qFuzzyIsNull(m_a) && !qFuzzyIsNull(m_g)) { + a = std::pow(1.0f / m_a, m_g); + b = -a * m_e; + e = -m_b / m_a; + g = 1.0f / m_g; + } else { + a = 0.0f; + b = 0.0f; + e = 1.0f; + g = 1.0f; + } + + return QColorTransferFunction(a, b, c, d, e, f, g); + } + + // A few predefined curves: + static QColorTransferFunction fromGamma(float gamma) + { + return QColorTransferFunction(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, gamma); + } + static QColorTransferFunction fromSRgb() + { + return QColorTransferFunction(1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045f, 0.0f, 0.0f, 2.4f); + } + static QColorTransferFunction fromBt2020() + { + return QColorTransferFunction(1.0f / 1.0993f, 0.0993f / 1.0993f, 1.0f / 4.5f, 0.08145f, 0.0f, 0.0f, 2.2f); + } + static QColorTransferFunction fromProPhotoRgb() + { + return QColorTransferFunction(1.0f, 0.0f, 1.0f / 16.0f, 16.0f / 512.0f, 0.0f, 0.0f, 1.8f); + } + bool matches(const QColorTransferFunction &o) const + { + return paramCompare(m_a, o.m_a) && paramCompare(m_b, o.m_b) + && paramCompare(m_c, o.m_c) && paramCompare(m_d, o.m_d) + && paramCompare(m_e, o.m_e) && paramCompare(m_f, o.m_f) + && paramCompare(m_g, o.m_g); + } + friend inline bool operator==(const QColorTransferFunction &f1, const QColorTransferFunction &f2); + friend inline bool operator!=(const QColorTransferFunction &f1, const QColorTransferFunction &f2); + + float m_a; + float m_b; + float m_c; + float m_d; + float m_e; + float m_f; + float m_g; + +private: + static inline bool paramCompare(float p1, float p2) + { + // Much fuzzier than fuzzy compare. + // It tries match parameters that has been passed through a 8.8 + // fixed point form. + return (qAbs(p1 - p2) <= (1.0f / 512.0f)); + } + + void updateHints() const + { + if (m_flags & quint32(Hints::Calculated)) + return; + // We do not consider the case with m_d = 1.0f linear or simple, + // since it wouldn't be linear for applyExtended(). + bool simple = paramCompare(m_a, 1.0f) && paramCompare(m_b, 0.0f) + && paramCompare(m_d, 0.0f) + && paramCompare(m_e, 0.0f); + if (simple) { + m_flags |= quint32(Hints::IsGamma); + if (qFuzzyCompare(m_g, 1.0f)) + m_flags |= quint32(Hints::IsLinear); + } else { + if (*this == fromSRgb()) + m_flags |= quint32(Hints::IsSRgb); + } + m_flags |= quint32(Hints::Calculated); + } + enum class Hints : quint32 { + Calculated = 1, + IsGamma = 2, + IsLinear = 4, + IsSRgb = 8 + }; + mutable quint32 m_flags; +}; + +inline bool operator==(const QColorTransferFunction &f1, const QColorTransferFunction &f2) +{ + return f1.matches(f2); +} +inline bool operator!=(const QColorTransferFunction &f1, const QColorTransferFunction &f2) +{ + return !f1.matches(f2); +} + +QT_END_NAMESPACE + +#endif // QCOLORTRANSFERFUNCTION_P_H diff --git a/src/gui/painting/qcolortransfertable_p.h b/src/gui/painting/qcolortransfertable_p.h new file mode 100644 index 0000000000..c8b2f7bd92 --- /dev/null +++ b/src/gui/painting/qcolortransfertable_p.h @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QCOLORTRANSFERTABLE_P_H +#define QCOLORTRANSFERTABLE_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 "qcolortransferfunction_p.h" + +#include <QVector> +#include <cmath> + +QT_BEGIN_NAMESPACE + +// Defines either an ICC TRC 'curve' or a lut8/lut16 A or B table +class Q_GUI_EXPORT QColorTransferTable +{ +public: + QColorTransferTable() noexcept + : m_tableSize(0) + { } + QColorTransferTable(uint32_t size, const QVector<uint8_t> &table) noexcept + : m_tableSize(size) + , m_table8(table) + { } + QColorTransferTable(uint32_t size, const QVector<uint16_t> &table) noexcept + : m_tableSize(size) + , m_table16(table) + { } + + bool isValid() const + { + if (m_tableSize < 2) + return false; + +#if !defined(QT_NO_DEBUG) + // The table must describe an injective curve: + if (!m_table8.isEmpty()) { + uint8_t val = 0; + for (uint i = 0; i < m_tableSize; ++i) { + Q_ASSERT(m_table8[i] >= val); + val = m_table8[i]; + } + } + if (!m_table16.isEmpty()) { + uint16_t val = 0; + for (uint i = 0; i < m_tableSize; ++i) { + Q_ASSERT(m_table16[i] >= val); + val = m_table16[i]; + } + } +#endif + return !m_table8.isEmpty() || !m_table16.isEmpty(); + } + + float apply(float x) const + { + x = std::min(std::max(x, 0.0f), 1.0f); + x *= m_tableSize - 1; + uint32_t lo = (int)std::floor(x); + uint32_t hi = std::min(lo + 1, m_tableSize); + float frac = x - lo; + if (!m_table16.isEmpty()) + return (m_table16[lo] * (1.0f - frac) + m_table16[hi] * frac) * (1.0f/65535.0f); + if (!m_table8.isEmpty()) + return (m_table8[lo] * (1.0f - frac) + m_table8[hi] * frac) * (1.0f/255.0f); + return x; + } + + // Apply inverse, optimized by giving a previous result a value < x. + float applyInverse(float x, float resultLargerThan = 0.0f) const + { + Q_ASSERT(resultLargerThan >= 0.0f && resultLargerThan <= 1.0f); + if (x <= 0.0f) + return 0.0f; + if (x >= 1.0f) + return 1.0f; + if (!m_table16.isEmpty()) { + float v = x * 65535.0f; + uint i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1; + for ( ; i < m_tableSize; ++i) { + if (m_table16[i] > v) + break; + } + if (i >= m_tableSize - 1) + return 1.0f; + float y1 = m_table16[i - 1]; + float y2 = m_table16[i]; + Q_ASSERT(x >= y1 && x < y2); + float fr = (v - y1) / (y2 - y1); + return (i + fr) * (1.0f / (m_tableSize - 1)); + + } + if (!m_table8.isEmpty()) { + float v = x * 255.0f; + uint i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1; + for ( ; i < m_tableSize; ++i) { + if (m_table8[i] > v) + break; + } + if (i >= m_tableSize - 1) + return 1.0f; + float y1 = m_table8[i - 1]; + float y2 = m_table8[i]; + Q_ASSERT(x >= y1 && x < y2); + float fr = (v - y1) / (y2 - y1); + return (i + fr) * (1.0f / (m_tableSize - 1)); + } + return x; + } + + bool asColorTransferFunction(QColorTransferFunction *transferFn) + { + Q_ASSERT(isValid()); + Q_ASSERT(transferFn); + if (!m_table8.isEmpty() && (m_table8[0] != 0 || m_table8[m_tableSize - 1] != 255)) + return false; + if (!m_table16.isEmpty() && (m_table16[0] != 0 || m_table16[m_tableSize - 1] != 65535)) + return false; + if (m_tableSize == 2) { + *transferFn = QColorTransferFunction(); // Linear + return true; + } + // The following heuristics are based on those from Skia: + if (m_tableSize == 26 && !m_table16.isEmpty()) { + // code.facebook.com/posts/411525055626587/under-the-hood-improving-facebook-photos + if (m_table16[6] != 3062) + return false; + if (m_table16[12] != 12824) + return false; + if (m_table16[18] != 31237) + return false; + *transferFn = QColorTransferFunction::fromSRgb(); + return true; + } + if (m_tableSize == 1024 && !m_table16.isEmpty()) { + // HP and Canon sRGB gamma tables: + if (m_table16[257] != 3366) + return false; + if (m_table16[513] != 14116) + return false; + if (m_table16[768] != 34318) + return false; + *transferFn = QColorTransferFunction::fromSRgb(); + return true; + } + if (m_tableSize == 4096 && !m_table16.isEmpty()) { + // Nikon, Epson, and lcms2 sRGB gamma tables: + if (m_table16[515] != 960) + return false; + if (m_table16[1025] != 3342) + return false; + if (m_table16[2051] != 14079) + return false; + *transferFn = QColorTransferFunction::fromSRgb(); + return true; + } + return false; + } + friend inline bool operator!=(const QColorTransferTable &t1, const QColorTransferTable &t2); + friend inline bool operator==(const QColorTransferTable &t1, const QColorTransferTable &t2); + + uint32_t m_tableSize; + QVector<uint8_t> m_table8; + QVector<uint16_t> m_table16; +}; + +inline bool operator!=(const QColorTransferTable &t1, const QColorTransferTable &t2) +{ + if (t1.m_tableSize != t2.m_tableSize) + return true; + if (t1.m_table8.isEmpty() != t2.m_table8.isEmpty()) + return true; + if (t1.m_table16.isEmpty() != t2.m_table16.isEmpty()) + return true; + if (!t1.m_table8.isEmpty()) { + for (quint32 i = 0; i < t1.m_tableSize; ++i) { + if (t1.m_table8[i] != t2.m_table8[i]) + return true; + } + } + if (!t1.m_table16.isEmpty()) { + for (quint32 i = 0; i < t1.m_tableSize; ++i) { + if (t1.m_table16[i] != t2.m_table16[i]) + return true; + } + } + return false; +} + +inline bool operator==(const QColorTransferTable &t1, const QColorTransferTable &t2) +{ + return !(t1 != t2); +} + +QT_END_NAMESPACE + +#endif // QCOLORTRANSFERTABLE_P_H diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp new file mode 100644 index 0000000000..c723e12f8a --- /dev/null +++ b/src/gui/painting/qcolortransform.cpp @@ -0,0 +1,696 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + + +#include "qcolortransform.h" +#include "qcolortransform_p.h" + +#include "qcolormatrix_p.h" +#include "qcolorspace_p.h" +#include "qcolortrc_p.h" +#include "qcolortrclut_p.h" + +#include <QtCore/qatomic.h> +#include <QtCore/qmath.h> +#include <QtGui/qcolor.h> +#include <QtGui/qtransform.h> +#include <QtCore/private/qsimd_p.h> + +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +QColorTrcLut *lutFromTrc(const QColorTrc &trc) +{ + if (trc.m_type == QColorTrc::Type::Table) + return QColorTrcLut::fromTransferTable(trc.m_table); + if (trc.m_type == QColorTrc::Type::Function) + return QColorTrcLut::fromTransferFunction(trc.m_fun); + qWarning() << "TRC uninitialized"; + return nullptr; +} + +void QColorTransformPrivate::updateLutsIn() const +{ + if (colorSpaceIn->lutsGenerated.loadAcquire()) + return; + for (int i = 0; i < 3; ++i) { + if (!colorSpaceIn->trc[i].isValid()) + return; + } + + if (colorSpaceIn->trc[0] == colorSpaceIn->trc[1] && colorSpaceIn->trc[0] == colorSpaceIn->trc[2]) { + colorSpaceIn->lut[0].reset(lutFromTrc(colorSpaceIn->trc[0])); + colorSpaceIn->lut[1] = colorSpaceIn->lut[0]; + colorSpaceIn->lut[2] = colorSpaceIn->lut[0]; + } else { + for (int i = 0; i < 3; ++i) + colorSpaceIn->lut[i].reset(lutFromTrc(colorSpaceIn->trc[i])); + } + + colorSpaceIn->lutsGenerated.storeRelease(1); +} + +void QColorTransformPrivate::updateLutsOut() const +{ + if (colorSpaceOut->lutsGenerated.loadAcquire()) + return; + for (int i = 0; i < 3; ++i) { + if (!colorSpaceOut->trc[i].isValid()) + return; + } + + if (colorSpaceOut->trc[0] == colorSpaceOut->trc[1] && colorSpaceOut->trc[0] == colorSpaceOut->trc[2]) { + colorSpaceOut->lut[0].reset(lutFromTrc(colorSpaceOut->trc[0])); + colorSpaceOut->lut[1] = colorSpaceOut->lut[0]; + colorSpaceOut->lut[2] = colorSpaceOut->lut[0]; + } else { + for (int i = 0; i < 3; ++i) + colorSpaceOut->lut[i].reset(lutFromTrc(colorSpaceOut->trc[i])); + } + + colorSpaceOut->lutsGenerated.storeRelease(1); +} + +/*! + \class QColorTransform + \brief The QColorTransform class is a transformation between color spaces. + \since 5.14 + + \ingroup painting + \ingroup appearance + \inmodule QtGui + + QColorTransform is an instantiation of a transformation between color spaces. + It can be applied on color and pixels to convert them from one color space to + another. + + Setting up a QColorTransform takes some preprocessing, so keeping around + QColorTransforms that you need often is recommended, instead of generating + them on the fly. +*/ + + +QColorTransform::~QColorTransform() noexcept +{ +} + +/*! + Applies the color transformation on the QRgb value \a argb. + + The input should be opaque or unpremultiplied. +*/ +QRgb QColorTransform::map(const QRgb &argb) const +{ + if (!d_ptr) + return argb; + Q_D(const QColorTransform); + constexpr float f = 1.0f / 255.0f; + QColorVector c = { qRed(argb) * f, qGreen(argb) * f, qBlue(argb) * f }; + c.x = d->colorSpaceIn->trc[0].apply(c.x); + c.y = d->colorSpaceIn->trc[1].apply(c.y); + c.z = d->colorSpaceIn->trc[2].apply(c.z); + c = d->colorMatrix.map(c); + c.x = std::max(0.0f, std::min(1.0f, c.x)); + c.y = std::max(0.0f, std::min(1.0f, c.y)); + c.z = std::max(0.0f, std::min(1.0f, c.z)); + if (d->colorSpaceOut->lutsGenerated.loadAcquire()) { + c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x); + c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y); + c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z); + } else { + c.x = d->colorSpaceOut->trc[0].applyInverse(c.x); + c.y = d->colorSpaceOut->trc[1].applyInverse(c.y); + c.z = d->colorSpaceOut->trc[2].applyInverse(c.z); + } + + return qRgba(c.x * 255 + 0.5f, c.y * 255 + 0.5f, c.z * 255 + 0.5f, qAlpha(argb)); +} + +/*! + Applies the color transformation on the QRgba64 value \a rgba64. + + The input should be opaque or unpremultiplied. +*/ +QRgba64 QColorTransform::map(const QRgba64 &rgba64) const +{ + if (!d_ptr) + return rgba64; + Q_D(const QColorTransform); + constexpr float f = 1.0f / 65535.0f; + QColorVector c = { rgba64.red() * f, rgba64.green() * f, rgba64.blue() * f }; + c.x = d->colorSpaceIn->trc[0].apply(c.x); + c.y = d->colorSpaceIn->trc[1].apply(c.y); + c.z = d->colorSpaceIn->trc[2].apply(c.z); + c = d->colorMatrix.map(c); + c.x = std::max(0.0f, std::min(1.0f, c.x)); + c.y = std::max(0.0f, std::min(1.0f, c.y)); + c.z = std::max(0.0f, std::min(1.0f, c.z)); + if (d->colorSpaceOut->lutsGenerated.loadAcquire()) { + c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x); + c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y); + c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z); + } else { + c.x = d->colorSpaceOut->trc[0].applyInverse(c.x); + c.y = d->colorSpaceOut->trc[1].applyInverse(c.y); + c.z = d->colorSpaceOut->trc[2].applyInverse(c.z); + } + + return QRgba64::fromRgba64(c.x * 65535, c.y * 65535, c.z * 65535, rgba64.alpha()); +} + +/*! + Applies the color transformation on the QColor value \a color. + +*/ +QColor QColorTransform::map(const QColor &color) const +{ + if (!d_ptr) + return color; + Q_D(const QColorTransform); + QColor clr = color; + if (color.spec() != QColor::ExtendedRgb || color.spec() != QColor::Rgb) + clr = clr.toRgb(); + + QColorVector c = { (float)clr.redF(), (float)clr.greenF(), (float)clr.blueF() }; + if (clr.spec() == QColor::ExtendedRgb) { + c.x = d->colorSpaceIn->trc[0].applyExtended(c.x); + c.y = d->colorSpaceIn->trc[1].applyExtended(c.y); + c.z = d->colorSpaceIn->trc[2].applyExtended(c.z); + } else { + c.x = d->colorSpaceIn->trc[0].apply(c.x); + c.y = d->colorSpaceIn->trc[1].apply(c.y); + c.z = d->colorSpaceIn->trc[2].apply(c.z); + } + c = d->colorMatrix.map(c); + bool inGamut = c.x >= 0.0f && c.x <= 1.0f && c.y >= 0.0f && c.y <= 1.0f && c.z >= 0.0f && c.z <= 1.0f; + if (inGamut) { + if (d_ptr->colorSpaceOut->lutsGenerated.loadAcquire()) { + c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x); + c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y); + c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z); + } else { + c.x = d->colorSpaceOut->trc[0].applyInverse(c.x); + c.y = d->colorSpaceOut->trc[1].applyInverse(c.y); + c.z = d->colorSpaceOut->trc[2].applyInverse(c.z); + } + } else { + c.x = d->colorSpaceOut->trc[0].applyInverseExtended(c.x); + c.y = d->colorSpaceOut->trc[1].applyInverseExtended(c.y); + c.z = d->colorSpaceOut->trc[2].applyInverseExtended(c.z); + } + QColor out; + out.setRgbF(c.x, c.y, c.z, color.alphaF()); + return out; +} + +// Optimized sub-routines for fast block based conversion: + +static void applyMatrix(QColorVector *buffer, const qsizetype len, const QColorMatrix &colorMatrix) +{ +#if defined(__SSE2__) + const __m128 minV = _mm_set1_ps(0.0f); + const __m128 maxV = _mm_set1_ps(1.0f); + const __m128 xMat = _mm_loadu_ps(&colorMatrix.r.x); + const __m128 yMat = _mm_loadu_ps(&colorMatrix.g.x); + const __m128 zMat = _mm_loadu_ps(&colorMatrix.b.x); + for (qsizetype j = 0; j < len; ++j) { + __m128 c = _mm_loadu_ps(&buffer[j].x); + __m128 cx = _mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 cy = _mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 cz = _mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)); + cx = _mm_mul_ps(cx, xMat); + cy = _mm_mul_ps(cy, yMat); + cz = _mm_mul_ps(cz, zMat); + cx = _mm_add_ps(cx, cy); + cx = _mm_add_ps(cx, cz); + // Clamp: + cx = _mm_min_ps(cx, maxV); + cx = _mm_max_ps(cx, minV); + _mm_storeu_ps(&buffer[j].x, cx); + } +#else + for (int j = 0; j < len; ++j) { + const QColorVector cv = colorMatrix.map(buffer[j]); + buffer[j].x = std::max(0.0f, std::min(1.0f, cv.x)); + buffer[j].y = std::max(0.0f, std::min(1.0f, cv.y)); + buffer[j].z = std::max(0.0f, std::min(1.0f, cv.z)); + } +#endif +} + +template<typename T> +static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr); +template<typename T> +static void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr); + +#if defined(__SSE2__) +// Load to [0-alpha] in 4x32 SIMD +template<typename T> +static inline void loadP(const T &p, __m128i &v); + +template<> +inline void loadP<QRgb>(const QRgb &p, __m128i &v) +{ + v = _mm_cvtsi32_si128(p); +#if defined(__SSE4_1__) + v = _mm_cvtepu8_epi32(v); +#else + v = _mm_unpacklo_epi8(v, _mm_setzero_si128()); + v = _mm_unpacklo_epi16(v, _mm_setzero_si128()); +#endif +} + +template<> +inline void loadP<QRgba64>(const QRgba64 &p, __m128i &v) +{ + v = _mm_loadl_epi64((const __m128i *)&p); +#if defined(__SSE4_1__) + v = _mm_cvtepu16_epi32(v); +#else + v = _mm_unpacklo_epi16(v, _mm_setzero_si128()); +#endif + // Shuffle to ARGB as the template below expects it + v = _mm_shuffle_epi32(v, _MM_SHUFFLE(3, 0, 1, 2)); +} + +template<typename T> +static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr) +{ + const __m128 v4080 = _mm_set1_ps(4080.f); + const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256)); + for (qsizetype i = 0; i < len; ++i) { + __m128i v; + loadP<T>(src[i], v); + __m128 vf = _mm_cvtepi32_ps(v); + // Approximate 1/a: + __m128 va = _mm_shuffle_ps(vf, vf, _MM_SHUFFLE(3, 3, 3, 3)); + __m128 via = _mm_rcp_ps(va); + via = _mm_sub_ps(_mm_add_ps(via, via), _mm_mul_ps(via, _mm_mul_ps(via, va))); + // v * (1/a) + vf = _mm_mul_ps(vf, via); + + // Handle zero alpha + __m128 vAlphaMask = _mm_cmpeq_ps(va, _mm_set1_ps(0.0f)); + vf = _mm_andnot_ps(vAlphaMask, vf); + + // LUT + v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080)); + const int ridx = _mm_extract_epi16(v, 4); + const int gidx = _mm_extract_epi16(v, 2); + const int bidx = _mm_extract_epi16(v, 0); + v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0); + v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2); + v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4); + vf = _mm_mul_ps(_mm_cvtepi32_ps(v), iFF00); + + _mm_storeu_ps(&buffer[i].x, vf); + } +} + +// Load to [0-4080] in 4x32 SIMD +template<typename T> +static inline void loadPU(const T &p, __m128i &v); + +template<> +inline void loadPU<QRgb>(const QRgb &p, __m128i &v) +{ + v = _mm_cvtsi32_si128(p); +#if defined(__SSE4_1__) + v = _mm_cvtepu8_epi32(v); +#else + v = _mm_unpacklo_epi8(v, _mm_setzero_si128()); + v = _mm_unpacklo_epi16(v, _mm_setzero_si128()); +#endif + v = _mm_slli_epi32(v, 4); +} + +template<> +inline void loadPU<QRgba64>(const QRgba64 &p, __m128i &v) +{ + v = _mm_loadl_epi64((const __m128i *)&p); + v = _mm_sub_epi16(v, _mm_srli_epi16(v, 8)); +#if defined(__SSE4_1__) + v = _mm_cvtepu16_epi32(v); +#else + v = _mm_unpacklo_epi16(v, _mm_setzero_si128()); +#endif + v = _mm_srli_epi32(v, 4); + // Shuffle to ARGB as the template below expects it + v = _mm_shuffle_epi32(v, _MM_SHUFFLE(3, 0, 1, 2)); +} + +template<typename T> +void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr) +{ + const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256)); + for (qsizetype i = 0; i < len; ++i) { + __m128i v; + loadPU<T>(src[i], v); + const int ridx = _mm_extract_epi16(v, 4); + const int gidx = _mm_extract_epi16(v, 2); + const int bidx = _mm_extract_epi16(v, 0); + v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0); + v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2); + v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4); + __m128 vf = _mm_mul_ps(_mm_cvtepi32_ps(v), iFF00); + _mm_storeu_ps(&buffer[i].x, vf); + } +} + +#else +template<> +void loadPremultiplied<QRgb>(QColorVector *buffer, const QRgb *src, const qsizetype len, const QColorTransformPrivate *d_ptr) +{ + for (qsizetype i = 0; i < len; ++i) { + const uint p = src[i]; + const int a = qAlpha(p); + if (a) { + const float ia = 4080.0f / a; + const int ridx = int(qRed(p) * ia + 0.5f); + const int gidx = int(qGreen(p) * ia + 0.5f); + const int bidx = int(qBlue(p) * ia + 0.5f); + buffer[i].x = d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx] * (1.0f / (255 * 256)); + buffer[i].y = d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx] * (1.0f / (255 * 256)); + buffer[i].z = d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx] * (1.0f / (255 * 256)); + } else { + buffer[i].x = buffer[i].y = buffer[i].z = 0.0f; + } + } +} + +template<> +void loadPremultiplied<QRgba64>(QColorVector *buffer, const QRgba64 *src, const qsizetype len, const QColorTransformPrivate *d_ptr) +{ + for (qsizetype i = 0; i < len; ++i) { + const QRgba64 &p = src[i]; + const int a = p.alpha(); + if (a) { + const float ia = 4080.0f / a; + const int ridx = int(p.red() * ia + 0.5f); + const int gidx = int(p.green() * ia + 0.5f); + const int bidx = int(p.blue() * ia + 0.5f); + buffer[i].x = d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx] * (1.0f / (255 * 256)); + buffer[i].y = d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx] * (1.0f / (255 * 256)); + buffer[i].z = d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx] * (1.0f / (255 * 256)); + } else { + buffer[i].x = buffer[i].y = buffer[i].z = 0.0f; + } + } +} + +template<> +void loadUnpremultiplied<QRgb>(QColorVector *buffer, const QRgb *src, const qsizetype len, const QColorTransformPrivate *d_ptr) +{ + for (qsizetype i = 0; i < len; ++i) { + const uint p = src[i]; + buffer[i].x = d_ptr->colorSpaceIn->lut[0]->u8ToLinearF32(qRed(p)); + buffer[i].y = d_ptr->colorSpaceIn->lut[1]->u8ToLinearF32(qGreen(p)); + buffer[i].z = d_ptr->colorSpaceIn->lut[2]->u8ToLinearF32(qBlue(p)); + } +} + +template<> +void loadUnpremultiplied<QRgba64>(QColorVector *buffer, const QRgba64 *src, const qsizetype len, const QColorTransformPrivate *d_ptr) +{ + for (qsizetype i = 0; i < len; ++i) { + const QRgba64 &p = src[i]; + buffer[i].x = d_ptr->colorSpaceIn->lut[0]->u16ToLinearF32(p.red()); + buffer[i].y = d_ptr->colorSpaceIn->lut[1]->u16ToLinearF32(p.green()); + buffer[i].z = d_ptr->colorSpaceIn->lut[2]->u16ToLinearF32(p.blue()); + } +} +#endif + +static void storePremultiplied(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len, + const QColorTransformPrivate *d_ptr) +{ +#if defined(__SSE2__) + const __m128 v4080 = _mm_set1_ps(4080.f); + const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256)); + for (qsizetype i = 0; i < len; ++i) { + const int a = qAlpha(src[i]); + __m128 vf = _mm_loadu_ps(&buffer[i].x); + __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080)); + __m128 va = _mm_set1_ps(a); + va = _mm_mul_ps(va, iFF00); + const int ridx = _mm_extract_epi16(v, 0); + const int gidx = _mm_extract_epi16(v, 2); + const int bidx = _mm_extract_epi16(v, 4); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 4); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 2); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 0); + vf = _mm_cvtepi32_ps(v); + vf = _mm_mul_ps(vf, va); + v = _mm_cvtps_epi32(vf); + v = _mm_packs_epi32(v, v); + v = _mm_insert_epi16(v, a, 3); + v = _mm_packus_epi16(v, v); + dst[i] = _mm_cvtsi128_si32(v); + } +#else + for (qsizetype i = 0; i < len; ++i) { + const int a = qAlpha(src[i]); + const float fa = a / (255.0f * 256.0f); + const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * 4080.0f + 0.5f)]; + const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * 4080.0f + 0.5f)]; + const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * 4080.0f + 0.5f)]; + dst[i] = qRgba(r * fa + 0.5f, g * fa + 0.5f, b * fa + 0.5f, a); + } +#endif +} + +static void storeUnpremultiplied(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len, + const QColorTransformPrivate *d_ptr) +{ +#if defined(__SSE2__) + const __m128 v4080 = _mm_set1_ps(4080.f); + for (qsizetype i = 0; i < len; ++i) { + const int a = qAlpha(src[i]); + __m128 vf = _mm_loadu_ps(&buffer[i].x); + __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080)); + const int ridx = _mm_extract_epi16(v, 0); + const int gidx = _mm_extract_epi16(v, 2); + const int bidx = _mm_extract_epi16(v, 4); + v = _mm_setzero_si128(); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 2); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 1); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 0); + v = _mm_add_epi16(v, _mm_set1_epi16(0x80)); + v = _mm_srli_epi16(v, 8); + v = _mm_insert_epi16(v, a, 3); + v = _mm_packus_epi16(v, v); + dst[i] = _mm_cvtsi128_si32(v); + } +#else + for (qsizetype i = 0; i < len; ++i) { + const int r = d_ptr->colorSpaceOut->lut[0]->u8FromLinearF32(buffer[i].x); + const int g = d_ptr->colorSpaceOut->lut[1]->u8FromLinearF32(buffer[i].y); + const int b = d_ptr->colorSpaceOut->lut[2]->u8FromLinearF32(buffer[i].z); + dst[i] = (src[i] & 0xff000000) | (r << 16) | (g << 8) | (b << 0); + } +#endif +} + +static void storeOpaque(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len, + const QColorTransformPrivate *d_ptr) +{ + Q_UNUSED(src); +#if defined(__SSE2__) + const __m128 v4080 = _mm_set1_ps(4080.f); + for (qsizetype i = 0; i < len; ++i) { + __m128 vf = _mm_loadu_ps(&buffer[i].x); + __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080)); + const int ridx = _mm_extract_epi16(v, 0); + const int gidx = _mm_extract_epi16(v, 2); + const int bidx = _mm_extract_epi16(v, 4); + v = _mm_setzero_si128(); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 2); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 1); + v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 0); + v = _mm_add_epi16(v, _mm_set1_epi16(0x80)); + v = _mm_srli_epi16(v, 8); + v = _mm_insert_epi16(v, 255, 3); + v = _mm_packus_epi16(v, v); + dst[i] = _mm_cvtsi128_si32(v); + } +#else + for (qsizetype i = 0; i < len; ++i) { + const int r = d_ptr->colorSpaceOut->lut[0]->u8FromLinearF32(buffer[i].x); + const int g = d_ptr->colorSpaceOut->lut[1]->u8FromLinearF32(buffer[i].y); + const int b = d_ptr->colorSpaceOut->lut[2]->u8FromLinearF32(buffer[i].z); + dst[i] = 0xff000000 | (r << 16) | (g << 8) | (b << 0); + } +#endif +} + +static void storePremultiplied(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len, + const QColorTransformPrivate *d_ptr) +{ + for (qsizetype i = 0; i < len; ++i) { + const int a = src[i].alpha(); + const float fa = a / (255.0f * 256.0f); + const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * 4080.0f + 0.5f)]; + const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * 4080.0f + 0.5f)]; + const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * 4080.0f + 0.5f)]; + dst[i] = qRgba64(r * fa + 0.5f, g * fa + 0.5f, b * fa + 0.5f, a); + } +} + +static void storeUnpremultiplied(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len, + const QColorTransformPrivate *d_ptr) +{ + for (qsizetype i = 0; i < len; ++i) { + const int r = d_ptr->colorSpaceOut->lut[0]->u16FromLinearF32(buffer[i].x); + const int g = d_ptr->colorSpaceOut->lut[1]->u16FromLinearF32(buffer[i].y); + const int b = d_ptr->colorSpaceOut->lut[2]->u16FromLinearF32(buffer[i].z); + dst[i] = qRgba64(r, g, b, src[i].alpha()); + } +} + +static void storeOpaque(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len, + const QColorTransformPrivate *d_ptr) +{ + Q_UNUSED(src); + for (qsizetype i = 0; i < len; ++i) { + const int r = d_ptr->colorSpaceOut->lut[0]->u16FromLinearF32(buffer[i].x); + const int g = d_ptr->colorSpaceOut->lut[1]->u16FromLinearF32(buffer[i].y); + const int b = d_ptr->colorSpaceOut->lut[2]->u16FromLinearF32(buffer[i].z); + dst[i] = qRgba64(r, g, b, 0xFFFF); + } +} + +static constexpr qsizetype WorkBlockSize = 256; + +template<typename T> +void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, TransformFlags flags) const +{ + if (!colorMatrix.isValid()) + return; + + updateLutsIn(); + updateLutsOut(); + + bool doApplyMatrix = (colorMatrix != QColorMatrix::identity()); + + QColorVector buffer[WorkBlockSize]; + qsizetype i = 0; + while (i < count) { + const qsizetype len = qMin(count - i, WorkBlockSize); + if (flags & InputPremultiplied) + loadPremultiplied(buffer, src + i, len, this); + else + loadUnpremultiplied(buffer, src + i, len, this); + + if (doApplyMatrix) + applyMatrix(buffer, len, colorMatrix); + + if (flags & InputOpaque) + storeOpaque(dst + i, src + i, buffer, len, this); + else if (flags & OutputPremultiplied) + storePremultiplied(dst + i, src + i, buffer, len, this); + else + storeUnpremultiplied(dst + i, src + i, buffer, len, this); + + i += len; + } +} + +/*! + \internal + \enum QColorTransformPrivate::TransformFlag + + Defines how the transform is to be applied. + + \value Unpremultiplied The input and output should both be unpremultiplied. + \value InputOpaque The input is guaranteed to be opaque. + \value InputPremultiplied The input is premultiplied. + \value OutputPremultiplied The output should be premultiplied. + \value Premultiplied Both input and output should both be premultiplied. +*/ + +/*! + \internal + Prepares a color transformation for fast application. You do not need to + call this explicitly as it will be called implicitly on the first transforms, but + if you want predictable performance on the first transforms, you can perform it + in advance. + + \sa QColorTransform::map(), apply() +*/ +void QColorTransformPrivate::prepare() +{ + updateLutsIn(); + updateLutsOut(); +} + +/*! + \internal + Applies the color transformation on \a count QRgb pixels starting from + \a src and stores the result in \a dst. + + Thread-safe if prepare() has been called first. + + Assumes unpremultiplied data by default. Set \a flags to change defaults. + + \sa prepare() +*/ +void QColorTransformPrivate::apply(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags) const +{ + apply<QRgb>(dst, src, count, flags); +} + +/*! + \internal + Applies the color transformation on \a count QRgba64 pixels starting from + \a src and stores the result in \a dst. + + Thread-safe if prepare() has been called first. + + Assumes unpremultiplied data by default. Set \a flags to change defaults. + + \sa prepare() +*/ +void QColorTransformPrivate::apply(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const +{ + apply<QRgba64>(dst, src, count, flags); +} + + +QT_END_NAMESPACE diff --git a/src/gui/painting/qcolortransform.h b/src/gui/painting/qcolortransform.h new file mode 100644 index 0000000000..9274387b97 --- /dev/null +++ b/src/gui/painting/qcolortransform.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QCOLORTRANSFORM_H +#define QCOLORTRANSFORM_H + +#include <QtGui/qtguiglobal.h> +#include <QtCore/qsharedpointer.h> +#include <QtGui/qrgb.h> + +QT_BEGIN_NAMESPACE + +class QColor; +class QRgba64; +class QColorSpacePrivate; +class QColorTransformPrivate; + +class Q_GUI_EXPORT QColorTransform +{ +public: + QColorTransform() noexcept : d_ptr(nullptr) { } + ~QColorTransform() noexcept; + QColorTransform(const QColorTransform &colorTransform) noexcept + : d_ptr(colorTransform.d_ptr) + { } + QColorTransform(QColorTransform &&colorTransform) noexcept + : d_ptr(std::move(colorTransform.d_ptr)) + { } + QColorTransform &operator=(const QColorTransform &other) noexcept + { + d_ptr = other.d_ptr; + return *this; + } + QColorTransform &operator=(QColorTransform &&other) noexcept + { + d_ptr = std::move(other.d_ptr); + return *this; + } + + bool isNull() const { return d_ptr.isNull(); } + + QRgb map(const QRgb &argb) const; + QRgba64 map(const QRgba64 &rgba64) const; + QColor map(const QColor &color) const; + +private: + friend class QColorSpace; + friend class QColorSpacePrivate; + friend class QImage; + + Q_DECLARE_PRIVATE(QColorTransform) + QSharedPointer<QColorTransformPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QCOLORTRANSFORM_H diff --git a/src/gui/painting/qcolortransform_p.h b/src/gui/painting/qcolortransform_p.h new file mode 100644 index 0000000000..74a1e7fe0a --- /dev/null +++ b/src/gui/painting/qcolortransform_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 QCOLORTRANSFORM_P_H +#define QCOLORTRANSFORM_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 "qcolormatrix_p.h" +#include "qcolorspace_p.h" + +QT_BEGIN_NAMESPACE + +class QColorTransformPrivate +{ +public: + QColorMatrix colorMatrix; + QExplicitlySharedDataPointer<const QColorSpacePrivate> colorSpaceIn; + QExplicitlySharedDataPointer<const QColorSpacePrivate> colorSpaceOut; + + void updateLutsIn() const; + void updateLutsOut() const; + bool simpleGammaCorrection() const; + + void prepare(); + enum TransformFlag { + Unpremultiplied = 0, + InputOpaque = 1, + InputPremultiplied = 2, + OutputPremultiplied = 4, + Premultiplied = (InputPremultiplied | OutputPremultiplied) + }; + Q_DECLARE_FLAGS(TransformFlags, TransformFlag) + + void apply(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags = Unpremultiplied) const; + void apply(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags = Unpremultiplied) const; + + template<typename T> + void apply(T *dst, const T *src, qsizetype count, TransformFlags flags) const; +}; + +QT_END_NAMESPACE + +#endif // QCOLORTRANSFORM_P_H diff --git a/src/gui/painting/qcolortrc_p.h b/src/gui/painting/qcolortrc_p.h new file mode 100644 index 0000000000..3ef9d442fc --- /dev/null +++ b/src/gui/painting/qcolortrc_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QCOLORTRC_P_H +#define QCOLORTRC_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 "qcolortransferfunction_p.h" +#include "qcolortransfertable_p.h" + +QT_BEGIN_NAMESPACE + + +// Defines an ICC TRC (Tone Reproduction Curve) +class Q_GUI_EXPORT QColorTrc +{ +public: + QColorTrc() noexcept : m_type(Type::Uninitialized) + { } + QColorTrc(const QColorTransferFunction &fun) : m_type(Type::Function), m_fun(fun) + { } + QColorTrc(const QColorTransferTable &table) : m_type(Type::Table), m_table(table) + { } + + enum class Type { + Uninitialized, + Function, + Table + }; + + bool isLinear() const + { + return m_type == Type::Uninitialized || (m_type == Type::Function && m_fun.isLinear()); + } + bool isValid() const + { + return m_type != Type::Uninitialized; + } + float apply(float x) const + { + if (m_type == Type::Table) + return m_table.apply(x); + if (m_type == Type::Function) + return m_fun.apply(x); + return x; + } + float applyExtended(float x) const + { + if (x >= 0.0f && x <= 1.0f) + return apply(x); + if (m_type == Type::Function) + return std::copysign(m_fun.apply(std::abs(x)), x); + if (m_type == Type::Table) + return x < 0.0f ? 0.0f : 1.0f; + return x; + } + float applyInverse(float x) const + { + if (m_type == Type::Table) + return m_table.applyInverse(x); + if (m_type == Type::Function) + return m_fun.inverted().apply(x); + return x; + } + float applyInverseExtended(float x) const + { + if (x >= 0.0f && x <= 1.0f) + return applyInverse(x); + if (m_type == Type::Function) + return std::copysign(applyInverse(x), x); + if (m_type == Type::Table) + return x < 0.0f ? 0.0f : 1.0f; + return x; + } + + friend inline bool operator!=(const QColorTrc &o1, const QColorTrc &o2); + friend inline bool operator==(const QColorTrc &o1, const QColorTrc &o2); + + Type m_type; + QColorTransferFunction m_fun; + QColorTransferTable m_table; +}; + +inline bool operator!=(const QColorTrc &o1, const QColorTrc &o2) +{ + if (o1.m_type != o2.m_type) + return true; + if (o1.m_type == QColorTrc::Type::Function) + return o1.m_fun != o2.m_fun; + if (o1.m_type == QColorTrc::Type::Table) + return o1.m_table != o2.m_table; + return false; +} +inline bool operator==(const QColorTrc &o1, const QColorTrc &o2) +{ + return !(o1 != o2); +} + +QT_END_NAMESPACE + +#endif // QCOLORTRC diff --git a/src/gui/painting/qcolorprofile.cpp b/src/gui/painting/qcolortrclut.cpp index 3b7b0a248b..268d7252b4 100644 --- a/src/gui/painting/qcolorprofile.cpp +++ b/src/gui/painting/qcolortrclut.cpp @@ -37,14 +37,16 @@ ** ****************************************************************************/ -#include "qcolorprofile_p.h" +#include "qcolortrclut_p.h" +#include "qcolortransferfunction_p.h" +#include "qcolortransfertable_p.h" #include <qmath.h> QT_BEGIN_NAMESPACE -QColorProfile *QColorProfile::fromGamma(qreal gamma) +QColorTrcLut *QColorTrcLut::fromGamma(qreal gamma) { - QColorProfile *cp = new QColorProfile; + QColorTrcLut *cp = new QColorTrcLut; for (int i = 0; i <= (255 * 16); ++i) { cp->m_toLinear[i] = ushort(qRound(qPow(i / qreal(255 * 16), gamma) * (255 * 256))); @@ -54,31 +56,28 @@ QColorProfile *QColorProfile::fromGamma(qreal gamma) return cp; } -static qreal srgbToLinear(qreal v) +QColorTrcLut *QColorTrcLut::fromTransferFunction(const QColorTransferFunction &fun) { - 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)); -} + QColorTrcLut *cp = new QColorTrcLut; + QColorTransferFunction inv = fun.inverted(); -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; + for (int i = 0; i <= (255 * 16); ++i) { + cp->m_toLinear[i] = ushort(qRound(fun.apply(i / qreal(255 * 16)) * (255 * 256))); + cp->m_fromLinear[i] = ushort(qRound(inv.apply(i / qreal(255 * 16)) * (255 * 256))); + } + + return cp; } -QColorProfile *QColorProfile::fromSRgb() +QColorTrcLut *QColorTrcLut::fromTransferTable(const QColorTransferTable &table) { - QColorProfile *cp = new QColorProfile; + QColorTrcLut *cp = new QColorTrcLut; + float minInverse = 0.0f; 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))); + cp->m_toLinear[i] = ushort(qBound(0, qRound(table.apply(i / qreal(255 * 16)) * (255 * 256)), 65280)); + minInverse = table.applyInverse(i / qreal(255 * 16), minInverse); + cp->m_fromLinear[i] = ushort(qBound(0, qRound(minInverse * (255 * 256)), 65280)); } return cp; diff --git a/src/gui/painting/qcolorprofile_p.h b/src/gui/painting/qcolortrclut_p.h index 425e9abace..76a6a60803 100644 --- a/src/gui/painting/qcolorprofile_p.h +++ b/src/gui/painting/qcolortrclut_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QCOLORPROFILE_P_H -#define QCOLORPROFILE_P_H +#ifndef QCOLORTRCLUT_P_H +#define QCOLORTRCLUT_P_H // // W A R N I N G @@ -52,21 +52,29 @@ // #include <QtGui/private/qtguiglobal_p.h> +#include <QtCore/qsharedpointer.h> #include <QtGui/qrgb.h> #include <QtGui/qrgba64.h> +#include <cmath> + #if defined(__SSE2__) #include <emmintrin.h> #elif defined(__ARM_NEON__) || defined(__ARM_NEON) #include <arm_neon.h> #endif + QT_BEGIN_NAMESPACE -class Q_GUI_EXPORT QColorProfile +class QColorTransferFunction; +class QColorTransferTable; + +class Q_GUI_EXPORT QColorTrcLut : public QEnableSharedFromThis<QColorTrcLut> { public: - static QColorProfile *fromGamma(qreal gamma); - static QColorProfile *fromSRgb(); + static QColorTrcLut *fromGamma(qreal gamma); + static QColorTrcLut *fromTransferFunction(const QColorTransferFunction &transfn); + static QColorTrcLut *fromTransferTable(const QColorTransferTable &transTable); // The following methods all convert opaque or unpremultiplied colors: @@ -121,6 +129,25 @@ public: return convertWithTable(rgb64, m_toLinear); } + float u8ToLinearF32(int c) const + { + ushort v = m_toLinear[c << 4]; + return v * (1.0f / (255*256)); + } + + float u16ToLinearF32(int c) const + { + c -= (c >> 8); + ushort v = m_toLinear[c >> 4]; + return v * (1.0f / (255*256)); + } + + float toLinear(float f) const + { + ushort v = m_toLinear[(int)(f * (255 * 16) + 0.5f)]; + return v * (1.0f / (255*256)); + } + QRgb fromLinear64(QRgba64 rgb64) const { #if defined(__SSE2__) @@ -176,8 +203,31 @@ public: return convertWithTable(rgb64, m_fromLinear); } + int u8FromLinearF32(float f) const + { + ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)]; + return (v + 0x80) >> 8; + } + int u16FromLinearF32(float f) const + { + ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)]; + return v + (v >> 8); + } + float fromLinear(float f) const + { + ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)]; + return v * (1.0f / (255*256)); + } + + // 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] + private: - QColorProfile() { } + QColorTrcLut() { } Q_ALWAYS_INLINE static QRgb convertWithTable(QRgb rgb32, const ushort *table) { @@ -230,16 +280,8 @@ private: return QRgba64::fromRgba64(r, g, b, rgb64.alpha()); #endif } - - // 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 +#endif // QCOLORTRCLUT_P_H diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp index 5c1afe8425..06a849e790 100644 --- a/src/gui/painting/qcompositionfunctions.cpp +++ b/src/gui/painting/qcompositionfunctions.cpp @@ -137,6 +137,7 @@ struct Rgba64OperationsBase { ::memcpy(dest, src, len * sizeof(Type)); } }; +#if QT_CONFIG(raster_64bit) const Rgba64OperationsBase::Type Rgba64OperationsBase::clear = QRgba64::fromRgba64(0); struct Rgba64OperationsC : public Rgba64OperationsBase @@ -309,10 +310,8 @@ struct Rgba64OperationsNEON : public Rgba64OperationsBase return interpolate65535(x, a1, y, a2); } }; - #endif -typedef Argb32OperationsC Argb32Operations; #if defined(__SSE2__) typedef Rgba64OperationsSSE2 Rgba64Operations; #elif defined(__ARM_NEON__) @@ -320,6 +319,9 @@ typedef Rgba64OperationsNEON Rgba64Operations; #else typedef Rgba64OperationsC Rgba64Operations; #endif +#endif // QT_CONFIG(raster_64bit) + +typedef Argb32OperationsC Argb32Operations; /* result = 0 @@ -343,20 +345,23 @@ void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_ comp_func_Clear_template<Argb32Operations>(dest, length, const_alpha); } -void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha) +void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) { - comp_func_Clear_template<Rgba64Operations>(dest, length, const_alpha); + comp_func_Clear_template<Argb32Operations>(dest, length, const_alpha); } -void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha) { - comp_func_Clear_template<Argb32Operations>(dest, length, const_alpha); + comp_func_Clear_template<Rgba64Operations>(dest, length, const_alpha); } void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int length, uint const_alpha) { comp_func_Clear_template<Rgba64Operations>(dest, length, const_alpha); } +#endif + /* result = s @@ -399,36 +404,40 @@ void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint comp_func_solid_Source_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_Source_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_Source_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_Source_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_Source_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_Source_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif 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(uint *, const uint *, int, uint) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_Destination_rgb64(QRgba64 *, int, QRgba64, uint) { } void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, uint) { } +#endif /* result = s + d * sia @@ -483,20 +492,22 @@ void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, comp_func_solid_SourceOver_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_SourceOver_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_SourceOver_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_SourceOver_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_SourceOver_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_SourceOver_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* result = d + s * dia @@ -542,20 +553,22 @@ void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint co comp_func_solid_DestinationOver_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_DestinationOver_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_DestinationOver_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_DestinationOver_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_DestinationOver_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_DestinationOver_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* result = s * da @@ -606,20 +619,22 @@ void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, ui comp_func_solid_SourceIn_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_SourceIn_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_SourceIn_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_SourceIn_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_SourceIn_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_SourceIn_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* result = d * sa @@ -665,20 +680,22 @@ void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint colo comp_func_solid_DestinationIn_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_DestinationIn_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_DestinationIn_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_DestinationIn_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_DestinationIn_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_DestinationIn_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* result = s * dia @@ -727,20 +744,22 @@ void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, u comp_func_solid_SourceOut_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_SourceOut_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_SourceOut_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_SourceOut_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_SourceOut_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_SourceOut_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* result = d * sia @@ -786,20 +805,22 @@ void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint col comp_func_solid_DestinationOut_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_DestinationOut_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_DestinationOut_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_DestinationOut_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_DestinationOut_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_DestinationOut_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* result = s*da + d*sia @@ -845,20 +866,22 @@ void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, comp_func_solid_SourceAtop_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_SourceAtop_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_SourceAtop_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_SourceAtop_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_SourceAtop_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_SourceAtop_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* result = d*sa + s*dia @@ -909,20 +932,22 @@ void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint co comp_func_solid_DestinationAtop_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_DestinationAtop_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_DestinationAtop_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_DestinationAtop_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_DestinationAtop_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_DestinationAtop_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* result = d*sia + s*dia @@ -969,20 +994,22 @@ void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint co comp_func_solid_XOR_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_XOR_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_XOR_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_XOR_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_XOR_template<Rgba64Operations>(dest, length, color, const_alpha); } void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { comp_func_XOR_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif struct QFullCoverage { inline void store(uint *dest, const uint src) const @@ -1078,20 +1105,22 @@ void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint c comp_func_solid_Plus_template<Argb32Operations>(dest, length, color, const_alpha); } -void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { - comp_func_solid_Plus_template<Rgba64Operations>(dest, length, color, const_alpha); + comp_func_Plus_template<Argb32Operations>(dest, src, length, const_alpha); } -void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { - comp_func_Plus_template<Argb32Operations>(dest, src, length, const_alpha); + comp_func_solid_Plus_template<Rgba64Operations>(dest, length, color, 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) { comp_func_Plus_template<Rgba64Operations>(dest, src, length, const_alpha); } +#endif /* Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) @@ -1101,11 +1130,6 @@ 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)); } -static inline uint multiply_op_rgb64(uint dst, uint src, uint da, uint sa) -{ - return qt_div_65535(src * dst + src * (65535 - da) + dst * (65535 - sa)); -} - template <typename T> static inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage) { @@ -1129,6 +1153,20 @@ static inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint co } } +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)); +} + +#if QT_CONFIG(raster_64bit) +static inline uint multiply_op_rgb64(uint dst, uint src, uint da, uint sa) +{ + return qt_div_65535(src * dst + src * (65535 - da) + dst * (65535 - sa)); +} + template <typename T> static inline void comp_func_solid_Multiply_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -1152,14 +1190,6 @@ static inline void comp_func_solid_Multiply_impl(QRgba64 *dest, int length, QRgb } } -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)); -} - void QT_FASTCALL comp_func_solid_Multiply_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -1167,6 +1197,7 @@ void QT_FASTCALL comp_func_solid_Multiply_rgb64(QRgba64 *dest, int length, QRgba else comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -1189,6 +1220,15 @@ static inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uin } } +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)); +} + +#if QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_Multiply_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -1210,14 +1250,6 @@ static inline void comp_func_Multiply_impl(QRgba64 *Q_DECL_RESTRICT dest, const } } -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)); -} - void QT_FASTCALL comp_func_Multiply_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -1225,6 +1257,7 @@ void QT_FASTCALL comp_func_Multiply_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const Q else comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) @@ -1253,6 +1286,15 @@ static inline void comp_func_solid_Screen_impl(uint *dest, int length, uint colo } } +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)); +} + +#if QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_solid_Screen_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -1276,14 +1318,6 @@ static inline void comp_func_solid_Screen_impl(QRgba64 *dest, int length, QRgba6 } } -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)); -} - void QT_FASTCALL comp_func_solid_Screen_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -1291,6 +1325,7 @@ void QT_FASTCALL comp_func_solid_Screen_rgb64(QRgba64 *dest, int length, QRgba64 else comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -1313,6 +1348,15 @@ static inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint } } +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 QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_Screen_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -1334,14 +1378,6 @@ static inline void comp_func_Screen_impl(QRgba64 *Q_DECL_RESTRICT dest, const QR } } -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)); -} - void QT_FASTCALL comp_func_Screen_rgb64(QRgba64 *dest, const QRgba64 *src, int length, uint const_alpha) { if (const_alpha == 255) @@ -1349,6 +1385,7 @@ void QT_FASTCALL comp_func_Screen_rgb64(QRgba64 *dest, const QRgba64 *src, int l else comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* if 2.Dca < Da @@ -1365,15 +1402,6 @@ static inline int overlay_op(int dst, int src, int da, int sa) return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); } -static inline uint overlay_op_rgb64(uint dst, uint src, uint da, uint sa) -{ - const uint temp = src * (65535 - da) + dst * (65535 - sa); - if (2 * dst < da) - return qt_div_65535(2 * src * dst + temp); - else - return qt_div_65535(sa * da - 2 * (da - dst) * (sa - src) + temp); -} - template <typename T> static inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage) { @@ -1397,6 +1425,24 @@ static inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint col } } +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)); +} + +#if QT_CONFIG(raster_64bit) +static inline uint overlay_op_rgb64(uint dst, uint src, uint da, uint sa) +{ + const uint temp = src * (65535 - da) + dst * (65535 - sa); + if (2 * dst < da) + return qt_div_65535(2 * src * dst + temp); + else + return qt_div_65535(sa * da - 2 * (da - dst) * (sa - src) + temp); +} + template <typename T> static inline void comp_func_solid_Overlay_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -1420,14 +1466,6 @@ static inline void comp_func_solid_Overlay_impl(QRgba64 *dest, int length, QRgba } } -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)); -} - void QT_FASTCALL comp_func_solid_Overlay_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -1435,6 +1473,7 @@ void QT_FASTCALL comp_func_solid_Overlay_rgb64(QRgba64 *dest, int length, QRgba6 else comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -1457,6 +1496,15 @@ static inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint } } +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)); +} + +#if QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_Overlay_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -1478,14 +1526,6 @@ static inline void comp_func_Overlay_impl(QRgba64 *Q_DECL_RESTRICT dest, const Q } } -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)); -} - void QT_FASTCALL comp_func_Overlay_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -1493,6 +1533,7 @@ void QT_FASTCALL comp_func_Overlay_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QR else comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) @@ -1503,11 +1544,6 @@ 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)); } -static inline uint darken_op_rgb64(uint dst, uint src, uint da, uint sa) -{ - return qt_div_65535(qMin(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa)); -} - template <typename T> static inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage) { @@ -1531,6 +1567,20 @@ static inline void comp_func_solid_Darken_impl(uint *dest, int length, uint colo } } +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)); +} + +#if QT_CONFIG(raster_64bit) +static inline uint darken_op_rgb64(uint dst, uint src, uint da, uint sa) +{ + return qt_div_65535(qMin(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa)); +} + template <typename T> static inline void comp_func_solid_Darken_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -1554,14 +1604,6 @@ static inline void comp_func_solid_Darken_impl(QRgba64 *dest, int length, QRgba6 } } -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)); -} - void QT_FASTCALL comp_func_solid_Darken_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -1569,6 +1611,7 @@ void QT_FASTCALL comp_func_solid_Darken_rgb64(QRgba64 *dest, int length, QRgba64 else comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -1591,6 +1634,15 @@ static inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint } } +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)); +} + +#if QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_Darken_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -1612,14 +1664,6 @@ static inline void comp_func_Darken_impl(QRgba64 *Q_DECL_RESTRICT dest, const QR } } -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)); -} - void QT_FASTCALL comp_func_Darken_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -1627,6 +1671,7 @@ void QT_FASTCALL comp_func_Darken_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRg else comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) @@ -1637,11 +1682,6 @@ 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)); } -static inline uint lighten_op_rgb64(uint dst, uint src, uint da, uint sa) -{ - return qt_div_65535(qMax(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa)); -} - template <typename T> static inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage) { @@ -1665,6 +1705,21 @@ static inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint col } } +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)); +} + + +#if QT_CONFIG(raster_64bit) +static inline uint lighten_op_rgb64(uint dst, uint src, uint da, uint sa) +{ + return qt_div_65535(qMax(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa)); +} + template <typename T> static inline void comp_func_solid_Lighten_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -1688,14 +1743,6 @@ static inline void comp_func_solid_Lighten_impl(QRgba64 *dest, int length, QRgba } } -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)); -} - void QT_FASTCALL comp_func_solid_Lighten_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -1703,6 +1750,7 @@ void QT_FASTCALL comp_func_solid_Lighten_rgb64(QRgba64 *dest, int length, QRgba6 else comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -1725,6 +1773,15 @@ static inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint } } +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 QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_Lighten_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -1746,14 +1803,6 @@ static inline void comp_func_Lighten_impl(QRgba64 *Q_DECL_RESTRICT dest, const Q } } -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)); -} - void QT_FASTCALL comp_func_Lighten_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -1761,6 +1810,7 @@ void QT_FASTCALL comp_func_Lighten_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QR else comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* if Sca.Da + Dca.Sa >= Sa.Da @@ -1781,19 +1831,6 @@ static inline int color_dodge_op(int dst, int src, int da, int sa) return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp); } -static inline uint color_dodge_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa) -{ - const qint64 sa_da = sa * da; - const qint64 dst_sa = dst * sa; - const qint64 src_da = src * da; - - const qint64 temp = src * (65535 - da) + dst * (65535 - sa); - if (src_da + dst_sa >= sa_da) - return qt_div_65535(sa_da + temp); - else - return qt_div_65535(65535 * dst_sa / (65535 - 65535 * src / sa) + temp); -} - template <typename T> static inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage) { @@ -1817,6 +1854,28 @@ static inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint } } +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)); +} + +#if QT_CONFIG(raster_64bit) +static inline uint color_dodge_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa) +{ + const qint64 sa_da = sa * da; + const qint64 dst_sa = dst * sa; + const qint64 src_da = src * da; + + const qint64 temp = src * (65535 - da) + dst * (65535 - sa); + if (src_da + dst_sa >= sa_da) + return qt_div_65535(sa_da + temp); + else + return qt_div_65535(65535 * dst_sa / (65535 - 65535 * src / sa) + temp); +} + template <typename T> static inline void comp_func_solid_ColorDodge_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -1840,14 +1899,6 @@ static inline void comp_func_solid_ColorDodge_impl(QRgba64 *dest, int length, QR } } -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)); -} - void QT_FASTCALL comp_func_solid_ColorDodge_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -1855,6 +1906,7 @@ void QT_FASTCALL comp_func_solid_ColorDodge_rgb64(QRgba64 *dest, int length, QRg else comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -1877,6 +1929,15 @@ static inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const u } } +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 QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_ColorDodge_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -1898,14 +1959,6 @@ static inline void comp_func_ColorDodge_impl(QRgba64 *Q_DECL_RESTRICT dest, cons } } -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)); -} - void QT_FASTCALL comp_func_ColorDodge_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -1913,6 +1966,7 @@ void QT_FASTCALL comp_func_ColorDodge_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const else comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* if Sca.Da + Dca.Sa <= Sa.Da @@ -1933,19 +1987,6 @@ static inline int color_burn_op(int dst, int src, int da, int sa) return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); } -static inline uint color_burn_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa) -{ - const qint64 src_da = src * da; - const qint64 dst_sa = dst * sa; - const qint64 sa_da = sa * da; - - const qint64 temp = src * (65535 - da) + dst * (65535 - sa); - - if (src == 0 || src_da + dst_sa <= sa_da) - return qt_div_65535(temp); - return qt_div_65535(sa * (src_da + dst_sa - sa_da) / src + temp); -} - template <typename T> static inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage) { @@ -1969,6 +2010,28 @@ static inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint c } } +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)); +} + +#if QT_CONFIG(raster_64bit) +static inline uint color_burn_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa) +{ + const qint64 src_da = src * da; + const qint64 dst_sa = dst * sa; + const qint64 sa_da = sa * da; + + const qint64 temp = src * (65535 - da) + dst * (65535 - sa); + + if (src == 0 || src_da + dst_sa <= sa_da) + return qt_div_65535(temp); + return qt_div_65535(sa * (src_da + dst_sa - sa_da) / src + temp); +} + template <typename T> static inline void comp_func_solid_ColorBurn_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -1992,14 +2055,6 @@ static inline void comp_func_solid_ColorBurn_impl(QRgba64 *dest, int length, QRg } } -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)); -} - void QT_FASTCALL comp_func_solid_ColorBurn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -2007,6 +2062,7 @@ void QT_FASTCALL comp_func_solid_ColorBurn_rgb64(QRgba64 *dest, int length, QRgb else comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -2029,6 +2085,15 @@ static inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const ui } } +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 QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_ColorBurn_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -2050,14 +2115,6 @@ static inline void comp_func_ColorBurn_impl(QRgba64 *Q_DECL_RESTRICT dest, const } } -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)); -} - void QT_FASTCALL comp_func_ColorBurn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -2065,6 +2122,7 @@ void QT_FASTCALL comp_func_ColorBurn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const else comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* if 2.Sca < Sa @@ -2082,16 +2140,6 @@ static inline uint hardlight_op(int dst, int src, int da, int sa) return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); } -static inline uint hardlight_op_rgb64(uint dst, uint src, uint da, uint sa) -{ - const uint temp = src * (65535 - da) + dst * (65535 - sa); - - if (2 * src < sa) - return qt_div_65535(2 * src * dst + temp); - else - return qt_div_65535(sa * da - 2 * (da - dst) * (sa - src) + temp); -} - template <typename T> static inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage) { @@ -2115,6 +2163,25 @@ static inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint c } } +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)); +} + +#if QT_CONFIG(raster_64bit) +static inline uint hardlight_op_rgb64(uint dst, uint src, uint da, uint sa) +{ + const uint temp = src * (65535 - da) + dst * (65535 - sa); + + if (2 * src < sa) + return qt_div_65535(2 * src * dst + temp); + else + return qt_div_65535(sa * da - 2 * (da - dst) * (sa - src) + temp); +} + template <typename T> static inline void comp_func_solid_HardLight_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -2138,14 +2205,6 @@ static inline void comp_func_solid_HardLight_impl(QRgba64 *dest, int length, QRg } } -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)); -} - void QT_FASTCALL comp_func_solid_HardLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -2153,6 +2212,7 @@ void QT_FASTCALL comp_func_solid_HardLight_rgb64(QRgba64 *dest, int length, QRgb else comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -2175,6 +2235,15 @@ static inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const ui } } +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 QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_HardLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -2196,14 +2265,6 @@ static inline void comp_func_HardLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const } } -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)); -} - void QT_FASTCALL comp_func_HardLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -2211,6 +2272,7 @@ void QT_FASTCALL comp_func_HardLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const else comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* if 2.Sca <= Sa @@ -2235,22 +2297,6 @@ static inline int soft_light_op(int dst, int src, int da, int sa) } } -static inline uint soft_light_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa) -{ - const qint64 src2 = src << 1; - const qint64 dst_np = da != 0 ? (65535 * dst) / da : 0; - const qint64 temp = (src * (65535 - da) + dst * (65535 - sa)) * 65535; - const qint64 factor = qint64(65535) * 65535; - - if (src2 < sa) - return (dst * (sa * 65535 + (src2 - sa) * (65535 - dst_np)) + temp) / factor; - else if (4 * dst <= da) - return (dst * sa * 65535 + da * (src2 - sa) * ((((16 * dst_np - 12 * 65535) * dst_np + 3 * factor) * dst_np) / factor) + temp) / factor; - else { - return (dst * sa * 65535 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 65535))) - dst_np) + temp) / factor; - } -} - template <typename T> static inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage) { @@ -2274,6 +2320,23 @@ static inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint c } } +#if QT_CONFIG(raster_64bit) +static inline uint soft_light_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa) +{ + const qint64 src2 = src << 1; + const qint64 dst_np = da != 0 ? (65535 * dst) / da : 0; + const qint64 temp = (src * (65535 - da) + dst * (65535 - sa)) * 65535; + const qint64 factor = qint64(65535) * 65535; + + if (src2 < sa) + return (dst * (sa * 65535 + (src2 - sa) * (65535 - dst_np)) + temp) / factor; + else if (4 * dst <= da) + return (dst * sa * 65535 + da * (src2 - sa) * ((((16 * dst_np - 12 * 65535) * dst_np + 3 * factor) * dst_np) / factor) + temp) / factor; + else { + return (dst * sa * 65535 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 65535))) - dst_np) + temp) / factor; + } +} + template <typename T> static inline void comp_func_solid_SoftLight_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -2296,6 +2359,7 @@ static inline void comp_func_solid_SoftLight_impl(QRgba64 *dest, int length, QRg coverage.store(&dest[i], qRgba64(r, g, b, a)); } } +#endif void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha) { @@ -2305,14 +2369,6 @@ void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, u comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha)); } -void QT_FASTCALL comp_func_solid_SoftLight_rgb64(QRgba64 *dest, int length, QRgba64 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> static inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -2334,6 +2390,23 @@ static inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const ui } } +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)); +} + +#if QT_CONFIG(raster_64bit) +void QT_FASTCALL comp_func_solid_SoftLight_rgb64(QRgba64 *dest, int length, QRgba64 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> static inline void comp_func_SoftLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -2355,14 +2428,6 @@ static inline void comp_func_SoftLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const } } -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)); -} - void QT_FASTCALL comp_func_SoftLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -2370,6 +2435,7 @@ void QT_FASTCALL comp_func_SoftLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const else comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) @@ -2380,11 +2446,6 @@ 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)); } -static inline uint difference_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa) -{ - return src + dst - qt_div_65535(2 * qMin(src * da, dst * sa)); -} - template <typename T> static inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage) { @@ -2408,6 +2469,20 @@ static inline void comp_func_solid_Difference_impl(uint *dest, int length, uint } } +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)); +} + +#if QT_CONFIG(raster_64bit) +static inline uint difference_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa) +{ + return src + dst - qt_div_65535(2 * qMin(src * da, dst * sa)); +} + template <typename T> static inline void comp_func_solid_Difference_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -2431,14 +2506,6 @@ static inline void comp_func_solid_Difference_impl(QRgba64 *dest, int length, QR } } -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)); -} - void QT_FASTCALL comp_func_solid_Difference_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -2446,6 +2513,7 @@ void QT_FASTCALL comp_func_solid_Difference_rgb64(QRgba64 *dest, int length, QRg else comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -2468,6 +2536,15 @@ static inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const u } } +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)); +} + +#if QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_Difference_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -2489,14 +2566,6 @@ static inline void comp_func_Difference_impl(QRgba64 *Q_DECL_RESTRICT dest, cons } } -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)); -} - void QT_FASTCALL comp_func_Difference_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -2504,6 +2573,7 @@ void QT_FASTCALL comp_func_Difference_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const else comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif /* Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) @@ -2531,6 +2601,15 @@ static inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int le } } +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)); +} + +#if QT_CONFIG(raster_64bit) template <typename T> static inline void QT_FASTCALL comp_func_solid_Exclusion_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage) { @@ -2555,14 +2634,6 @@ static inline void QT_FASTCALL comp_func_solid_Exclusion_impl(QRgba64 *dest, int } -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)); -} - void QT_FASTCALL comp_func_solid_Exclusion_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) { if (const_alpha == 255) @@ -2570,6 +2641,7 @@ void QT_FASTCALL comp_func_solid_Exclusion_rgb64(QRgba64 *dest, int length, QRgb else comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha)); } +#endif template <typename T> static inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) @@ -2592,6 +2664,15 @@ static inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const ui } } +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)); +} + +#if QT_CONFIG(raster_64bit) template <typename T> static inline void comp_func_Exclusion_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -2613,14 +2694,6 @@ static inline void comp_func_Exclusion_impl(QRgba64 *Q_DECL_RESTRICT dest, const } } -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 comp_func_Exclusion_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) { if (const_alpha == 255) @@ -2628,6 +2701,7 @@ void QT_FASTCALL comp_func_Exclusion_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const else comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#endif void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, int length, @@ -2977,6 +3051,7 @@ CompositionFunctionSolid qt_functionForModeSolid_C[] = { }; CompositionFunctionSolid64 qt_functionForModeSolid64_C[] = { +#if QT_CONFIG(raster_64bit) comp_func_solid_SourceOver_rgb64, comp_func_solid_DestinationOver_rgb64, comp_func_solid_Clear_rgb64, @@ -3001,6 +3076,10 @@ CompositionFunctionSolid64 qt_functionForModeSolid64_C[] = { comp_func_solid_SoftLight_rgb64, comp_func_solid_Difference_rgb64, comp_func_solid_Exclusion_rgb64, +#else + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#endif 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -3047,6 +3126,7 @@ CompositionFunction qt_functionForMode_C[] = { }; CompositionFunction64 qt_functionForMode64_C[] = { +#if QT_CONFIG(raster_64bit) comp_func_SourceOver_rgb64, comp_func_DestinationOver_rgb64, comp_func_Clear_rgb64, @@ -3071,6 +3151,10 @@ CompositionFunction64 qt_functionForMode64_C[] = { comp_func_SoftLight_rgb64, comp_func_Difference_rgb64, comp_func_Exclusion_rgb64, +#else + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#endif 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; diff --git a/src/gui/painting/qcosmeticstroker_p.h b/src/gui/painting/qcosmeticstroker_p.h index 082ddee30f..8571b0476a 100644 --- a/src/gui/painting/qcosmeticstroker_p.h +++ b/src/gui/painting/qcosmeticstroker_p.h @@ -98,8 +98,8 @@ public: : state(s), deviceRect(dr_unclipped), clip(dr), - pattern(0), - reversePattern(0), + pattern(nullptr), + reversePattern(nullptr), patternSize(0), patternLength(0), patternOffset(0), diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h index 28d5f6d6c5..181d19da0b 100644 --- a/src/gui/painting/qdatabuffer_p.h +++ b/src/gui/painting/qdatabuffer_p.h @@ -69,7 +69,7 @@ public: buffer = (Type*) malloc(capacity * sizeof(Type)); Q_CHECK_PTR(buffer); } else { - buffer = 0; + buffer = nullptr; } siz = 0; } @@ -128,7 +128,7 @@ public: Q_CHECK_PTR(buffer); } else { free(buffer); - buffer = 0; + buffer = nullptr; } } diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 2dd18f6dfc..ac15d8f4f4 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -43,7 +43,7 @@ #include <qstylehints.h> #include <qguiapplication.h> #include <qatomic.h> -#include <private/qcolorprofile_p.h> +#include <private/qcolortrclut_p.h> #include <private/qdrawhelper_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qpainter_p.h> @@ -1117,6 +1117,7 @@ static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr); } +#if QT_CONFIG(raster_64bit) static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count) { for (int i = 0; i < count; ++i) @@ -1126,6 +1127,7 @@ static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count) static void convertRGBA64PMToRGBA64PM(QRgba64 *, int) { } +#endif static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count, const QVector<QRgb> *, QDitherInfo *) @@ -1699,22 +1701,6 @@ static uint *QT_FASTCALL destFetchUndefined(uint *buffer, QRasterBuffer *, int, return buffer; } -static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) -{ - const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; - return const_cast<QRgba64 *>(layout->fetchToRGBA64PM(buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr)); -} - -static QRgba64 * QT_FASTCALL destFetchRGB64(QRgba64 *, QRasterBuffer *rasterBuffer, int x, int y, int) -{ - return (QRgba64 *)rasterBuffer->scanLine(y) + x; -} - -static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer *, int, int, int) -{ - return buffer; -} - static DestFetchProc destFetchProc[QImage::NImageFormats] = { 0, // Format_Invalid @@ -1748,6 +1734,23 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = destFetch, // Format_Grayscale16 }; +#if QT_CONFIG(raster_64bit) +static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; + return const_cast<QRgba64 *>(layout->fetchToRGBA64PM(buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr)); +} + +static QRgba64 * QT_FASTCALL destFetchRGB64(QRgba64 *, QRasterBuffer *rasterBuffer, int x, int y, int) +{ + return (QRgba64 *)rasterBuffer->scanLine(y) + x; +} + +static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer *, int, int, int) +{ + return buffer; +} + static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = { 0, // Format_Invalid @@ -1780,6 +1783,7 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = destFetchRGB64, // Format_RGBA64_Premultiplied destFetch64, // Format_Grayscale16 }; +#endif /* Returns the color in the mono destination color table @@ -1887,21 +1891,6 @@ static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, con store(dest, buffer, x, length, nullptr, nullptr); } -static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) -{ - auto store = qStoreFromRGBA64PM[rasterBuffer->format]; - uchar *dest = rasterBuffer->scanLine(y); - store(dest, buffer, x, length, nullptr, nullptr); -} - -static void QT_FASTCALL destStore64RGBA64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) -{ - QRgba64 *dest = reinterpret_cast<QRgba64*>(rasterBuffer->scanLine(y)) + x; - for (int i = 0; i < length; ++i) { - dest[i] = buffer[i].unpremultiplied(); - } -} - static DestStoreProc destStoreProc[QImage::NImageFormats] = { 0, // Format_Invalid @@ -1935,6 +1924,22 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] = destStore, // Format_Grayscale16 }; +#if QT_CONFIG(raster_64bit) +static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + auto store = qStoreFromRGBA64PM[rasterBuffer->format]; + uchar *dest = rasterBuffer->scanLine(y); + store(dest, buffer, x, length, nullptr, nullptr); +} + +static void QT_FASTCALL destStore64RGBA64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + QRgba64 *dest = reinterpret_cast<QRgba64*>(rasterBuffer->scanLine(y)) + x; + for (int i = 0; i < length; ++i) { + dest[i] = buffer[i].unpremultiplied(); + } +} + static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = { 0, // Format_Invalid @@ -1967,6 +1972,7 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = 0, // Format_RGBA64_Premultiplied destStore64, // Format_Grayscale16 }; +#endif /* Source fetches @@ -2017,6 +2023,7 @@ static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Opera return buffer; } +#if QT_CONFIG(raster_64bit) static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Operator *, const QSpanData *data, int y, int x, int length) { @@ -2030,6 +2037,7 @@ static const QRgba64 *QT_FASTCALL fetchUntransformedRGBA64PM(QRgba64 *, const Op const uchar *scanLine = data->texture.scanLine(y); return reinterpret_cast<const QRgba64 *>(scanLine) + x; } +#endif template<TextureBlendType blendType> inline void fetchTransformed_pixelBounds(int max, int l1, int l2, int &v) @@ -2220,6 +2228,7 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, return buffer; } +#if QT_CONFIG(raster_64bit) 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) @@ -2240,6 +2249,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper convertRGBA64ToRGBA64PM(buffer, length); return buffer; } +#endif /** \internal interpolate 4 argb pixels with the distx and disty factor. @@ -3541,6 +3551,7 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper return buffer; } +#if QT_CONFIG(raster_64bit) template<TextureBlendType blendType> static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buffer, const QSpanData *data, int y, int x, int length) @@ -3861,6 +3872,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co return fetchTransformedBilinear64_uint64<blendType>(buffer, data, y, x, length); return fetchTransformedBilinear64_uint32<blendType>(buffer, data, y, x, length); } +#endif // FetchUntransformed can have more specialized methods added depending on SIMD features. static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = { @@ -3931,6 +3943,20 @@ static SourceFetchProc sourceFetchAny32[NBlendTypes] = { fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP32> // TransformedBilinearTiled }; +static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format) +{ + if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied) + return sourceFetchARGB32PM[blendType]; + if (blendType == BlendUntransformed || blendType == BlendTiled) + return sourceFetchUntransformed[format]; + if (qPixelLayouts[format].bpp == QPixelLayout::BPP16) + return sourceFetchAny16[blendType]; + if (qPixelLayouts[format].bpp == QPixelLayout::BPP32) + return sourceFetchAny32[blendType]; + return sourceFetchGeneric[blendType]; +} + +#if QT_CONFIG(raster_64bit) static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = { fetchUntransformed64, // Untransformed fetchUntransformed64, // Tiled @@ -3949,25 +3975,13 @@ static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = { fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled }; -static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format) -{ - if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied) - return sourceFetchARGB32PM[blendType]; - if (blendType == BlendUntransformed || blendType == BlendTiled) - return sourceFetchUntransformed[format]; - if (qPixelLayouts[format].bpp == QPixelLayout::BPP16) - return sourceFetchAny16[blendType]; - if (qPixelLayouts[format].bpp == QPixelLayout::BPP32) - return sourceFetchAny32[blendType]; - return sourceFetchGeneric[blendType]; -} - static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QImage::Format format) { if (format == QImage::Format_RGBX64 || format == QImage::Format_RGBA64_Premultiplied) return sourceFetchRGBA64PM[blendType]; return sourceFetchGeneric64[blendType]; } +#endif #define FIXPT_BITS 8 @@ -3979,11 +3993,13 @@ static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos) return data->colorTable32[qt_gradient_clamp(data, ipos)]; } +#if QT_CONFIG(raster_64bit) static const QRgba64& qt_gradient_pixel64_fixed(const QGradientData *data, int fixed_pos) { int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; return data->colorTable64[qt_gradient_clamp(data, ipos)]; } +#endif static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data) { @@ -4017,6 +4033,7 @@ public: } }; +#if QT_CONFIG(raster_64bit) class GradientBase64 { public: @@ -4035,6 +4052,7 @@ public: qt_memfill64((quint64*)buffer, fill, length); } }; +#endif template<class GradientBase, typename BlendType> static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template( @@ -4112,11 +4130,13 @@ static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Ope return qt_fetch_linear_gradient_template<GradientBase32, uint>(buffer, op, data, y, x, length); } +#if QT_CONFIG(raster_64bit) 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); } +#endif static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data) { @@ -4178,11 +4198,13 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Oper static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain; +#if QT_CONFIG(raster_64bit) const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase64>, QRgba64>(buffer, op, data, y, x, length); } +#endif template <class GradientBase, typename BlendType> static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template( @@ -4241,23 +4263,29 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op return qt_fetch_conical_gradient_template<GradientBase32, uint>(buffer, data, y, x, length); } +#if QT_CONFIG(raster_64bit) static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buffer, const Operator *, const QSpanData *data, int y, int x, int length) { return qt_fetch_conical_gradient_template<GradientBase64, QRgba64>(buffer, data, y, x, length); } +#endif extern CompositionFunctionSolid qt_functionForModeSolid_C[]; extern CompositionFunctionSolid64 qt_functionForModeSolid64_C[]; static const CompositionFunctionSolid *functionForModeSolid = qt_functionForModeSolid_C; +#if QT_CONFIG(raster_64bit) static const CompositionFunctionSolid64 *functionForModeSolid64 = qt_functionForModeSolid64_C; +#endif extern CompositionFunction qt_functionForMode_C[]; extern CompositionFunction64 qt_functionForMode64_C[]; static const CompositionFunction *functionForMode = qt_functionForMode_C; +#if QT_CONFIG(raster_64bit) static const CompositionFunction64 *functionForMode64 = qt_functionForMode64_C; +#endif static TextureBlendType getBlendType(const QSpanData *data) { @@ -4289,41 +4317,58 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in case QSpanData::Solid: solidSource = data->solidColor.isOpaque(); op.srcFetch = 0; +#if QT_CONFIG(raster_64bit) op.srcFetch64 = 0; +#endif break; case QSpanData::LinearGradient: solidSource = !data->gradient.alphaColor; getLinearGradientValues(&op.linear, data); op.srcFetch = qt_fetch_linear_gradient; +#if QT_CONFIG(raster_64bit) op.srcFetch64 = qt_fetch_linear_gradient_rgb64; +#endif break; case QSpanData::RadialGradient: solidSource = !data->gradient.alphaColor; getRadialGradientValues(&op.radial, data); op.srcFetch = qt_fetch_radial_gradient; +#if QT_CONFIG(raster_64bit) op.srcFetch64 = qt_fetch_radial_gradient_rgb64; +#endif break; case QSpanData::ConicalGradient: solidSource = !data->gradient.alphaColor; op.srcFetch = qt_fetch_conical_gradient; +#if QT_CONFIG(raster_64bit) op.srcFetch64 = qt_fetch_conical_gradient_rgb64; +#endif break; case QSpanData::Texture: solidSource = !data->texture.hasAlpha; op.srcFetch = getSourceFetch(getBlendType(data), data->texture.format); +#if QT_CONFIG(raster_64bit) op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);; +#endif break; default: Q_UNREACHABLE(); break; } +#if !QT_CONFIG(raster_64bit) + op.srcFetch64 = 0; +#endif op.mode = data->rasterBuffer->compositionMode; if (op.mode == QPainter::CompositionMode_SourceOver && solidSource) op.mode = QPainter::CompositionMode_Source; op.destFetch = destFetchProc[data->rasterBuffer->format]; +#if QT_CONFIG(raster_64bit) op.destFetch64 = destFetchProc64[data->rasterBuffer->format]; +#else + op.destFetch64 = 0; +#endif if (op.mode == QPainter::CompositionMode_Source && (data->type != QSpanData::Texture || data->texture.const_alpha == 256)) { const QSpan *lastSpan = spans + spanCount; @@ -4340,18 +4385,25 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in // But don't clear passthrough destFetch as they are just as fast and save destStore. if (op.destFetch != destFetchARGB32P) op.destFetch = destFetchUndefined; +#if QT_CONFIG(raster_64bit) if (op.destFetch64 != destFetchRGB64) op.destFetch64 = destFetch64Undefined; +#endif } } op.destStore = destStoreProc[data->rasterBuffer->format]; - op.destStore64 = destStoreProc64[data->rasterBuffer->format]; - op.funcSolid = functionForModeSolid[op.mode]; - op.funcSolid64 = functionForModeSolid64[op.mode]; op.func = functionForMode[op.mode]; +#if QT_CONFIG(raster_64bit) + op.destStore64 = destStoreProc64[data->rasterBuffer->format]; + op.funcSolid64 = functionForModeSolid64[op.mode]; op.func64 = functionForMode64[op.mode]; +#else + op.destStore64 = 0; + op.funcSolid64 = 0; + op.func64 = 0; +#endif return op; } @@ -4458,6 +4510,7 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData) void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) { +#if QT_CONFIG(raster_64bit) QSpanData *data = reinterpret_cast<QSpanData *>(userData); Operator op = getOperator(data, nullptr, 0); if (!op.funcSolid64) { @@ -4492,6 +4545,9 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) } ++spans; } +#else + blend_color_generic(count, spans, userData); +#endif } static void blend_color_rgb16(int count, const QSpan *spans, void *userData) @@ -4665,6 +4721,7 @@ public: } }; +#if QT_CONFIG(raster_64bit) class BlendSrcGenericRGB64 : public QBlendBase<QRgba64> { public: @@ -4695,6 +4752,7 @@ public: op.destStore64(data->rasterBuffer, x, y, dest, len); } }; +#endif static void blend_src_generic(int count, const QSpan *spans, void *userData) { @@ -4703,6 +4761,7 @@ static void blend_src_generic(int count, const QSpan *spans, void *userData) handleSpans(count, spans, data, blend); } +#if QT_CONFIG(raster_64bit) static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -4716,6 +4775,7 @@ static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userDat handleSpans(count, spans, data, blend32); } } +#endif static void blend_untransformed_generic(int count, const QSpan *spans, void *userData) { @@ -4762,6 +4822,7 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use } } +#if QT_CONFIG(raster_64bit) static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -4810,6 +4871,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi ++spans; } } +#endif static void blend_untransformed_argb(int count, const QSpan *spans, void *userData) { @@ -5004,6 +5066,7 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData) } } +#if QT_CONFIG(raster_64bit) static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -5099,6 +5162,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD ++spans; } } +#endif static void blend_tiled_argb(int count, const QSpan *spans, void *userData) { @@ -5275,6 +5339,7 @@ static const ProcessSpans processTextureSpansGeneric[NBlendTypes] = { blend_src_generic // TransformedBilinearTiled }; +#if QT_CONFIG(raster_64bit) static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = { blend_untransformed_generic_rgb64, // Untransformed blend_tiled_generic_rgb64, // Tiled @@ -5283,6 +5348,7 @@ static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = { blend_src_generic_rgb64, // TransformedBilinear blend_src_generic_rgb64 // TransformedBilinearTiled }; +#endif void qBlendTexture(int count, const QSpan *spans, void *userData) { @@ -5296,6 +5362,7 @@ void qBlendTexture(int count, const QSpan *spans, void *userData) case QImage::Format_RGB16: proc = processTextureSpansRGB16[blendType]; break; +#if QT_CONFIG(raster_64bit) #if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8) case QImage::Format_ARGB32: case QImage::Format_RGBA8888: @@ -5310,6 +5377,7 @@ void qBlendTexture(int count, const QSpan *spans, void *userData) case QImage::Format_Grayscale16: proc = processTextureSpansGeneric64[blendType]; break; +#endif // QT_CONFIG(raster_64bit) case QImage::Format_Invalid: Q_UNREACHABLE(); return; @@ -5377,7 +5445,11 @@ static void blend_vertical_gradient(int count, const QSpan *spans, void *userDat while (count--) { int y = spans->y; +#if QT_CONFIG(raster_64bit) data->solidColor = qt_gradient_pixel64_fixed(&data->gradient, yinc * y + off); +#else + data->solidColor = QRgba64::fromArgb32(qt_gradient_pixel_fixed(&data->gradient, yinc * y + off)); +#endif blend_color(1, spans, userData); ++spans; } @@ -5400,6 +5472,7 @@ void qBlendGradient(int count, const QSpan *spans, void *userData) if (isVerticalGradient) return blend_vertical_gradient_argb(count, spans, userData); return blend_src_generic(count, spans, userData); +#if QT_CONFIG(raster_64bit) #if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8) case QImage::Format_ARGB32: case QImage::Format_RGBA8888: @@ -5414,6 +5487,7 @@ void qBlendGradient(int count, const QSpan *spans, void *userData) if (isVerticalGradient) return blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData); return blend_src_generic_rgb64(count, spans, userData); +#endif // QT_CONFIG(raster_64bit) case QImage::Format_Invalid: break; default: @@ -5523,7 +5597,36 @@ inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer, map, mapWidth, mapHeight, mapStride); } -static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorProfile *colorProfile) +static inline void grayBlendPixel(quint32 *dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile) +{ + // Do a gammacorrected gray alphablend... + const QRgba64 dstLinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst); + + QRgba64 blend = interpolate255(srcLinear, coverage, dstLinear, 255 - coverage); + + *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend); +} + +static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcLinear, quint32 src, const QColorTrcLut *colorProfile) +{ + if (coverage == 0) { + // nothing + } else if (coverage == 255) { + *dst = src; + } else if (!colorProfile) { + *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); + } else { + if (*dst >= 0xff000000) { + grayBlendPixel(dst, coverage, srcLinear, colorProfile); + } else { + // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 + *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); + } + } +} + +#if QT_CONFIG(raster_64bit) +static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile) { if (coverage == 0) { // nothing @@ -5558,7 +5661,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, if (color.isTransparent()) return; - const QColorProfile *colorProfile = nullptr; + const QColorTrcLut *colorProfile = nullptr; if (useGammaCorrection) colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); @@ -5624,6 +5727,85 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, } // for (yp -> bottom) } } +#else +static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, + int x, int y, const QRgba64 &color, + const uchar *map, + int mapWidth, int mapHeight, int mapStride, + const QClipData *clip, bool useGammaCorrection) +{ + if (color.isTransparent()) + return; + + const quint32 c = color.toArgb32(); + + const QColorTrcLut *colorProfile = nullptr; + + if (useGammaCorrection) + colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); + + QRgba64 srcColor = color; + if (colorProfile) { + if (color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); + else + srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); + } + + quint32 buffer[BufferSize]; + const DestFetchProc destFetch = destFetchProc[rasterBuffer->format]; + const DestStoreProc destStore = destStoreProc[rasterBuffer->format]; + + if (!clip) { + for (int ly = 0; ly < mapHeight; ++ly) { + int i = x; + int length = mapWidth; + while (length > 0) { + int l = qMin(BufferSize, length); + quint32 *dest = destFetch(buffer, rasterBuffer, i, y + ly, l); + for (int j=0; j < l; ++j) { + const int coverage = map[j + (i - x)]; + alphamapblend_argb32(dest + j, coverage, srcColor, c, colorProfile); + } + if (destStore) + destStore(rasterBuffer, i, y + ly, dest, l); + length -= l; + i += l; + } + map += mapStride; + } + } else { + int bottom = qMin(y + mapHeight, rasterBuffer->height()); + + int top = qMax(y, 0); + map += (top - y) * mapStride; + + const_cast<QClipData *>(clip)->initialize(); + for (int yp = top; yp<bottom; ++yp) { + const QClipData::ClipLine &line = clip->m_clipLines[yp]; + + for (int i=0; i<line.count; ++i) { + const QSpan &clip = line.spans[i]; + + int start = qMax<int>(x, clip.x); + int end = qMin<int>(x + mapWidth, clip.x + clip.len); + if (end <= start) + continue; + Q_ASSERT(end - start <= BufferSize); + quint32 *dest = destFetch(buffer, rasterBuffer, start, clip.y, end - start); + + for (int xp=start; xp<end; ++xp) { + const int coverage = map[xp - x]; + alphamapblend_argb32(dest + xp - x, coverage, srcColor, color, colorProfile); + } + if (destStore) + destStore(rasterBuffer, start, clip.y, dest, end - start); + } // for (i -> line.count) + map += mapStride; + } // for (yp -> bottom) + } +} +#endif static inline void alphamapblend_quint16(int coverage, quint16 *dest, int x, const quint16 srcColor) { @@ -5684,44 +5866,6 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer, } } -static inline void rgbBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorProfile *colorProfile) -{ - // Do a gammacorrected RGB alphablend... - const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst); - - QRgba64 blend = rgbBlend(dlinear, slinear, coverage); - - *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend); -} - -static inline void grayBlendPixel(quint32 *dst, int coverage, QRgba64 srcLinear, const QColorProfile *colorProfile) -{ - // Do a gammacorrected gray alphablend... - const QRgba64 dstLinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst); - - QRgba64 blend = interpolate255(srcLinear, coverage, dstLinear, 255 - coverage); - - *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend); -} - -static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcLinear, quint32 src, const QColorProfile *colorProfile) -{ - if (coverage == 0) { - // nothing - } else if (coverage == 255) { - *dst = src; - } else if (!colorProfile) { - *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); - } else { - if (*dst >= 0xff000000) { - grayBlendPixel(dst, coverage, srcLinear, colorProfile); - } else { - // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 - *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); - } - } -} - static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uchar *map, @@ -5734,7 +5878,7 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer, if (color.isTransparent()) return; - const QColorProfile *colorProfile = nullptr; + const QColorTrcLut *colorProfile = nullptr; if (useGammaCorrection) colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); @@ -5790,6 +5934,16 @@ static inline int qRgbAvg(QRgb rgb) return (qRed(rgb) * 5 + qGreen(rgb) * 6 + qBlue(rgb) * 5) / 16; } +static inline void rgbBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile) +{ + // Do a gammacorrected RGB alphablend... + const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst); + + QRgba64 blend = rgbBlend(dlinear, slinear, coverage); + + *dst = colorProfile ? colorProfile->fromLinear64(blend) : toArgb32(blend); +} + static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha) { #if defined(__SSE2__) @@ -5830,7 +5984,8 @@ static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha) #endif } -static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorProfile *colorProfile) +#if QT_CONFIG(raster_64bit) +static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile) { if (coverage == 0xff000000) { // nothing @@ -5851,8 +6006,9 @@ static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, co } } } +#endif -static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorProfile *colorProfile) +static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile) { if (coverage == 0xff000000) { // nothing @@ -5869,6 +6025,7 @@ static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba } } +#if QT_CONFIG(raster_64bit) static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uint *src, int mapWidth, int mapHeight, int srcStride, @@ -5877,7 +6034,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, if (color.isTransparent()) return; - const QColorProfile *colorProfile = nullptr; + const QColorTrcLut *colorProfile = nullptr; if (useGammaCorrection) colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); @@ -5943,6 +6100,84 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, } // for (yp -> bottom) } } +#else +static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, + int x, int y, const QRgba64 &color, + const uint *src, int mapWidth, int mapHeight, int srcStride, + const QClipData *clip, bool useGammaCorrection) +{ + if (color.isTransparent()) + return; + + const quint32 c = color.toArgb32(); + + const QColorTrcLut *colorProfile = nullptr; + + if (useGammaCorrection) + colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); + + QRgba64 srcColor = color; + if (colorProfile) { + if (color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); + else + srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); + } + + quint32 buffer[BufferSize]; + const DestFetchProc destFetch = destFetchProc[rasterBuffer->format]; + const DestStoreProc destStore = destStoreProc[rasterBuffer->format]; + + if (!clip) { + for (int ly = 0; ly < mapHeight; ++ly) { + int i = x; + int length = mapWidth; + while (length > 0) { + int l = qMin(BufferSize, length); + quint32 *dest = destFetch(buffer, rasterBuffer, i, y + ly, l); + for (int j=0; j < l; ++j) { + const uint coverage = src[j + (i - x)]; + alphargbblend_argb32(dest + j, coverage, srcColor, c, colorProfile); + } + if (destStore) + destStore(rasterBuffer, i, y + ly, dest, l); + length -= l; + i += l; + } + src += srcStride; + } + } else { + int bottom = qMin(y + mapHeight, rasterBuffer->height()); + + int top = qMax(y, 0); + src += (top - y) * srcStride; + + const_cast<QClipData *>(clip)->initialize(); + for (int yp = top; yp<bottom; ++yp) { + const QClipData::ClipLine &line = clip->m_clipLines[yp]; + + for (int i=0; i<line.count; ++i) { + const QSpan &clip = line.spans[i]; + + int start = qMax<int>(x, clip.x); + int end = qMin<int>(x + mapWidth, clip.x + clip.len); + if (end <= start) + continue; + Q_ASSERT(end - start <= BufferSize); + quint32 *dest = destFetch(buffer, rasterBuffer, start, clip.y, end - start); + + for (int xp=start; xp<end; ++xp) { + const uint coverage = src[xp - x]; + alphargbblend_argb32(dest + xp - start, coverage, srcColor, c, colorProfile); + } + if (destStore) + destStore(rasterBuffer, start, clip.y, dest, end - start); + } // for (i -> line.count) + src += srcStride; + } // for (yp -> bottom) + } +} +#endif static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, @@ -5954,7 +6189,7 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, const quint32 c = color.toArgb32(); - const QColorProfile *colorProfile = nullptr; + const QColorTrcLut *colorProfile = nullptr; if (useGammaCorrection) colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); @@ -6533,8 +6768,10 @@ static void qInitDrawhelperFunctions() qPixelLayouts[QImage::Format_A2RGB30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>; qStoreFromRGBA64PM[QImage::Format_ARGB32] = storeARGB32FromRGBA64PM_sse4; qStoreFromRGBA64PM[QImage::Format_RGBA8888] = storeRGBA8888FromRGBA64PM_sse4; +#if QT_CONFIG(raster_64bit) destStoreProc64[QImage::Format_ARGB32] = destStore64ARGB32_sse4; destStoreProc64[QImage::Format_RGBA8888] = destStore64RGBA8888_sse4; +#endif } #endif @@ -6558,18 +6795,19 @@ static void qInitDrawhelperFunctions() qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx2; extern void QT_FASTCALL comp_func_Source_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); - extern void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha); extern void QT_FASTCALL comp_func_SourceOver_avx2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); - extern void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha); extern void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha); - extern void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int length, QRgba64 color, uint const_alpha); - qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_avx2; - qt_functionForMode64_C[QPainter::CompositionMode_Source] = comp_func_Source_rgb64_avx2; qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_avx2; - qt_functionForMode64_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgb64_avx2; qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2; +#if QT_CONFIG(raster_64bit) + extern void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *destPixels, const QRgba64 *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int length, QRgba64 color, uint const_alpha); + qt_functionForMode64_C[QPainter::CompositionMode_Source] = comp_func_Source_rgb64_avx2; + qt_functionForMode64_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgb64_avx2; qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2; +#endif extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int /*fdy*/); @@ -6593,6 +6831,7 @@ static void qInitDrawhelperFunctions() qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_avx2; qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2; +#if QT_CONFIG(raster_64bit) extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_avx2(QRgba64 *, const uint *, int, const QVector<QRgb> *, QDitherInfo *); extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uint *, int count, const QVector<QRgb> *, QDitherInfo *); extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QVector<QRgb> *, QDitherInfo *); @@ -6601,6 +6840,7 @@ static void qInitDrawhelperFunctions() qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_avx2; qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_avx2; qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_avx2; +#endif } #endif diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp index 2b3cc9b226..fb50cb6a50 100644 --- a/src/gui/painting/qdrawhelper_avx2.cpp +++ b/src/gui/painting/qdrawhelper_avx2.cpp @@ -396,6 +396,7 @@ void QT_FASTCALL comp_func_SourceOver_avx2(uint *destPixels, const uint *srcPixe BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_AVX2(dst, src, length, const_alpha); } +#if QT_CONFIG(raster_64bit) void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *dst, const QRgba64 *src, int length, uint const_alpha) { Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255] @@ -453,6 +454,7 @@ void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *dst, const QRgba64 *sr blend_pixel(dst[x], src[x], const_alpha); } } +#endif void QT_FASTCALL comp_func_Source_avx2(uint *dst, const uint *src, int length, uint const_alpha) { @@ -485,6 +487,7 @@ void QT_FASTCALL comp_func_Source_avx2(uint *dst, const uint *src, int length, u } } +#if QT_CONFIG(raster_64bit) void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *dst, const QRgba64 *src, int length, uint const_alpha) { Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255] @@ -517,6 +520,7 @@ void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *dst, const QRgba64 *src, i dst[x] = interpolate65535(src[x], ca, dst[x], cia); } } +#endif void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha) { @@ -549,6 +553,7 @@ void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, u } } +#if QT_CONFIG(raster_64bit) void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int length, QRgba64 color, uint const_alpha) { Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255] @@ -579,6 +584,7 @@ void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int destPixels[x] = color + multiplyAlpha65535(destPixels[x], minusAlphaOfColor); } } +#endif #define interpolate_4_pixels_16_avx2(tlr1, tlr2, blr1, blr2, distx, disty, colorMask, v_256, b) \ { \ diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 37108949d6..9c5d525722 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -296,7 +296,9 @@ struct QGradientData #define GRADIENT_STOPTABLE_SIZE 1024 #define GRADIENT_STOPTABLE_SIZE_SHIFT 10 +#if QT_CONFIG(raster_64bit) const QRgba64 *colorTable64; //[GRADIENT_STOPTABLE_SIZE]; +#endif const QRgb *colorTable32; //[GRADIENT_STOPTABLE_SIZE]; uint alphaColor : 1; @@ -328,7 +330,7 @@ struct QTextureData struct QSpanData { - QSpanData() : tempImage(0) {} + QSpanData() : tempImage(nullptr) {} ~QSpanData() { delete tempImage; } QRasterBuffer *rasterBuffer; @@ -402,11 +404,13 @@ static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos) return data->colorTable32[qt_gradient_clamp(data, ipos)]; } +#if QT_CONFIG(raster_64bit) static inline const QRgba64& qt_gradient_pixel64(const QGradientData *data, qreal pos) { int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5)); return data->colorTable64[qt_gradient_clamp(data, ipos)]; } +#endif static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) { diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp index e387026972..68d887ae6d 100644 --- a/src/gui/painting/qdrawhelper_sse4.cpp +++ b/src/gui/painting/qdrawhelper_sse4.cpp @@ -417,6 +417,7 @@ void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, i d[i] = qConvertArgb32ToA2rgb30_sse4<PixelOrder>(src[i]); } +#if QT_CONFIG(raster_64bit) void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) { uint *dest = (uint*)rasterBuffer->scanLine(y) + x; @@ -428,6 +429,7 @@ void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, in uint *dest = (uint*)rasterBuffer->scanLine(y) + x; convertARGBFromRGBA64PM_sse4<true>(dest, buffer, length); } +#endif void QT_FASTCALL storeARGB32FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count, const QVector<QRgb> *, QDitherInfo *) diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp new file mode 100644 index 0000000000..d88b005782 --- /dev/null +++ b/src/gui/painting/qicc.cpp @@ -0,0 +1,669 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qicc_p.h" + +#include <qbuffer.h> +#include <qbytearray.h> +#include <qdatastream.h> +#include <qloggingcategory.h> +#include <qendian.h> + +#include "qcolorspace_p.h" +#include "qcolortrc_p.h" + +QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcIcc, "qt.gui.icc") + +struct ICCProfileHeader +{ + quint32_be profileSize; + + quint32_be preferredCmmType; + + quint32_be profileVersion; + quint32_be profileClass; + quint32_be inputColorSpace; + quint32_be pcs; + quint32_be datetime[3]; + quint32_be signature; + quint32_be platformSignature; + quint32_be flags; + quint32_be deviceManufacturer; + quint32_be deviceModel; + quint32_be deviceAttributes[2]; + + quint32_be renderingIntent; + qint32_be illuminantXyz[3]; + + quint32_be creatorSignature; + quint32_be profileId[4]; + + quint32_be reserved[7]; + +// Technically after the header, but easier to include here: + quint32_be tagCount; +}; + +constexpr quint32 IccTag(uchar a, uchar b, uchar c, uchar d) +{ + return (a << 24) | (b << 16) | (c << 8) | d; +} + +enum class ProfileClass : quint32 { + Input = IccTag('s', 'c', 'r', 'n'), + Display = IccTag('m', 'n', 't', 'r'), + // Not supported: + Output = IccTag('p', 'r', 't', 'r'), + ColorSpace = IccTag('s', 'p', 'a', 'c'), +}; + +enum class Tag : quint32 { + acsp = IccTag('a', 'c', 's', 'p'), + RGB_ = IccTag('R', 'G', 'B', ' '), + XYZ_ = IccTag('X', 'Y', 'Z', ' '), + rXYZ = IccTag('r', 'X', 'Y', 'Z'), + gXYZ = IccTag('g', 'X', 'Y', 'Z'), + bXYZ = IccTag('b', 'X', 'Y', 'Z'), + rTRC = IccTag('r', 'T', 'R', 'C'), + gTRC = IccTag('g', 'T', 'R', 'C'), + bTRC = IccTag('b', 'T', 'R', 'C'), + A2B0 = IccTag('A', '2', 'B', '0'), + A2B1 = IccTag('A', '2', 'B', '1'), + B2A0 = IccTag('B', '2', 'A', '0'), + B2A1 = IccTag('B', '2', 'A', '1'), + desc = IccTag('d', 'e', 's', 'c'), + text = IccTag('t', 'e', 'x', 't'), + cprt = IccTag('c', 'p', 'r', 't'), + curv = IccTag('c', 'u', 'r', 'v'), + para = IccTag('p', 'a', 'r', 'a'), + wtpt = IccTag('w', 't', 'p', 't'), + bkpt = IccTag('b', 'k', 'p', 't'), + mft1 = IccTag('m', 'f', 't', '1'), + mft2 = IccTag('m', 'f', 't', '2'), + mAB_ = IccTag('m', 'A', 'B', ' '), + mBA_ = IccTag('m', 'B', 'A', ' '), + chad = IccTag('c', 'h', 'a', 'd'), + sf32 = IccTag('s', 'f', '3', '2'), + + // Apple extensions for ICCv2: + aarg = IccTag('a', 'a', 'r', 'g'), + aagg = IccTag('a', 'a', 'g', 'g'), + aabg = IccTag('a', 'a', 'b', 'g'), +}; + +inline uint qHash(const Tag &key, uint seed = 0) +{ + return qHash(quint32(key), seed); +} + +namespace QIcc { + +struct TagTableEntry +{ + quint32_be signature; + quint32_be offset; + quint32_be size; +}; + +struct GenericTagData { + quint32_be type; + quint32_be null; +}; + +struct XYZTagData : GenericTagData { + qint32_be fixedX; + qint32_be fixedY; + qint32_be fixedZ; +}; + +struct CurvTagData : GenericTagData { + quint32_be valueCount; + quint16_be value[1]; +}; + +struct ParaTagData : GenericTagData { + quint16_be curveType; + quint16_be null2; + quint32_be parameter[1]; +}; + +// For both mAB and mBA +struct mABTagData : GenericTagData { + quint8 inputChannels; + quint8 outputChannels; + quint8 padding[2]; + quint32_be bCurvesOffset; + quint32_be matrixOffset; + quint32_be mCurvesOffset; + quint32_be clutOffset; + quint32_be aCurvesOffset; +}; + +struct Sf32TagData : GenericTagData { + quint32_be value[1]; +}; + +static int toFixedS1516(float x) +{ + return int(x * 65536.0f + 0.5f); +} + +static float fromFixedS1516(int x) +{ + return x * (1.0f / 65536.0f); +} + +QColorVector fromXyzData(const XYZTagData *xyz) +{ + const float x = fromFixedS1516(xyz->fixedX); + const float y = fromFixedS1516(xyz->fixedY); + const float z = fromFixedS1516(xyz->fixedZ); + qCDebug(lcIcc) << "XYZ_ " << x << y << z; + + return QColorVector(x, y, z); +} + +static bool isValidIccProfile(const ICCProfileHeader &header) +{ + if (header.signature != uint(Tag::acsp)) { + qCWarning(lcIcc, "Failed ICC signature test"); + return false; + } + if (header.profileSize < (sizeof(ICCProfileHeader) + header.tagCount * sizeof(TagTableEntry))) { + qCWarning(lcIcc, "Failed basic size sanity"); + return false; + } + + if (header.profileClass != uint(ProfileClass::Input) + && header.profileClass != uint(ProfileClass::Display)) { + qCWarning(lcIcc, "Unsupported ICC profile class %x", quint32(header.profileClass)); + return false; + } + if (header.inputColorSpace != 0x52474220 /* 'RGB '*/) { + qCWarning(lcIcc, "Unsupported ICC input color space %x", quint32(header.inputColorSpace)); + return false; + } + if (header.pcs != 0x58595a20 /* 'XYZ '*/) { + // ### support PCSLAB + qCWarning(lcIcc, "Unsupported ICC profile connection space %x", quint32(header.pcs)); + return false; + } + + QColorVector illuminant; + illuminant.x = fromFixedS1516(header.illuminantXyz[0]); + illuminant.y = fromFixedS1516(header.illuminantXyz[1]); + illuminant.z = fromFixedS1516(header.illuminantXyz[2]); + if (illuminant != QColorVector::D50()) { + qCWarning(lcIcc, "Invalid ICC illuminant"); + return false; + } + + return true; +} + +static int writeColorTrc(QDataStream &stream, const QColorTrc &trc) +{ + if (trc.isLinear()) { + stream << uint(Tag::curv) << uint(0); + stream << uint(0); + return 12; + } + + if (trc.m_type == QColorTrc::Type::Function) { + const QColorTransferFunction &fun = trc.m_fun; + stream << uint(Tag::para) << uint(0); + if (fun.isGamma()) { + stream << ushort(0) << ushort(0); + stream << toFixedS1516(fun.m_g); + return 12 + 4; + } + bool type3 = qFuzzyIsNull(fun.m_e) && qFuzzyIsNull(fun.m_f); + stream << ushort(type3 ? 3 : 4) << ushort(0); + stream << toFixedS1516(fun.m_g); + stream << toFixedS1516(fun.m_a); + stream << toFixedS1516(fun.m_b); + stream << toFixedS1516(fun.m_c); + stream << toFixedS1516(fun.m_d); + if (type3) + return 12 + 5 * 4; + stream << toFixedS1516(fun.m_e); + stream << toFixedS1516(fun.m_f); + return 12 + 7 * 4; + } + + Q_ASSERT(trc.m_type == QColorTrc::Type::Table); + stream << uint(Tag::curv) << uint(0); + stream << uint(trc.m_table.m_tableSize); + if (!trc.m_table.m_table16.isEmpty()) { + for (uint i = 0; i < trc.m_table.m_tableSize; ++i) { + stream << ushort(trc.m_table.m_table16[i]); + } + } else { + for (uint i = 0; i < trc.m_table.m_tableSize; ++i) { + stream << ushort(trc.m_table.m_table8[i] * 257U); + } + } + return 12 + 2 * trc.m_table.m_tableSize; +} + +QByteArray toIccProfile(const QColorSpace &space) +{ + if (!space.isValid()) + return QByteArray(); + + const QColorSpacePrivate *spaceDPtr = space.d_func(); + + constexpr int tagCount = 9; + constexpr uint profileDataOffset = 128 + 4 + 12 * tagCount; + constexpr uint variableTagTableOffsets = 128 + 4 + 12 * 5; + uint currentOffset = 0; + uint rTrcOffset, gTrcOffset, bTrcOffset; + uint rTrcSize, gTrcSize, bTrcSize; + uint descOffset, descSize; + + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + QDataStream stream(&buffer); + + // Profile header: + stream << uint(0); // Size, we will update this later + stream << uint(0); + stream << uint(0x02400000); // Version 2.4 (note we use 'para' from version 4) + stream << uint(ProfileClass::Display); + stream << uint(Tag::RGB_); + stream << uint(Tag::XYZ_); + stream << uint(0) << uint(0) << uint(0); + stream << uint(Tag::acsp); + stream << uint(0) << uint(0) << uint(0); + stream << uint(0) << uint(0) << uint(0); + stream << uint(1); // Rendering intent + stream << uint(0x0000f6d6); // D50 X + stream << uint(0x00010000); // D50 Y + stream << uint(0x0000d32d); // D50 Z + stream << IccTag('Q','t', QT_VERSION_MAJOR, QT_VERSION_MINOR); + stream << uint(0) << uint(0) << uint(0) << uint(0); + stream << uint(0) << uint(0) << uint(0) << uint(0) << uint(0) << uint(0) << uint(0); + + // Tag table: + stream << uint(tagCount); + stream << uint(Tag::rXYZ) << uint(profileDataOffset + 00) << uint(20); + stream << uint(Tag::gXYZ) << uint(profileDataOffset + 20) << uint(20); + stream << uint(Tag::bXYZ) << uint(profileDataOffset + 40) << uint(20); + stream << uint(Tag::wtpt) << uint(profileDataOffset + 60) << uint(20); + stream << uint(Tag::cprt) << uint(profileDataOffset + 80) << uint(12); + // From here the offset and size will be updated later: + stream << uint(Tag::rTRC) << uint(0) << uint(0); + stream << uint(Tag::gTRC) << uint(0) << uint(0); + stream << uint(Tag::bTRC) << uint(0) << uint(0); + stream << uint(Tag::desc) << uint(0) << uint(0); + // TODO: consider adding 'chad' tag (required in ICC >=4 when we have non-D50 whitepoint) + currentOffset = profileDataOffset; + + // Tag data: + stream << uint(Tag::XYZ_) << uint(0); + stream << toFixedS1516(spaceDPtr->toXyz.r.x); + stream << toFixedS1516(spaceDPtr->toXyz.r.y); + stream << toFixedS1516(spaceDPtr->toXyz.r.z); + stream << uint(Tag::XYZ_) << uint(0); + stream << toFixedS1516(spaceDPtr->toXyz.g.x); + stream << toFixedS1516(spaceDPtr->toXyz.g.y); + stream << toFixedS1516(spaceDPtr->toXyz.g.z); + stream << uint(Tag::XYZ_) << uint(0); + stream << toFixedS1516(spaceDPtr->toXyz.b.x); + stream << toFixedS1516(spaceDPtr->toXyz.b.y); + stream << toFixedS1516(spaceDPtr->toXyz.b.z); + stream << uint(Tag::XYZ_) << uint(0); + stream << toFixedS1516(spaceDPtr->whitePoint.x); + stream << toFixedS1516(spaceDPtr->whitePoint.y); + stream << toFixedS1516(spaceDPtr->whitePoint.z); + stream << uint(Tag::text) << uint(0); + stream << uint(IccTag('N', '/', 'A', '\0')); + currentOffset += 92; + + // From now on the data is variable sized: + rTrcOffset = currentOffset; + rTrcSize = writeColorTrc(stream, spaceDPtr->trc[0]); + currentOffset += rTrcSize; + if (spaceDPtr->trc[0] == spaceDPtr->trc[1]) { + gTrcOffset = rTrcOffset; + gTrcSize = rTrcSize; + } else { + gTrcOffset = currentOffset; + gTrcSize = writeColorTrc(stream, spaceDPtr->trc[1]); + currentOffset += gTrcSize; + } + if (spaceDPtr->trc[0] == spaceDPtr->trc[2]) { + bTrcOffset = rTrcOffset; + bTrcSize = rTrcSize; + } else { + bTrcOffset = currentOffset; + bTrcSize = writeColorTrc(stream, spaceDPtr->trc[2]); + currentOffset += bTrcSize; + } + + descOffset = currentOffset; + QByteArray description = spaceDPtr->description.toUtf8(); + stream << uint(Tag::desc) << uint(0); + stream << uint(description.size() + 1); + stream.writeRawData(description.constData(), description.size() + 1); + stream << uint(0) << uint(0); + stream << ushort(0) << uchar(0); + QByteArray macdesc(67, '\0'); + stream.writeRawData(macdesc.constData(), 67); + descSize = 90 + description.size() + 1; + currentOffset += descSize; + + buffer.close(); + QByteArray iccProfile = buffer.buffer(); + // Now write final size + *(quint32_be *)iccProfile.data() = iccProfile.size(); + // And the final indices and sizes of variable size tags: + *(quint32_be *)(iccProfile.data() + variableTagTableOffsets + 4) = rTrcOffset; + *(quint32_be *)(iccProfile.data() + variableTagTableOffsets + 8) = rTrcSize; + *(quint32_be *)(iccProfile.data() + variableTagTableOffsets + 12 + 4) = gTrcOffset; + *(quint32_be *)(iccProfile.data() + variableTagTableOffsets + 12 + 8) = gTrcSize; + *(quint32_be *)(iccProfile.data() + variableTagTableOffsets + 2 * 12 + 4) = bTrcOffset; + *(quint32_be *)(iccProfile.data() + variableTagTableOffsets + 2 * 12 + 8) = bTrcSize; + *(quint32_be *)(iccProfile.data() + variableTagTableOffsets + 3 * 12 + 4) = descOffset; + *(quint32_be *)(iccProfile.data() + variableTagTableOffsets + 3 * 12 + 8) = descSize; + +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + const ICCProfileHeader *iccHeader = (const ICCProfileHeader *)iccProfile.constData(); + Q_ASSERT(qsizetype(iccHeader->profileSize) == qsizetype(iccProfile.size())); + Q_ASSERT(isValidIccProfile(*iccHeader)); +#endif + + return iccProfile; +} + +bool parseTRC(const GenericTagData *trcData, QColorTrc &gamma) +{ + if (trcData->type == quint32(Tag::curv)) { + const CurvTagData *curv = reinterpret_cast<const CurvTagData *>(trcData); + qCDebug(lcIcc) << "curv" << uint(curv->valueCount); + if (curv->valueCount == 0) { + gamma.m_type = QColorTrc::Type::Function; + gamma.m_fun = QColorTransferFunction(); // Linear + } else if (curv->valueCount == 1) { + float g = curv->value[0] * (1.0f / 256.0f); + qCDebug(lcIcc) << g; + gamma.m_type = QColorTrc::Type::Function; + gamma.m_fun = QColorTransferFunction::fromGamma(g); + } else { + QVector<quint16> tabl; + tabl.resize(curv->valueCount); + for (uint i = 0; i < curv->valueCount; ++i) + tabl[i] = curv->value[i]; + QColorTransferTable table = QColorTransferTable(curv->valueCount, std::move(tabl)); + QColorTransferFunction curve; + if (!table.asColorTransferFunction(&curve)) { + gamma.m_type = QColorTrc::Type::Table; + gamma.m_table = table; + } else { + qCDebug(lcIcc) << "Detected curv table as function"; + gamma.m_type = QColorTrc::Type::Function; + gamma.m_fun = curve; + } + } + return true; + } + if (trcData->type == quint32(Tag::para)) { + const ParaTagData *para = reinterpret_cast<const ParaTagData *>(trcData); + qCDebug(lcIcc) << "para" << uint(para->curveType); + switch (para->curveType) { + case 0: { + float g = fromFixedS1516(para->parameter[0]); + qCDebug(lcIcc) << g; + gamma.m_type = QColorTrc::Type::Function; + gamma.m_fun = QColorTransferFunction::fromGamma(g); + break; + } + case 1: { + float g = fromFixedS1516(para->parameter[0]); + float a = fromFixedS1516(para->parameter[1]); + float b = fromFixedS1516(para->parameter[2]); + float d = -b / a; + qCDebug(lcIcc) << g << a << b; + gamma.m_type = QColorTrc::Type::Function; + gamma.m_fun = QColorTransferFunction(a, b, 0.0f, d, 0.0f, 0.0f, g); + break; + } + case 2: { + float g = fromFixedS1516(para->parameter[0]); + float a = fromFixedS1516(para->parameter[1]); + float b = fromFixedS1516(para->parameter[2]); + float c = fromFixedS1516(para->parameter[3]); + float d = -b / a; + qCDebug(lcIcc) << g << a << b << c; + gamma.m_type = QColorTrc::Type::Function; + gamma.m_fun = QColorTransferFunction(a, b, 0.0f, d, c, c, g); + break; + } + case 3: { + float g = fromFixedS1516(para->parameter[0]); + float a = fromFixedS1516(para->parameter[1]); + float b = fromFixedS1516(para->parameter[2]); + float c = fromFixedS1516(para->parameter[3]); + float d = fromFixedS1516(para->parameter[4]); + qCDebug(lcIcc) << g << a << b << c << d; + gamma.m_type = QColorTrc::Type::Function; + gamma.m_fun = QColorTransferFunction(a, b, c, d, 0.0f, 0.0f, g); + break; + } + case 4: { + float g = fromFixedS1516(para->parameter[0]); + float a = fromFixedS1516(para->parameter[1]); + float b = fromFixedS1516(para->parameter[2]); + float c = fromFixedS1516(para->parameter[3]); + float d = fromFixedS1516(para->parameter[4]); + float e = fromFixedS1516(para->parameter[5]); + float f = fromFixedS1516(para->parameter[6]); + qCDebug(lcIcc) << g << a << b << c << d << e << f; + gamma.m_type = QColorTrc::Type::Function; + gamma.m_fun = QColorTransferFunction(a, b, c, d, e, f, g); + break; + } + default: + qCWarning(lcIcc) << "Unknown para type" << uint(para->curveType); + return false; + } + return true; + } + qCWarning(lcIcc) << "Invalid TRC data type"; + return false; +} + +bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace) +{ + if (data.size() < qsizetype(sizeof(ICCProfileHeader))) { + qCWarning(lcIcc) << "fromIccProfile: failed size sanity 1"; + return false; + } + const ICCProfileHeader *header = (const ICCProfileHeader *)data.constData(); + if (!isValidIccProfile(*header)) { + qCWarning(lcIcc) << "fromIccProfile: failed general sanity check"; + return false; + } + if (qsizetype(header->profileSize) > data.size()) { + qCWarning(lcIcc) << "fromIccProfile: failed size sanity 2"; + return false; + } + + // Read tag index + const TagTableEntry *tagTable = (const TagTableEntry *)(data.constData() + sizeof(ICCProfileHeader)); + const qsizetype offsetToData = sizeof(ICCProfileHeader) + header->tagCount * sizeof(TagTableEntry); + + QHash<Tag, quint32> tagIndex; + for (uint i = 0; i < header->tagCount; ++i) { + // Sanity check tag sizes and offsets: + if (qsizetype(tagTable[i].offset) < offsetToData) { + qCWarning(lcIcc) << "fromIccProfile: failed tag offset sanity 1"; + return false; + } + // Checked separately from (+ size) to handle overflow. + if (tagTable[i].offset > header->profileSize) { + qCWarning(lcIcc) << "fromIccProfile: failed tag offset sanity 2"; + return false; + } + if ((tagTable[i].offset + tagTable[i].size) > header->profileSize) { + qCWarning(lcIcc) << "fromIccProfile: failed tag offset + size sanity"; + return false; + } +// printf("'%4s' %d %d\n", (const char *)&tagTable[i].signature, +// quint32(tagTable[i].offset), +// quint32(tagTable[i].size)); + tagIndex.insert(Tag(quint32(tagTable[i].signature)), tagTable[i].offset); + } + // Check the profile is three-component matrix based (what we currently support): + if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) || + !tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) || + !tagIndex.contains(Tag::wtpt)) { + qCWarning(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based"; + return false; + } + + // Parse XYZ tags + const XYZTagData *rXyz = (const XYZTagData *)(data.constData() + tagIndex[Tag::rXYZ]); + const XYZTagData *gXyz = (const XYZTagData *)(data.constData() + tagIndex[Tag::gXYZ]); + const XYZTagData *bXyz = (const XYZTagData *)(data.constData() + tagIndex[Tag::bXYZ]); + const XYZTagData *wXyz = (const XYZTagData *)(data.constData() + tagIndex[Tag::wtpt]); + if (rXyz->type != quint32(Tag::XYZ_) || gXyz->type != quint32(Tag::XYZ_) || + wXyz->type != quint32(Tag::XYZ_) || wXyz->type != quint32(Tag::XYZ_)) { + qCWarning(lcIcc) << "fromIccProfile: Bad XYZ data type"; + return false; + } + QColorSpacePrivate *colorspaceDPtr = colorSpace->d_func(); + + colorspaceDPtr->toXyz.r = fromXyzData(rXyz); + colorspaceDPtr->toXyz.g = fromXyzData(gXyz); + colorspaceDPtr->toXyz.b = fromXyzData(bXyz); + QColorVector whitePoint = fromXyzData(wXyz); + colorspaceDPtr->whitePoint = whitePoint; + + colorspaceDPtr->gamut = QColorSpace::Gamut::Custom; + if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) { + qCDebug(lcIcc) << "fromIccProfile: sRGB gamut detected"; + colorspaceDPtr->gamut = QColorSpace::Gamut::SRgb; + } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) { + qCDebug(lcIcc) << "fromIccProfile: Adobe RGB gamut detected"; + colorspaceDPtr->gamut = QColorSpace::Gamut::AdobeRgb; + } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) { + qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 gamut detected"; + colorspaceDPtr->gamut = QColorSpace::Gamut::DciP3D65; + } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromBt2020()) { + qCDebug(lcIcc) << "fromIccProfile: BT.2020 gamut detected"; + colorspaceDPtr->gamut = QColorSpace::Gamut::Bt2020; + } + if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) { + qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB gamut detected"; + colorspaceDPtr->gamut = QColorSpace::Gamut::ProPhotoRgb; + } + // Reset the matrix to our canonical values: + if (colorspaceDPtr->gamut != QColorSpace::Gamut::Custom) + colorspaceDPtr->setToXyzMatrix(); + + // Parse TRC tags + const GenericTagData *rTrc; + const GenericTagData *gTrc; + const GenericTagData *bTrc; + if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) { + // Apple extension for parametric version of TRCs in ICCv2: + rTrc = (const GenericTagData *)(data.constData() + tagIndex[Tag::aarg]); + gTrc = (const GenericTagData *)(data.constData() + tagIndex[Tag::aagg]); + bTrc = (const GenericTagData *)(data.constData() + tagIndex[Tag::aabg]); + } else { + rTrc = (const GenericTagData *)(data.constData() + tagIndex[Tag::rTRC]); + gTrc = (const GenericTagData *)(data.constData() + tagIndex[Tag::gTRC]); + bTrc = (const GenericTagData *)(data.constData() + tagIndex[Tag::bTRC]); + } + + QColorTrc rCurve; + QColorTrc gCurve; + QColorTrc bCurve; + if (!parseTRC(rTrc, rCurve)) + return false; + if (!parseTRC(gTrc, gCurve)) + return false; + if (!parseTRC(bTrc, bCurve)) + return false; + if (rCurve == gCurve && gCurve == bCurve && rCurve.m_type == QColorTrc::Type::Function) { + if (rCurve.m_fun.isLinear()) { + qCDebug(lcIcc) << "fromIccProfile: Linear gamma detected"; + colorspaceDPtr->trc[0] = QColorTransferFunction(); + colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Linear; + colorspaceDPtr->gamma = 1.0f; + } else if (rCurve.m_fun.isGamma()) { + qCDebug(lcIcc) << "fromIccProfile: Simple gamma detected"; + colorspaceDPtr->trc[0] = QColorTransferFunction::fromGamma(rCurve.m_fun.m_g); + colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Gamma; + colorspaceDPtr->gamma = rCurve.m_fun.m_g; + } else if (rCurve.m_fun.isSRgb()) { + qCDebug(lcIcc) << "fromIccProfile: sRGB gamma detected"; + colorspaceDPtr->trc[0] = QColorTransferFunction::fromSRgb(); + colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::SRgb; + } else { + colorspaceDPtr->trc[0] = rCurve; + colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Custom; + } + + colorspaceDPtr->trc[1] = colorspaceDPtr->trc[0]; + colorspaceDPtr->trc[2] = colorspaceDPtr->trc[0]; + } else { + colorspaceDPtr->trc[0] = rCurve; + colorspaceDPtr->trc[1] = gCurve; + colorspaceDPtr->trc[2] = bCurve; + colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Custom; + } + + // FIXME: try to parse the description.. + + if (!colorspaceDPtr->identifyColorSpace()) + colorspaceDPtr->id = QColorSpace::Unknown; + else + qCDebug(lcIcc) << "fromIccProfile: Named colorspace detected: " << colorSpace->colorSpaceId(); + + colorspaceDPtr->iccProfile = data; + + return true; +} + +} // namespace QIcc + +QT_END_NAMESPACE diff --git a/src/gui/painting/qicc_p.h b/src/gui/painting/qicc_p.h new file mode 100644 index 0000000000..c3220391f4 --- /dev/null +++ b/src/gui/painting/qicc_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QICC_P_H +#define QICC_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 <QtCore/qbytearray.h> +#include <QtGui/qtguiglobal.h> + +QT_BEGIN_NAMESPACE + +class QColorSpace; + +namespace QIcc { + +Q_GUI_EXPORT bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace); +Q_GUI_EXPORT QByteArray toIccProfile(const QColorSpace &space); + +} + +QT_END_NAMESPACE + +#endif // QICC_P_H diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 8a5274bd37..0d7205b483 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -528,6 +528,7 @@ static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *des } } +#if QT_CONFIG(raster_64bit) static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest, int dw, int dh, int dow, int sow); @@ -728,6 +729,7 @@ static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, } } } +#endif static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, int dw, int dh, int dow, int sow); @@ -945,10 +947,13 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh) return QImage(); } +#if QT_CONFIG(raster_64bit) if (src.depth() > 32) qt_qimageScaleRgba64(scaleinfo, (QRgba64 *)buffer.scanLine(0), dw, dh, dw, src.bytesPerLine() / 8); - else if (src.hasAlphaChannel()) + else +#endif + if (src.hasAlphaChannel()) qt_qimageScaleAARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0), dw, dh, dw, src.bytesPerLine() / 4); else diff --git a/src/gui/painting/qmatrix.cpp b/src/gui/painting/qmatrix.cpp index 24b33243da..b1f01332b6 100644 --- a/src/gui/painting/qmatrix.cpp +++ b/src/gui/painting/qmatrix.cpp @@ -248,7 +248,7 @@ QMatrix::QMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy) /*! Constructs a matrix that is a copy of the given \a matrix. */ -QMatrix::QMatrix(const QMatrix &matrix) Q_DECL_NOTHROW +QMatrix::QMatrix(const QMatrix &matrix) noexcept : _m11(matrix._m11) , _m12(matrix._m12) , _m21(matrix._m21) @@ -989,7 +989,7 @@ bool QMatrix::operator==(const QMatrix &m) const Returns the hash value for \a key, using \a seed to seed the calculation. */ -uint qHash(const QMatrix &key, uint seed) Q_DECL_NOTHROW +uint qHash(const QMatrix &key, uint seed) noexcept { QtPrivate::QHashCombine hash; seed = hash(seed, key.m11()); @@ -1068,7 +1068,7 @@ QMatrix QMatrix::operator *(const QMatrix &m) const /*! Assigns the given \a matrix's values to this matrix. */ -QMatrix &QMatrix::operator=(const QMatrix &matrix) Q_DECL_NOTHROW +QMatrix &QMatrix::operator=(const QMatrix &matrix) noexcept { _m11 = matrix._m11; _m12 = matrix._m12; diff --git a/src/gui/painting/qmatrix.h b/src/gui/painting/qmatrix.h index d8a4fcfb1c..a167260ade 100644 --- a/src/gui/painting/qmatrix.h +++ b/src/gui/painting/qmatrix.h @@ -64,12 +64,12 @@ public: #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove; the compiler-generated ones are fine! - QMatrix &operator=(QMatrix &&other) Q_DECL_NOTHROW // = default + QMatrix &operator=(QMatrix &&other) noexcept // = default { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(QMatrix)); return *this; } - QMatrix &operator=(const QMatrix &) Q_DECL_NOTHROW; // = default - QMatrix(QMatrix &&other) Q_DECL_NOTHROW // = default + QMatrix &operator=(const QMatrix &) noexcept; // = default + QMatrix(QMatrix &&other) noexcept // = default { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(QMatrix)); } - QMatrix(const QMatrix &other) Q_DECL_NOTHROW; // = default + QMatrix(const QMatrix &other) noexcept; // = default #endif void setMatrix(qreal m11, qreal m12, qreal m21, qreal m22, @@ -140,7 +140,7 @@ 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; +Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QMatrix &key, uint seed = 0) noexcept; // mathematical semantics inline QPoint operator*(const QPoint &p, const QMatrix &m) diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp index b2d02182c3..2074f98069 100644 --- a/src/gui/painting/qoutlinemapper.cpp +++ b/src/gui/painting/qoutlinemapper.cpp @@ -42,6 +42,7 @@ #include "qbezier_p.h" #include "qmath.h" #include "qpainterpath_p.h" +#include "qscopedvaluerollback.h" #include <stdlib.h> @@ -354,7 +355,7 @@ void QOutlineMapper::clipElements(const QPointF *elements, // instead of going through convenience functionallity, but since // this part of code hardly every used, it shouldn't matter. - m_in_clip_elements = true; + QScopedValueRollback<bool> in_clip_elements(m_in_clip_elements, true); QPainterPath path; @@ -397,8 +398,6 @@ void QOutlineMapper::clipElements(const QPointF *elements, convertPath(clippedPath); m_transform = oldTransform; } - - m_in_clip_elements = false; } QT_END_NAMESPACE diff --git a/src/gui/painting/qoutlinemapper_p.h b/src/gui/painting/qoutlinemapper_p.h index 71999fbdee..04a68797c2 100644 --- a/src/gui/painting/qoutlinemapper_p.h +++ b/src/gui/painting/qoutlinemapper_p.h @@ -180,13 +180,13 @@ public: QT_FT_Outline *outline() { if (m_valid) return &m_outline; - return 0; + return nullptr; } QT_FT_Outline *convertPath(const QPainterPath &path); QT_FT_Outline *convertPath(const QVectorPath &path); - inline QPainterPath::ElementType *elementTypes() const { return m_element_types.size() == 0 ? 0 : m_element_types.data(); } + inline QPainterPath::ElementType *elementTypes() const { return m_element_types.size() == 0 ? nullptr : m_element_types.data(); } public: QDataBuffer<QPainterPath::ElementType> m_element_types; diff --git a/src/gui/painting/qpagelayout.h b/src/gui/painting/qpagelayout.h index b41689d33b..7ee0ce7a76 100644 --- a/src/gui/painting/qpagelayout.h +++ b/src/gui/painting/qpagelayout.h @@ -82,13 +82,11 @@ public: const QMarginsF &margins, Unit units = Point, const QMarginsF &minMargins = QMarginsF(0, 0, 0, 0)); QPageLayout(const QPageLayout &other); -#ifdef Q_COMPILER_RVALUE_REFS - QPageLayout &operator=(QPageLayout &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QPageLayout &operator=(QPageLayout &&other) noexcept { swap(other); return *this; } QPageLayout &operator=(const QPageLayout &other); ~QPageLayout(); - void swap(QPageLayout &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QPageLayout &other) noexcept { qSwap(d, other.d); } friend Q_GUI_EXPORT bool operator==(const QPageLayout &lhs, const QPageLayout &rhs); bool isEquivalentTo(const QPageLayout &other) const; diff --git a/src/gui/painting/qpagesize.h b/src/gui/painting/qpagesize.h index 82054824b4..133274760f 100644 --- a/src/gui/painting/qpagesize.h +++ b/src/gui/painting/qpagesize.h @@ -236,14 +236,12 @@ public: const QString &name = QString(), SizeMatchPolicy matchPolicy = FuzzyMatch); QPageSize(const QPageSize &other); -#ifdef Q_COMPILER_RVALUE_REFS - QPageSize &operator=(QPageSize &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QPageSize &operator=(QPageSize &&other) noexcept { swap(other); return *this; } QPageSize &operator=(const QPageSize &other); ~QPageSize(); - void swap(QPageSize &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QPageSize &other) noexcept { qSwap(d, other.d); } friend Q_GUI_EXPORT bool operator==(const QPageSize &lhs, const QPageSize &rhs); bool isEquivalentTo(const QPageSize &other) const; diff --git a/src/gui/painting/qpaintdevice.cpp b/src/gui/painting/qpaintdevice.cpp index faaa316085..0ddfba6ee9 100644 --- a/src/gui/painting/qpaintdevice.cpp +++ b/src/gui/painting/qpaintdevice.cpp @@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE -QPaintDevice::QPaintDevice() Q_DECL_NOEXCEPT +QPaintDevice::QPaintDevice() noexcept { reserved = 0; painters = 0; diff --git a/src/gui/painting/qpaintdevice.h b/src/gui/painting/qpaintdevice.h index 9458b4ba9a..5f8dad205d 100644 --- a/src/gui/painting/qpaintdevice.h +++ b/src/gui/painting/qpaintdevice.h @@ -90,7 +90,7 @@ public: static inline qreal devicePixelRatioFScale() { return 0x10000; } protected: - QPaintDevice() Q_DECL_NOEXCEPT; + QPaintDevice() noexcept; virtual int metric(PaintDeviceMetric metric) const; virtual void initPainter(QPainter *painter) const; virtual QPaintDevice *redirected(QPoint *offset) const; diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h index 8ac3fcff5c..40b9474165 100644 --- a/src/gui/painting/qpaintengine_p.h +++ b/src/gui/painting/qpaintengine_p.h @@ -65,7 +65,7 @@ class Q_GUI_EXPORT QPaintEnginePrivate { Q_DECLARE_PUBLIC(QPaintEngine) public: - QPaintEnginePrivate() : pdev(0), q_ptr(0), currentClipDevice(0), hasSystemTransform(0), + QPaintEnginePrivate() : pdev(nullptr), q_ptr(nullptr), currentClipDevice(nullptr), hasSystemTransform(0), hasSystemViewport(0) {} virtual ~QPaintEnginePrivate(); @@ -138,8 +138,8 @@ public: static QPaintEnginePrivate *get(QPaintEngine *paintEngine) { return paintEngine->d_func(); } - virtual QPaintEngine *aggregateEngine() { return 0; } - virtual Qt::HANDLE nativeHandle() { return 0; } + virtual QPaintEngine *aggregateEngine() { return nullptr; } + virtual Qt::HANDLE nativeHandle() { return nullptr; } }; QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 65319c0804..85ddff53db 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -555,35 +555,6 @@ bool QRasterPaintEngine::end() /*! \internal */ -void QRasterPaintEngine::releaseBuffer() -{ - Q_D(QRasterPaintEngine); - d->rasterBuffer.reset(new QRasterBuffer); -} - -/*! - \internal -*/ -QSize QRasterPaintEngine::size() const -{ - Q_D(const QRasterPaintEngine); - return QSize(d->rasterBuffer->width(), d->rasterBuffer->height()); -} - -/*! - \internal -*/ -#ifndef QT_NO_DEBUG -void QRasterPaintEngine::saveBuffer(const QString &s) const -{ - Q_D(const QRasterPaintEngine); - d->rasterBuffer->bufferImage().save(s, "PNG"); -} -#endif - -/*! - \internal -*/ void QRasterPaintEngine::updateMatrix(const QTransform &matrix) { QRasterPaintEngineState *s = state(); @@ -927,7 +898,7 @@ void QRasterPaintEngine::renderHintsChanged() QRasterPaintEngineState *s = state(); #ifdef QT_DEBUG_DRAW - qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints; + qDebug() << "QRasterPaintEngine::renderHintsChanged()" << Qt::hex << s->renderHints; #endif bool was_aa = s->flags.antialiased; @@ -1774,7 +1745,7 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush) QRectF rf = path.controlPointRect(); qDebug() << "QRasterPaintEngine::fill(): " << "size=" << path.elementCount() - << ", hints=" << hex << path.hints() + << ", hints=" << Qt::hex << path.hints() << rf << brush; #endif @@ -3845,11 +3816,6 @@ QImage::Format QRasterBuffer::prepare(QImage *image) return format; } -void QRasterBuffer::resetBuffer(int val) -{ - memset(m_buffer, val, m_height*bytes_per_line); -} - QClipData::QClipData(int height) { clipSpanHeight = height; @@ -4272,55 +4238,13 @@ static void qt_span_clip(int count, const QSpan *spans, void *userData) } } -#ifndef QT_NO_DEBUG -QImage QRasterBuffer::bufferImage() const -{ - QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied); - - for (int y = 0; y < m_height; ++y) { - uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y); - - for (int x=0; x<m_width; ++x) { - uint argb = span[x]; - image.setPixel(x, y, argb); - } - } - return image; -} -#endif - - -void QRasterBuffer::flushToARGBImage(QImage *target) const -{ - int w = qMin(m_width, target->width()); - int h = qMin(m_height, target->height()); - - for (int y=0; y<h; ++y) { - uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y); - QRgb *dest = (QRgb *) target->scanLine(y); - for (int x=0; x<w; ++x) { - QRgb pixel = sourceLine[x]; - int alpha = qAlpha(pixel); - if (!alpha) { - dest[x] = 0; - } else { - dest[x] = (alpha << 24) - | ((255*qRed(pixel)/alpha) << 16) - | ((255*qGreen(pixel)/alpha) << 8) - | ((255*qBlue(pixel)/alpha) << 0); - } - } - } -} - - class QGradientCache { public: struct CacheInfo : QSpanData::Pinnable { inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) : - stops(qMove(s)), opacity(op), interpolationMode(mode) {} + stops(std::move(s)), opacity(op), interpolationMode(mode) {} QRgba64 buffer64[GRADIENT_STOPTABLE_SIZE]; QRgb buffer32[GRADIENT_STOPTABLE_SIZE]; QGradientStops stops; @@ -4607,7 +4531,9 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha); gradient.colorTable32 = cacheInfo->buffer32; +#if QT_CONFIG(raster_64bit) gradient.colorTable64 = cacheInfo->buffer64; +#endif cachedGradient = std::move(cacheInfo); gradient.spread = g->spread(); @@ -4629,7 +4555,9 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha); gradient.colorTable32 = cacheInfo->buffer32; +#if QT_CONFIG(raster_64bit) gradient.colorTable64 = cacheInfo->buffer64; +#endif cachedGradient = std::move(cacheInfo); gradient.spread = g->spread(); @@ -4655,7 +4583,9 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha); gradient.colorTable32 = cacheInfo->buffer32; +#if QT_CONFIG(raster_64bit) gradient.colorTable64 = cacheInfo->buffer64; +#endif cachedGradient = std::move(cacheInfo); gradient.spread = QGradient::RepeatSpread; diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 881144d1c2..500e0fae54 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -208,15 +208,6 @@ public: ClipType clipType() const; QRect clipBoundingRect() const; - void releaseBuffer(); - - QSize size() const; - -#ifndef QT_NO_DEBUG - void saveBuffer(const QString &s) const; -#endif - - #ifdef Q_OS_WIN void setDC(HDC hdc); HDC getDC() const; @@ -435,27 +426,16 @@ inline void QClipData::appendSpans(const QSpan *s, int num) class QRasterBuffer { public: - QRasterBuffer() : m_width(0), m_height(0), m_buffer(0) { init(); } + QRasterBuffer() : m_width(0), m_height(0), m_buffer(nullptr) { init(); } ~QRasterBuffer(); void init(); QImage::Format prepare(QImage *image); - QImage::Format prepare(QPixmap *pix); - void prepare(int w, int h); - void prepareBuffer(int w, int h); - - void resetBuffer(int val=0); uchar *scanLine(int y) { Q_ASSERT(y>=0); Q_ASSERT(y<m_height); return m_buffer + y * bytes_per_line; } -#ifndef QT_NO_DEBUG - QImage bufferImage() const; -#endif - - void flushToARGBImage(QImage *image) const; - int width() const { return m_width; } int height() const { return m_height; } int bytesPerLine() const { return bytes_per_line; } diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 22d3fb3001..8314e8bc8a 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -140,7 +140,7 @@ QDebug Q_GUI_EXPORT &operator<<(QDebug &s, const QVectorPath &path) QDebugStateSaver saver(s); QRectF rf = path.controlPointRect(); s << "QVectorPath(size:" << path.elementCount() - << " hints:" << hex << path.hints() + << " hints:" << Qt::hex << path.hints() << rf << ')'; return s; } diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 930180e9fa..bd2bc4c9b3 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -54,6 +54,8 @@ #include <QtCore/qvarlengtharray.h> #include <QtGui/private/qtguiglobal_p.h> #include "QtGui/qbrush.h" +#include "QtGui/qcolorspace.h" +#include "QtGui/qcolortransform.h" #include "QtGui/qfont.h" #include "QtGui/qpen.h" #include "QtGui/qregion.h" @@ -191,9 +193,9 @@ class QPainterPrivate Q_DECLARE_PUBLIC(QPainter) public: QPainterPrivate(QPainter *painter) - : q_ptr(painter), d_ptrs(0), state(0), dummyState(0), txinv(0), inDestructor(false), d_ptrs_size(0), - refcount(1), device(0), original_device(0), helper_device(0), engine(0), emulationEngine(0), - extended(0) + : q_ptr(painter), d_ptrs(nullptr), state(nullptr), dummyState(nullptr), txinv(0), inDestructor(false), d_ptrs_size(0), + refcount(1), device(nullptr), original_device(nullptr), helper_device(nullptr), engine(nullptr), emulationEngine(nullptr), + extended(nullptr) { } diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 42f94d038f..956b7f5514 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -75,7 +75,7 @@ struct QPainterPathPrivateDeleter { static inline void cleanup(QPainterPathPrivate *d) { - // note - we must up-cast to QPainterPathData since QPainterPathPrivate + // note - we must downcast to QPainterPathData since QPainterPathPrivate // has a non-virtual destructor! if (d && !d->ref.deref()) delete static_cast<QPainterPathData *>(d); @@ -527,7 +527,7 @@ void QPainterPath::setElementPositionAt(int i, qreal x, qreal y) /*! Constructs an empty QPainterPath object. */ -QPainterPath::QPainterPath() Q_DECL_NOEXCEPT +QPainterPath::QPainterPath() noexcept : d_ptr(0) { } @@ -3576,10 +3576,10 @@ void QPainterPath::computeControlPointRect() const #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug s, const QPainterPath &p) { - s.nospace() << "QPainterPath: Element count=" << p.elementCount() << endl; + s.nospace() << "QPainterPath: Element count=" << p.elementCount() << Qt::endl; const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"}; for (int i=0; i<p.elementCount(); ++i) { - s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << endl; + s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << Qt::endl; } return s; diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h index a69a192767..ed5be667b7 100644 --- a/src/gui/painting/qpainterpath.h +++ b/src/gui/painting/qpainterpath.h @@ -88,17 +88,15 @@ public: inline bool operator!=(const Element &e) const { return !operator==(e); } }; - QPainterPath() Q_DECL_NOEXCEPT; + QPainterPath() noexcept; explicit QPainterPath(const QPointF &startPoint); QPainterPath(const QPainterPath &other); QPainterPath &operator=(const QPainterPath &other); -#ifdef Q_COMPILER_RVALUE_REFS - inline QPainterPath &operator=(QPainterPath &&other) Q_DECL_NOEXCEPT + inline QPainterPath &operator=(QPainterPath &&other) noexcept { qSwap(d_ptr, other.d_ptr); return *this; } -#endif ~QPainterPath(); - inline void swap(QPainterPath &other) Q_DECL_NOEXCEPT { d_ptr.swap(other.d_ptr); } + inline void swap(QPainterPath &other) noexcept { d_ptr.swap(other.d_ptr); } void clear(); void reserve(int size); diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h index a36c8005bc..98056483bc 100644 --- a/src/gui/painting/qpainterpath_p.h +++ b/src/gui/painting/qpainterpath_p.h @@ -168,7 +168,7 @@ public: fillRule(Qt::OddEvenFill), dirtyBounds(false), dirtyControlBounds(false), - pathConverter(0) + pathConverter(nullptr) { require_moveTo = false; convex = false; @@ -181,7 +181,7 @@ public: dirtyBounds(other.dirtyBounds), dirtyControlBounds(other.dirtyControlBounds), convex(other.convex), - pathConverter(0) + pathConverter(nullptr) { require_moveTo = false; elements = other.elements; diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h index c25a479807..9444a87b71 100644 --- a/src/gui/painting/qpathclipper_p.h +++ b/src/gui/painting/qpathclipper_p.h @@ -82,7 +82,7 @@ public: bool intersect(); bool contains(); - static bool pathToRect(const QPainterPath &path, QRectF *rect = 0); + static bool pathToRect(const QPainterPath &path, QRectF *rect = nullptr); static QPainterPath intersect(const QPainterPath &path, const QRectF &rect); private: @@ -394,7 +394,7 @@ inline const QPathSegments::Intersection *QPathSegments::intersectionAt(int inde { const int intersection = m_segments.at(index).intersection; if (intersection < 0) - return 0; + return nullptr; else return &m_intersections.at(intersection); } @@ -428,12 +428,12 @@ inline int QWingedEdge::edgeCount() const inline QPathEdge *QWingedEdge::edge(int edge) { - return edge < 0 ? 0 : &m_edges.at(edge); + return edge < 0 ? nullptr : &m_edges.at(edge); } inline const QPathEdge *QWingedEdge::edge(int edge) const { - return edge < 0 ? 0 : &m_edges.at(edge); + return edge < 0 ? nullptr : &m_edges.at(edge); } inline int QWingedEdge::vertexCount() const @@ -449,12 +449,12 @@ inline int QWingedEdge::addVertex(const QPointF &p) inline QPathVertex *QWingedEdge::vertex(int vertex) { - return vertex < 0 ? 0 : &m_vertices.at(vertex); + return vertex < 0 ? nullptr : &m_vertices.at(vertex); } inline const QPathVertex *QWingedEdge::vertex(int vertex) const { - return vertex < 0 ? 0 : &m_vertices.at(vertex); + return vertex < 0 ? nullptr : &m_vertices.at(vertex); } inline QPathEdge::Traversal QWingedEdge::flip(QPathEdge::Traversal traversal) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 6bdc82a8e9..25d488961c 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -1671,19 +1671,19 @@ int QPdfEnginePrivate::writeXmpMetaData() const QDateTime now = QDateTime::currentDateTime(); const QDate date = now.date(); const QTime time = now.time(); - - QString timeStr; - timeStr.sprintf("%d-%02d-%02dT%02d:%02d:%02d", date.year(), date.month(), date.day(), - time.hour(), time.minute(), time.second()); + const QString timeStr = + QString::asprintf("%d-%02d-%02dT%02d:%02d:%02d", + date.year(), date.month(), date.day(), + time.hour(), time.minute(), time.second()); const int offset = now.offsetFromUtc(); const int hours = (offset / 60) / 60; const int mins = (offset / 60) % 60; QString tzStr; if (offset < 0) - tzStr.sprintf("-%02d:%02d", -hours, -mins); + tzStr = QString::asprintf("-%02d:%02d", -hours, -mins); else if (offset > 0) - tzStr.sprintf("+%02d:%02d", hours , mins); + tzStr = QString::asprintf("+%02d:%02d", hours , mins); else tzStr = QLatin1String("Z"); diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp index 258939a763..7f18ce42be 100644 --- a/src/gui/painting/qpdfwriter.cpp +++ b/src/gui/painting/qpdfwriter.cpp @@ -379,6 +379,9 @@ int QPdfWriter::resolution() const */ #endif +#if QT_DEPRECATED_SINCE(5, 14) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED /*! \reimp @@ -404,6 +407,8 @@ void QPdfWriter::setPageSizeMM(const QSizeF &size) { setPageSize(QPageSize(size, QPageSize::Millimeter)); } +QT_WARNING_POP +#endif /*! \internal @@ -427,6 +432,9 @@ bool QPdfWriter::newPage() } +#if QT_DEPRECATED_SINCE(5, 14) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED /*! \reimp @@ -438,6 +446,8 @@ void QPdfWriter::setMargins(const Margins &m) { setPageMargins(QMarginsF(m.left, m.top, m.right, m.bottom), QPageLayout::Millimeter); } +QT_WARNING_POP +#endif QT_END_NAMESPACE diff --git a/src/gui/painting/qpdfwriter.h b/src/gui/painting/qpdfwriter.h index b260805b2b..668081e008 100644 --- a/src/gui/painting/qpdfwriter.h +++ b/src/gui/painting/qpdfwriter.h @@ -86,10 +86,14 @@ public: using QPagedPaintDevice::setPageSize; #endif +#if QT_DEPRECATED_SINCE(5, 14) + QT_DEPRECATED_X("Use setPageSize(QPageSize(id)) instead") void setPageSize(PageSize size) override; + QT_DEPRECATED_X("Use setPageSize(QPageSize(size, QPageSize::Millimeter)) instead") void setPageSizeMM(const QSizeF &size) override; - + QT_DEPRECATED_X("Use setPageMargins(QMarginsF(l, t, r, b), QPageLayout::Millimeter) instead") void setMargins(const Margins &m) override; +#endif protected: QPaintEngine *paintEngine() const override; diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index 778c770b82..58a1716037 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -322,7 +322,7 @@ QPen::QPen(const QBrush &brush, qreal width, Qt::PenStyle s, Qt::PenCapStyle c, Constructs a pen that is a copy of the given \a pen. */ -QPen::QPen(const QPen &p) Q_DECL_NOTHROW +QPen::QPen(const QPen &p) noexcept { d = p.d; if (d) @@ -381,7 +381,7 @@ void QPen::detach() this pen. */ -QPen &QPen::operator=(const QPen &p) Q_DECL_NOTHROW +QPen &QPen::operator=(const QPen &p) noexcept { QPen(p).swap(*this); return *this; diff --git a/src/gui/painting/qpen.h b/src/gui/painting/qpen.h index 03abfb3d7d..10b11d1d85 100644 --- a/src/gui/painting/qpen.h +++ b/src/gui/painting/qpen.h @@ -65,18 +65,16 @@ public: QPen(const QColor &color); QPen(const QBrush &brush, qreal width, Qt::PenStyle s = Qt::SolidLine, Qt::PenCapStyle c = Qt::SquareCap, Qt::PenJoinStyle j = Qt::BevelJoin); - QPen(const QPen &pen) Q_DECL_NOTHROW; + QPen(const QPen &pen) noexcept; ~QPen(); - QPen &operator=(const QPen &pen) Q_DECL_NOTHROW; -#ifdef Q_COMPILER_RVALUE_REFS - QPen(QPen &&other) Q_DECL_NOTHROW + QPen &operator=(const QPen &pen) noexcept; + QPen(QPen &&other) noexcept : d(other.d) { other.d = nullptr; } - QPen &operator=(QPen &&other) Q_DECL_NOTHROW + QPen &operator=(QPen &&other) noexcept { qSwap(d, other.d); return *this; } -#endif - void swap(QPen &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QPen &other) noexcept { qSwap(d, other.d); } Qt::PenStyle style() const; void setStyle(Qt::PenStyle); diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index de5ba964dc..414d2bf0de 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -85,7 +85,7 @@ public: }; Q_DECLARE_FLAGS(Flags, Flag) - explicit QPlatformTextureList(QObject *parent = 0); + explicit QPlatformTextureList(QObject *parent = nullptr); ~QPlatformTextureList(); int count() const; @@ -99,7 +99,7 @@ public: bool isLocked() const; void appendTexture(void *source, GLuint textureId, const QRect &geometry, - const QRect &clipRect = QRect(), Flags flags = 0); + const QRect &clipRect = QRect(), Flags flags = nullptr); void clear(); Q_SIGNALS: diff --git a/src/gui/painting/qpolygon.h b/src/gui/painting/qpolygon.h index 8e74a499fd..93fab55aa1 100644 --- a/src/gui/painting/qpolygon.h +++ b/src/gui/painting/qpolygon.h @@ -60,18 +60,14 @@ public: inline ~QPolygon() {} inline explicit QPolygon(int size); inline /*implicit*/ QPolygon(const QVector<QPoint> &v) : QVector<QPoint>(v) {} -#ifdef Q_COMPILER_RVALUE_REFS - /*implicit*/ QPolygon(QVector<QPoint> &&v) Q_DECL_NOTHROW : QVector<QPoint>(std::move(v)) {} -#endif + /*implicit*/ QPolygon(QVector<QPoint> &&v) noexcept : QVector<QPoint>(std::move(v)) {} QPolygon(const QRect &r, bool closed=false); QPolygon(int nPoints, const int *points); QPolygon(const QPolygon &other) : QVector<QPoint>(other) {} -#ifdef Q_COMPILER_RVALUE_REFS - QPolygon(QPolygon &&other) Q_DECL_NOTHROW : QVector<QPoint>(std::move(other)) {} - QPolygon &operator=(QPolygon &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QPolygon(QPolygon &&other) noexcept : QVector<QPoint>(std::move(other)) {} + QPolygon &operator=(QPolygon &&other) noexcept { swap(other); return *this; } QPolygon &operator=(const QPolygon &other) { QVector<QPoint>::operator=(other); return *this; } - void swap(QPolygon &other) Q_DECL_NOTHROW { QVector<QPoint>::swap(other); } // prevent QVector<QPoint><->QPolygon swaps + void swap(QPolygon &other) noexcept { QVector<QPoint>::swap(other); } // prevent QVector<QPoint><->QPolygon swaps operator QVariant() const; @@ -145,16 +141,12 @@ public: inline ~QPolygonF() {} inline explicit QPolygonF(int size); inline /*implicit*/ QPolygonF(const QVector<QPointF> &v) : QVector<QPointF>(v) {} -#ifdef Q_COMPILER_RVALUE_REFS - /* implicit */ QPolygonF(QVector<QPointF> &&v) Q_DECL_NOTHROW : QVector<QPointF>(std::move(v)) {} -#endif + /* implicit */ QPolygonF(QVector<QPointF> &&v) noexcept : QVector<QPointF>(std::move(v)) {} QPolygonF(const QRectF &r); /*implicit*/ QPolygonF(const QPolygon &a); inline QPolygonF(const QPolygonF &a) : QVector<QPointF>(a) {} -#ifdef Q_COMPILER_RVALUE_REFS - QPolygonF(QPolygonF &&other) Q_DECL_NOTHROW : QVector<QPointF>(std::move(other)) {} - QPolygonF &operator=(QPolygonF &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QPolygonF(QPolygonF &&other) noexcept : QVector<QPointF>(std::move(other)) {} + QPolygonF &operator=(QPolygonF &&other) noexcept { swap(other); return *this; } QPolygonF &operator=(const QPolygonF &other) { QVector<QPointF>::operator=(other); return *this; } inline void swap(QPolygonF &other) { QVector<QPointF>::swap(other); } // prevent QVector<QPointF><->QPolygonF swaps diff --git a/src/gui/painting/qrbtree_p.h b/src/gui/painting/qrbtree_p.h index d3ee23a91c..42e88889a1 100644 --- a/src/gui/painting/qrbtree_p.h +++ b/src/gui/painting/qrbtree_p.h @@ -60,7 +60,7 @@ struct QRBTree { struct Node { - inline Node() : parent(0), left(0), right(0), red(true) { } + inline Node() : parent(nullptr), left(nullptr), right(nullptr), red(true) { } inline ~Node() {if (left) delete left; if (right) delete right;} T data; Node *parent; @@ -69,7 +69,7 @@ struct QRBTree bool red; }; - inline QRBTree() : root(0), freeList(0) { } + inline QRBTree() : root(nullptr), freeList(nullptr) { } inline ~QRBTree(); inline void clear(); @@ -120,7 +120,7 @@ inline QRBTree<T>::~QRBTree() while (freeList) { // Avoid recursively calling the destructor, as this list may become large. Node *next = freeList->right; - freeList->right = 0; + freeList->right = nullptr; delete freeList; freeList = next; } @@ -131,7 +131,7 @@ inline void QRBTree<T>::clear() { if (root) delete root; - root = 0; + root = nullptr; } template <class T> @@ -359,7 +359,7 @@ void QRBTree<T>::detach(Node *node) // call this before removing a node. ref = child; if (child) child->parent = node->parent; - node->left = node->right = node->parent = 0; + node->left = node->right = node->parent = nullptr; } // 'node' must be black. rebalance will reduce the depth of black nodes by one in the sibling tree. @@ -513,7 +513,7 @@ inline void QRBTree<T>::deleteNode(Node *&node) detach(node); node->right = freeList; freeList = node; - node = 0; + node = nullptr; } template <class T> @@ -522,7 +522,7 @@ inline typename QRBTree<T>::Node *QRBTree<T>::newNode() if (freeList) { Node *node = freeList; freeList = freeList->right; - node->parent = node->left = node->right = 0; + node->parent = node->left = node->right = nullptr; node->red = true; return node; } diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 77718ce747..51eed962f0 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -1287,10 +1287,10 @@ struct QRegionPrivate { } } - const QRect *begin() const Q_DECL_NOTHROW + const QRect *begin() const noexcept { return numRects == 1 ? &extents : rects.data(); } // avoid vectorize() - const QRect *end() const Q_DECL_NOTHROW + const QRect *end() const noexcept { return begin() + numRects; } inline void append(const QRect *r); @@ -4321,7 +4321,7 @@ QRegion QRegion::xored(const QRegion &r) const } } -QRect QRegion::boundingRect() const Q_DECL_NOTHROW +QRect QRegion::boundingRect() const noexcept { if (isEmpty()) return QRect(); @@ -4379,12 +4379,12 @@ QVector<QRect> QRegion::rects() const } #endif -QRegion::const_iterator QRegion::begin() const Q_DECL_NOTHROW +QRegion::const_iterator QRegion::begin() const noexcept { return d->qt_rgn ? d->qt_rgn->begin() : nullptr; } -QRegion::const_iterator QRegion::end() const Q_DECL_NOTHROW +QRegion::const_iterator QRegion::end() const noexcept { return d->qt_rgn ? d->qt_rgn->end() : nullptr; } @@ -4421,7 +4421,7 @@ void QRegion::setRects(const QRect *rects, int num) } } -int QRegion::rectCount() const Q_DECL_NOTHROW +int QRegion::rectCount() const noexcept { return (d->qt_rgn ? d->qt_rgn->numRects : 0); } diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index 9fe6ed5675..54de916198 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -69,30 +69,28 @@ public: QRegion(const QRect &r, RegionType t = Rectangle); QRegion(const QPolygon &pa, Qt::FillRule fillRule = Qt::OddEvenFill); QRegion(const QRegion ®ion); - QRegion(QRegion &&other) Q_DECL_NOTHROW + QRegion(QRegion &&other) noexcept : d(other.d) { other.d = const_cast<QRegionData*>(&shared_empty); } QRegion(const QBitmap &bitmap); ~QRegion(); QRegion &operator=(const QRegion &); -#ifdef Q_COMPILER_RVALUE_REFS - inline QRegion &operator=(QRegion &&other) Q_DECL_NOEXCEPT + inline QRegion &operator=(QRegion &&other) noexcept { qSwap(d, other.d); return *this; } -#endif - inline void swap(QRegion &other) Q_DECL_NOEXCEPT { qSwap(d, other.d); } + inline void swap(QRegion &other) noexcept { qSwap(d, other.d); } bool isEmpty() const; bool isNull() const; typedef const QRect *const_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - const_iterator begin() const Q_DECL_NOTHROW; - const_iterator cbegin() const Q_DECL_NOTHROW { return begin(); } - const_iterator end() const Q_DECL_NOTHROW; - const_iterator cend() const Q_DECL_NOTHROW { return end(); } - const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return const_reverse_iterator(end()); } - const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return rbegin(); } - const_reverse_iterator rend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } - const_reverse_iterator crend() const Q_DECL_NOTHROW { return rend(); } + const_iterator begin() const noexcept; + const_iterator cbegin() const noexcept { return begin(); } + const_iterator end() const noexcept; + const_iterator cend() const noexcept { return end(); } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const noexcept { return rbegin(); } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const noexcept { return rend(); } bool contains(const QPoint &p) const; bool contains(const QRect &r) const; @@ -121,13 +119,13 @@ public: bool intersects(const QRegion &r) const; bool intersects(const QRect &r) const; - QRect boundingRect() const Q_DECL_NOTHROW; + QRect boundingRect() const noexcept; #if QT_DEPRECATED_SINCE(5, 11) QT_DEPRECATED_X("Use begin()/end() instead") QVector<QRect> rects() const; #endif void setRects(const QRect *rect, int num); - int rectCount() const Q_DECL_NOTHROW; + int rectCount() const noexcept; #ifdef Q_COMPILER_MANGLES_RETURN_TYPE // ### Qt 6: remove these, they're kept for MSVC compat const QRegion operator|(const QRegion &r) const; diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index 327190b678..5b6990e667 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -173,15 +173,12 @@ template <class Iterator> bool qt_stroke_side(Iterator *it, QStroker *stroker, bool capFirst, QLineF *startTangent); /******************************************************************************* - * QLineF::angle gives us the smalles angle between two lines. Here we - * want to identify the line's angle direction on the unit circle. + * QLineF::angleTo gives us the angle between two lines with respecting the direction. + * Here we want to identify the line's angle direction on the unit circle. */ static inline qreal adapted_angle_on_x(const QLineF &line) { - qreal angle = line.angle(QLineF(0, 0, 1, 0)); - if (line.dy() > 0) - angle = 360 - angle; - return angle; + return QLineF(0, 0, 1, 0).angleTo(line); } QStrokerOps::QStrokerOps() @@ -459,7 +456,7 @@ void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine QLineF prevLine(qt_fixed_to_real(m_back2X), qt_fixed_to_real(m_back2Y), qt_fixed_to_real(m_back1X), qt_fixed_to_real(m_back1Y)); QPointF isect; - QLineF::IntersectType type = prevLine.intersect(nextLine, &isect); + QLineF::IntersectionType type = prevLine.intersects(nextLine, &isect); if (join == FlatJoin) { QLineF shortCut(prevLine.p2(), nextLine.p1()); diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 99b04aaba6..c21f2cdda4 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -73,7 +73,7 @@ int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const if (path.isEmpty()) break; - images[numImages++] = qMove(img); + images[numImages++] = std::move(img); } else { bool found = false; for (int j = 0; j < numImages; ++j) { @@ -83,7 +83,7 @@ int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const } } if (!found) - images[numImages++] = qMove(img); + images[numImages++] = std::move(img); } } diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index 3da28872b1..1e83ab46d1 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -75,7 +75,7 @@ class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache { public: QTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix) - : QFontEngineGlyphCache(format, matrix), m_current_fontengine(0), + : QFontEngineGlyphCache(format, matrix), m_current_fontengine(nullptr), m_w(0), m_h(0), m_cx(0), m_cy(0), m_currentRowHeight(0) { } diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 816514a695..7696da7d45 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -265,7 +265,9 @@ QTransform::QTransform() , m_13(0), m_23(0), m_33(1) , m_type(TxNone) , m_dirty(TxNone) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) , d(nullptr) +#endif { } @@ -284,7 +286,9 @@ QTransform::QTransform(qreal h11, qreal h12, qreal h13, , m_13(h13), m_23(h23), m_33(h33) , m_type(TxNone) , m_dirty(TxProject) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) , d(nullptr) +#endif { } @@ -301,7 +305,9 @@ QTransform::QTransform(qreal h11, qreal h12, qreal h21, , m_13(0), m_23(0), m_33(1) , m_type(TxNone) , m_dirty(TxShear) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) , d(nullptr) +#endif { } @@ -317,7 +323,9 @@ QTransform::QTransform(const QMatrix &mtx) m_13(0), m_23(0), m_33(1) , m_type(TxNone) , m_dirty(TxShear) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) , d(nullptr) +#endif { } @@ -795,7 +803,7 @@ bool QTransform::operator==(const QTransform &o) const Returns the hash value for \a key, using \a seed to seed the calculation. */ -uint qHash(const QTransform &key, uint seed) Q_DECL_NOTHROW +uint qHash(const QTransform &key, uint seed) noexcept { QtPrivate::QHashCombine hash; seed = hash(seed, key.m11()); @@ -1021,7 +1029,7 @@ QTransform QTransform::operator*(const QTransform &m) const /*! Assigns the given \a matrix's values to this matrix. */ -QTransform & QTransform::operator=(const QTransform &matrix) Q_DECL_NOTHROW +QTransform & QTransform::operator=(const QTransform &matrix) noexcept { affine._m11 = matrix.affine._m11; affine._m12 = matrix.affine._m12; diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h index 1e322d435a..b220770144 100644 --- a/src/gui/painting/qtransform.h +++ b/src/gui/painting/qtransform.h @@ -77,13 +77,13 @@ public: #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove; the compiler-generated ones are fine! - QTransform &operator=(QTransform &&other) Q_DECL_NOTHROW // = default + QTransform &operator=(QTransform &&other) noexcept // = default { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(QTransform)); return *this; } - QTransform &operator=(const QTransform &) Q_DECL_NOTHROW; // = default - QTransform(QTransform &&other) Q_DECL_NOTHROW // = default + QTransform &operator=(const QTransform &) noexcept; // = default + QTransform(QTransform &&other) noexcept // = default : affine(Qt::Uninitialized) { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(QTransform)); } - QTransform(const QTransform &other) Q_DECL_NOTHROW // = default + QTransform(const QTransform &other) noexcept // = default : affine(Qt::Uninitialized) { memcpy(static_cast<void *>(this), static_cast<const void *>(&other), sizeof(QTransform)); } #endif @@ -176,7 +176,9 @@ private: , m_13(h13), m_23(h23), m_33(h33) , m_type(TxNone) , m_dirty(TxProject) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) , d(nullptr) +#endif { } inline QTransform(bool) @@ -184,7 +186,9 @@ private: , m_13(0), m_23(0), m_33(1) , m_type(TxNone) , m_dirty(TxNone) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) , d(nullptr) +#endif { } inline TransformationType inline_type() const; @@ -202,7 +206,7 @@ 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; +Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QTransform &key, uint seed = 0) noexcept; /******* inlines *****/ inline QTransform::TransformationType QTransform::inline_type() const diff --git a/src/gui/painting/qtriangulator_p.h b/src/gui/painting/qtriangulator_p.h index c9ae2571f4..177e5e66ed 100644 --- a/src/gui/painting/qtriangulator_p.h +++ b/src/gui/painting/qtriangulator_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE -class Q_GUI_EXPORT QVertexIndexVector +class QVertexIndexVector { public: enum Type { @@ -93,19 +93,6 @@ public: return indices16.size(); } - QVertexIndexVector() = default; - QVertexIndexVector(const QVertexIndexVector &other) = default; - inline QVertexIndexVector &operator = (const QVertexIndexVector &other) - { - if (t == UnsignedInt) - indices32 = other.indices32; - else - indices16 = other.indices16; - - t = other.t; - return *this; - } - private: Type t; @@ -113,23 +100,15 @@ private: QVector<quint16> indices16; }; -struct Q_GUI_EXPORT QTriangleSet +struct QTriangleSet { - inline QTriangleSet() { } - inline QTriangleSet(const QTriangleSet &other) : vertices(other.vertices), indices(other.indices) { } - QTriangleSet &operator = (const QTriangleSet &other) {vertices = other.vertices; indices = other.indices; return *this;} - // The vertices of a triangle are given by: (x[i[n]], y[i[n]]), (x[j[n]], y[j[n]]), (x[k[n]], y[k[n]]), n = 0, 1, ... QVector<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...] QVertexIndexVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...] }; -struct Q_GUI_EXPORT QPolylineSet +struct QPolylineSet { - inline QPolylineSet() { } - inline QPolylineSet(const QPolylineSet &other) : vertices(other.vertices), indices(other.indices) { } - QPolylineSet &operator = (const QPolylineSet &other) {vertices = other.vertices; indices = other.indices; return *this;} - QVector<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...] QVertexIndexVector indices; // End of polyline is marked with -1. }; diff --git a/src/gui/painting/qvectorpath_p.h b/src/gui/painting/qvectorpath_p.h index 1b649a5d2a..df5772d4cc 100644 --- a/src/gui/painting/qvectorpath_p.h +++ b/src/gui/painting/qvectorpath_p.h @@ -106,7 +106,7 @@ public: // ### Falcon: introduca a struct XY for points so lars is not so confused... QVectorPath(const qreal *points, int count, - const QPainterPath::ElementType *elements = 0, + const QPainterPath::ElementType *elements = nullptr, uint hints = ArbitraryShapeHint) : m_elements(elements), m_points(points), @@ -128,12 +128,12 @@ public: inline bool hasExplicitOpen() const { return m_hints & ExplicitOpen; } inline bool hasWindingFill() const { return m_hints & WindingFill; } - inline void makeCacheable() const { m_hints |= ShouldUseCacheHint; m_cache = 0; } + inline void makeCacheable() const { m_hints |= ShouldUseCacheHint; m_cache = nullptr; } inline uint hints() const { return m_hints; } inline const QPainterPath::ElementType *elements() const { return m_elements; } inline const qreal *points() const { return m_points; } - inline bool isEmpty() const { return m_points == 0; } + inline bool isEmpty() const { return m_points == nullptr; } inline int elementCount() const { return m_count; } inline const QPainterPath convertToPainterPath() const; @@ -165,7 +165,7 @@ public: return e; e = e->next; } - return 0; + return nullptr; } template <typename T> static inline bool isRect(const T *pts, int elementCount) { |