summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/XCONSORTIUM_LICENSE.txt43
-rw-r--r--src/gui/painting/qbackingstore.cpp5
-rw-r--r--src/gui/painting/qbezier.cpp32
-rw-r--r--src/gui/painting/qcolormatrix_p.h22
-rw-r--r--src/gui/painting/qcolorspace.cpp157
-rw-r--r--src/gui/painting/qcolorspace.h27
-rw-r--r--src/gui/painting/qcolorspace_p.h16
-rw-r--r--src/gui/painting/qcolortransferfunction_p.h4
-rw-r--r--src/gui/painting/qcolortransform.cpp12
-rw-r--r--src/gui/painting/qdrawhelper.cpp199
-rw-r--r--src/gui/painting/qdrawhelper_p.h2
-rw-r--r--src/gui/painting/qdrawhelper_ssse3.cpp45
-rw-r--r--src/gui/painting/qicc.cpp10
-rw-r--r--src/gui/painting/qicc_p.h4
-rw-r--r--src/gui/painting/qpagesize.cpp8
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp59
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h2
-rw-r--r--src/gui/painting/qpainter.cpp2
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp31
-rw-r--r--src/gui/painting/qplatformbackingstore.h3
-rw-r--r--src/gui/painting/qregion.cpp54
-rw-r--r--src/gui/painting/qrgba64_p.h2
-rw-r--r--src/gui/painting/qt_attribution.json15
23 files changed, 388 insertions, 366 deletions
diff --git a/src/gui/painting/XCONSORTIUM_LICENSE.txt b/src/gui/painting/XCONSORTIUM_LICENSE.txt
new file mode 100644
index 0000000000..5d98625787
--- /dev/null
+++ b/src/gui/painting/XCONSORTIUM_LICENSE.txt
@@ -0,0 +1,43 @@
+Copyright (c) 1987, 1988 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index 3240b83451..b0393aff95 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -95,6 +95,11 @@ public:
QBackingStore::QBackingStore(QWindow *window)
: d_ptr(new QBackingStorePrivate(window))
{
+ if (window->handle()) {
+ // Create platform backingstore up front if we have a platform window,
+ // otherwise delay the creation until absolutely necessary.
+ handle();
+ }
}
/*!
diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp
index 9861fffff3..7622262da9 100644
--- a/src/gui/painting/qbezier.cpp
+++ b/src/gui/painting/qbezier.cpp
@@ -106,10 +106,10 @@ void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold
int levels[10];
beziers[0] = *this;
levels[0] = 9;
- QBezier *b = beziers;
- int *lvl = levels;
+ int top = 0;
- while (b >= beziers) {
+ while (top >= 0) {
+ QBezier *b = &beziers[top];
// check if we can pop the top bezier curve from the stack
qreal y4y1 = b->y4 - b->y1;
qreal x4x1 = b->x4 - b->x1;
@@ -123,17 +123,15 @@ void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold
qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
l = 1.;
}
- if (d < bezier_flattening_threshold*l || *lvl == 0) {
+ if (d < bezier_flattening_threshold * l || levels[top] == 0) {
// good enough, we pop it off and add the endpoint
polygon->append(QPointF(b->x4, b->y4));
- --b;
- --lvl;
+ --top;
} else {
// split, second half of the polygon goes lower into the stack
std::tie(b[1], b[0]) = b->split();
- lvl[1] = --lvl[0];
- ++b;
- ++lvl;
+ levels[top + 1] = --levels[top];
+ ++top;
}
}
}
@@ -144,10 +142,10 @@ void QBezier::addToPolygon(QDataBuffer<QPointF> &polygon, qreal bezier_flattenin
int levels[10];
beziers[0] = *this;
levels[0] = 9;
- QBezier *b = beziers;
- int *lvl = levels;
+ int top = 0;
- while (b >= beziers) {
+ while (top >= 0) {
+ QBezier *b = &beziers[top];
// check if we can pop the top bezier curve from the stack
qreal y4y1 = b->y4 - b->y1;
qreal x4x1 = b->x4 - b->x1;
@@ -161,17 +159,15 @@ void QBezier::addToPolygon(QDataBuffer<QPointF> &polygon, qreal bezier_flattenin
qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
l = 1.;
}
- if (d < bezier_flattening_threshold*l || *lvl == 0) {
+ if (d < bezier_flattening_threshold * l || levels[top] == 0) {
// good enough, we pop it off and add the endpoint
polygon.add(QPointF(b->x4, b->y4));
- --b;
- --lvl;
+ --top;
} else {
// split, second half of the polygon goes lower into the stack
std::tie(b[1], b[0]) = b->split();
- lvl[1] = --lvl[0];
- ++b;
- ++lvl;
+ levels[top + 1] = --levels[top];
+ ++top;
}
}
}
diff --git a/src/gui/painting/qcolormatrix_p.h b/src/gui/painting/qcolormatrix_p.h
index 66db95df7e..edb2d32258 100644
--- a/src/gui/painting/qcolormatrix_p.h
+++ b/src/gui/painting/qcolormatrix_p.h
@@ -62,17 +62,16 @@ class QColorVector
{
public:
QColorVector() = default;
- Q_DECL_CONSTEXPR QColorVector(float x, float y, float z) : x(x), y(y), z(z), _unused(0.0f) { }
+ Q_DECL_CONSTEXPR QColorVector(float x, float y, float z) : x(x), y(y), z(z) { }
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;
+ float x = 0.0f; // X, x or red
+ float y = 0.0f; // Y, y or green
+ float z = 0.0f; // Z, Y or blue
+ float _unused = 0.0f;
friend inline bool operator==(const QColorVector &v1, const QColorVector &v2);
friend inline bool operator!=(const QColorVector &v1, const QColorVector &v2);
@@ -81,7 +80,6 @@ public:
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))
@@ -187,10 +185,6 @@ public:
{ 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 } };
@@ -226,12 +220,6 @@ public:
{ 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)
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 86d0c57cfe..937bb505c9 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -70,12 +70,6 @@ QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Primaries primaries)
bluePoint = QPointF(0.150, 0.060);
whitePoint = QColorVector::D65Chromaticity();
break;
- case QColorSpace::Primaries::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::Primaries::AdobeRgb:
redPoint = QPointF(0.640, 0.330);
greenPoint = QPointF(0.210, 0.710);
@@ -152,25 +146,13 @@ QColorMatrix QColorSpacePrimaries::toXyzMatrix() const
}
QColorSpacePrivate::QColorSpacePrivate()
- : id(QColorSpace::Unknown)
- , primaries(QColorSpace::Primaries::Custom)
- , transferFunction(QColorSpace::TransferFunction::Custom)
- , gamma(0.0f)
- , whitePoint(QColorVector::null())
- , toXyz(QColorMatrix::null())
{
}
-QColorSpacePrivate::QColorSpacePrivate(QColorSpace::ColorSpaceId colorSpaceId)
- : id(colorSpaceId)
- , gamma(0.0f)
+QColorSpacePrivate::QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace)
+ : namedColorSpace(namedColorSpace)
{
- switch (colorSpaceId) {
- case QColorSpace::Undefined:
- primaries = QColorSpace::Primaries::Custom;
- transferFunction = QColorSpace::TransferFunction::Custom;
- description = QStringLiteral("Undefined");
- break;
+ switch (namedColorSpace) {
case QColorSpace::SRgb:
primaries = QColorSpace::Primaries::SRgb;
transferFunction = QColorSpace::TransferFunction::SRgb;
@@ -197,14 +179,6 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::ColorSpaceId colorSpaceId)
transferFunction = QColorSpace::TransferFunction::ProPhotoRgb;
description = QStringLiteral("ProPhoto RGB");
break;
- case QColorSpace::Bt2020:
- primaries = QColorSpace::Primaries::Bt2020;
- transferFunction = QColorSpace::TransferFunction::Bt2020;
- description = QStringLiteral("BT.2020");
- break;
- case QColorSpace::Unknown:
- qWarning("Can not create an unknown color space");
- Q_FALLTHROUGH();
default:
Q_UNREACHABLE();
}
@@ -216,8 +190,7 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorS
, transferFunction(fun)
, gamma(gamma)
{
- if (!identifyColorSpace())
- id = QColorSpace::Unknown;
+ identifyColorSpace();
initialize();
}
@@ -235,71 +208,63 @@ QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
setTransferFunction();
}
-bool QColorSpacePrivate::identifyColorSpace()
+void QColorSpacePrivate::identifyColorSpace()
{
switch (primaries) {
case QColorSpace::Primaries::SRgb:
if (transferFunction == QColorSpace::TransferFunction::SRgb) {
- id = QColorSpace::SRgb;
+ namedColorSpace = QColorSpace::SRgb;
if (description.isEmpty())
description = QStringLiteral("sRGB");
- return true;
+ return;
}
if (transferFunction == QColorSpace::TransferFunction::Linear) {
- id = QColorSpace::SRgbLinear;
+ namedColorSpace = QColorSpace::SRgbLinear;
if (description.isEmpty())
description = QStringLiteral("Linear sRGB");
- return true;
+ return;
}
break;
case QColorSpace::Primaries::AdobeRgb:
if (transferFunction == QColorSpace::TransferFunction::Gamma) {
if (qAbs(gamma - 2.19921875f) < (1/1024.0f)) {
- id = QColorSpace::AdobeRgb;
+ namedColorSpace = QColorSpace::AdobeRgb;
if (description.isEmpty())
description = QStringLiteral("Adobe RGB");
- return true;
+ return;
}
}
break;
case QColorSpace::Primaries::DciP3D65:
if (transferFunction == QColorSpace::TransferFunction::SRgb) {
- id = QColorSpace::DisplayP3;
+ namedColorSpace = QColorSpace::DisplayP3;
if (description.isEmpty())
description = QStringLiteral("Display P3");
- return true;
+ return;
}
break;
case QColorSpace::Primaries::ProPhotoRgb:
if (transferFunction == QColorSpace::TransferFunction::ProPhotoRgb) {
- id = QColorSpace::ProPhotoRgb;
+ namedColorSpace = QColorSpace::ProPhotoRgb;
if (description.isEmpty())
description = QStringLiteral("ProPhoto RGB");
- return true;
+ return;
}
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;
+ namedColorSpace = QColorSpace::ProPhotoRgb;
if (description.isEmpty())
description = QStringLiteral("ProPhoto RGB");
- return true;
+ return;
}
}
break;
- case QColorSpace::Primaries::Bt2020:
- if (transferFunction == QColorSpace::TransferFunction::Bt2020) {
- id = QColorSpace::Bt2020;
- if (description.isEmpty())
- description = QStringLiteral("BT.2020");
- return true;
- }
- break;
default:
break;
}
- id = QColorSpace::Unknown;
- return false;
+
+ namedColorSpace = Unknown;
}
void QColorSpacePrivate::initialize()
@@ -311,7 +276,7 @@ void QColorSpacePrivate::initialize()
void QColorSpacePrivate::setToXyzMatrix()
{
if (primaries == QColorSpace::Primaries::Custom) {
- toXyz = QColorMatrix::null();
+ toXyz = QColorMatrix();
whitePoint = QColorVector::D50();
return;
}
@@ -345,12 +310,6 @@ void QColorSpacePrivate::setTransferFunction()
if (qFuzzyIsNull(gamma))
gamma = 1.8f;
break;
- case QColorSpace::TransferFunction::Bt2020:
- trc[0].m_type = QColorTrc::Type::Function;
- trc[0].m_fun = QColorTransferFunction::fromBt2020();
- if (qFuzzyIsNull(gamma))
- gamma = 1.961f;
- break;
case QColorSpace::TransferFunction::Custom:
break;
default:
@@ -410,12 +369,10 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
/*!
- \enum QColorSpace::ColorSpaceId
+ \enum QColorSpace::NamedColorSpace
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}.
@@ -427,8 +384,6 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
\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}
*/
/*!
@@ -441,7 +396,6 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
\value AdobeRgb The Adobe RGB primaries
\value DciP3D65 The DCI-P3 primaries with the D65 whitepoint
\value ProPhotoRgb The ProPhoto RGB primaries with the D50 whitepoint
- \value Bt2020 The BT.2020 primaries
*/
/*!
@@ -454,26 +408,28 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
\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.
+ Creates a new colorspace object that represents an undefined and invalid colorspace.
*/
-QColorSpace::QColorSpace(QColorSpace::ColorSpaceId colorSpaceId)
- : d_ptr(nullptr)
-{
- static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::Bt2020];
- // Unknown and undefined both returns the static undefined colorspace
- if (colorSpaceId > QColorSpace::Unknown) {
- if (!predefinedColorspacePrivates[colorSpaceId - 2]) {
- predefinedColorspacePrivates[colorSpaceId - 2] = new QColorSpacePrivate(colorSpaceId);
- predefinedColorspacePrivates[colorSpaceId - 2]->ref.ref();
- }
- d_ptr = predefinedColorspacePrivates[colorSpaceId - 2];
- d_ptr->ref.ref();
- Q_ASSERT(isValid());
+QColorSpace::QColorSpace()
+{
+}
+
+/*!
+ Creates a new colorspace object that represents a \a namedColorSpace.
+ */
+QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
+{
+ static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::ProPhotoRgb + 1];
+ if (!predefinedColorspacePrivates[namedColorSpace]) {
+ predefinedColorspacePrivates[namedColorSpace] = new QColorSpacePrivate(namedColorSpace);
+ predefinedColorspacePrivates[namedColorSpace]->ref.ref();
}
+ d_ptr = predefinedColorspacePrivates[namedColorSpace];
+ d_ptr->ref.ref();
+ Q_ASSERT(isValid());
}
/*!
@@ -545,17 +501,6 @@ QColorSpace &QColorSpace::operator=(const QColorSpace &colorSpace)
*/
/*!
- 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
-{
- if (Q_UNLIKELY(!d_ptr))
- return QColorSpace::Undefined;
- return d_ptr->id;
-}
-
-/*!
Returns the predefined primaries of the color space
or \c primaries::Custom if it doesn't match any of them.
*/
@@ -596,8 +541,6 @@ float QColorSpace::gamma() const noexcept
/*!
Sets the transfer function to \a transferFunction and \a gamma.
- \note This also changes colorSpaceId().
-
\sa transferFunction(), gamma(), withTransferFunction()
*/
void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunction, float gamma)
@@ -634,8 +577,6 @@ QColorSpace QColorSpace::withTransferFunction(QColorSpace::TransferFunction tran
/*!
Sets the primaries to those of the \a primariesId set.
- \note This also changes colorSpaceId().
-
\sa primaries()
*/
void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
@@ -655,8 +596,6 @@ void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
Set primaries to the chromaticities of \a whitePoint, \a redPoint, \a greenPoint
and \a bluePoint.
- \note This also changes colorSpaceId().
-
\sa primaries()
*/
void QColorSpace::setPrimaries(const QPointF &whitePoint, const QPointF &redPoint,
@@ -718,7 +657,6 @@ QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile)
if (QIcc::fromIccProfile(iccProfile, &colorSpace))
return colorSpace;
QColorSpacePrivate *d = QColorSpacePrivate::getWritable(colorSpace);
- d->id = QColorSpace::Undefined;
d->iccProfile = iccProfile;
return colorSpace;
}
@@ -728,7 +666,8 @@ QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile)
*/
bool QColorSpace::isValid() const noexcept
{
- return d_ptr && d_ptr->id != QColorSpace::Undefined && d_ptr->toXyz.isValid()
+ return d_ptr
+ && d_ptr->toXyz.isValid()
&& d_ptr->trc[0].isValid() && d_ptr->trc[1].isValid() && d_ptr->trc[2].isValid();
}
@@ -744,11 +683,17 @@ bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
if (!colorSpace1.d_ptr || !colorSpace2.d_ptr)
return false;
- if (colorSpace1.colorSpaceId() == QColorSpace::Undefined && colorSpace2.colorSpaceId() == QColorSpace::Undefined)
+ if (colorSpace1.d_ptr->namedColorSpace && colorSpace2.d_ptr->namedColorSpace)
+ return colorSpace1.d_ptr->namedColorSpace == colorSpace2.d_ptr->namedColorSpace;
+
+ const bool valid1 = colorSpace1.isValid();
+ const bool valid2 = colorSpace2.isValid();
+ if (!valid1 && !valid2)
return colorSpace1.d_ptr->iccProfile == colorSpace2.d_ptr->iccProfile;
+ else if (!valid1 || !valid2)
+ return false;
- if (colorSpace1.colorSpaceId() != QColorSpace::Unknown && colorSpace2.colorSpaceId() != QColorSpace::Unknown)
- return colorSpace1.colorSpaceId() == colorSpace2.colorSpaceId();
+ // At this point one or both color spaces are unknown but valid, and must be compared in detail instead
if (colorSpace1.primaries() != QColorSpace::Primaries::Custom && colorSpace2.primaries() != QColorSpace::Primaries::Custom) {
if (colorSpace1.primaries() != colorSpace2.primaries())
@@ -839,7 +784,9 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg << "QColorSpace(";
- dbg << colorSpace.colorSpaceId() << ", " << colorSpace.primaries() << ", " << colorSpace.transferFunction();
+ if (colorSpace.d_ptr->namedColorSpace)
+ dbg << colorSpace.d_ptr->namedColorSpace << ", ";
+ dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction();
dbg << ", gamma=" << colorSpace.gamma();
dbg << ')';
return dbg;
diff --git a/src/gui/painting/qcolorspace.h b/src/gui/painting/qcolorspace.h
index 880f0ad4cf..e6bc62d58a 100644
--- a/src/gui/painting/qcolorspace.h
+++ b/src/gui/painting/qcolorspace.h
@@ -54,24 +54,20 @@ class Q_GUI_EXPORT QColorSpace
{
Q_GADGET
public:
- enum ColorSpaceId {
- Undefined = 0,
- Unknown = 1,
- SRgb,
+ enum NamedColorSpace {
+ SRgb = 1,
SRgbLinear,
AdobeRgb,
DisplayP3,
- ProPhotoRgb,
- Bt2020,
+ ProPhotoRgb
};
- Q_ENUM(ColorSpaceId)
+ Q_ENUM(NamedColorSpace)
enum class Primaries {
Custom = 0,
SRgb,
AdobeRgb,
DciP3D65,
- ProPhotoRgb,
- Bt2020,
+ ProPhotoRgb
};
Q_ENUM(Primaries)
enum class TransferFunction {
@@ -79,12 +75,12 @@ public:
Linear,
Gamma,
SRgb,
- ProPhotoRgb,
- Bt2020,
+ ProPhotoRgb
};
Q_ENUM(TransferFunction)
- QColorSpace(ColorSpaceId colorSpaceId = Undefined);
+ QColorSpace();
+ QColorSpace(NamedColorSpace namedColorSpace);
QColorSpace(Primaries primaries, TransferFunction fun, float gamma = 0.0f);
QColorSpace(Primaries primaries, float gamma);
QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
@@ -108,7 +104,6 @@ public:
void swap(QColorSpace &colorSpace) noexcept
{ qSwap(d_ptr, colorSpace.d_ptr); }
- ColorSpaceId colorSpaceId() const noexcept;
Primaries primaries() const noexcept;
TransferFunction transferFunction() const noexcept;
float gamma() const noexcept;
@@ -133,7 +128,11 @@ public:
private:
Q_DECLARE_PRIVATE(QColorSpace)
- QColorSpacePrivate *d_ptr;
+ QColorSpacePrivate *d_ptr = nullptr;
+
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace);
+#endif
};
bool Q_GUI_EXPORT operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2);
diff --git a/src/gui/painting/qcolorspace_p.h b/src/gui/painting/qcolorspace_p.h
index 037111a0ae..e7add19ed3 100644
--- a/src/gui/painting/qcolorspace_p.h
+++ b/src/gui/painting/qcolorspace_p.h
@@ -62,7 +62,7 @@
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QColorSpacePrimaries
+class Q_AUTOTEST_EXPORT QColorSpacePrimaries
{
public:
QColorSpacePrimaries() = default;
@@ -90,7 +90,7 @@ class QColorSpacePrivate : public QSharedData
{
public:
QColorSpacePrivate();
- QColorSpacePrivate(QColorSpace::ColorSpaceId colorSpaceId);
+ QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace);
QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction fun, float gamma);
QColorSpacePrivate(const QColorSpacePrimaries &primaries, QColorSpace::TransferFunction fun, float gamma);
QColorSpacePrivate(const QColorSpacePrivate &other) = default;
@@ -118,13 +118,15 @@ public:
void initialize();
void setToXyzMatrix();
void setTransferFunction();
- bool identifyColorSpace();
+ void identifyColorSpace();
QColorTransform transformationToColorSpace(const QColorSpacePrivate *out) const;
- QColorSpace::ColorSpaceId id;
- QColorSpace::Primaries primaries;
- QColorSpace::TransferFunction transferFunction;
- float gamma;
+ static constexpr QColorSpace::NamedColorSpace Unknown = QColorSpace::NamedColorSpace(0);
+ QColorSpace::NamedColorSpace namedColorSpace = Unknown;
+
+ QColorSpace::Primaries primaries = QColorSpace::Primaries::Custom;
+ QColorSpace::TransferFunction transferFunction = QColorSpace::TransferFunction::Custom;
+ float gamma = 0.0f;
QColorVector whitePoint;
QColorTrc trc[3];
diff --git a/src/gui/painting/qcolortransferfunction_p.h b/src/gui/painting/qcolortransferfunction_p.h
index fd7cfa2b2b..0575dbd888 100644
--- a/src/gui/painting/qcolortransferfunction_p.h
+++ b/src/gui/painting/qcolortransferfunction_p.h
@@ -130,10 +130,6 @@ public:
{
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);
diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp
index 53fd1dfbaa..10ccefed74 100644
--- a/src/gui/painting/qcolortransform.cpp
+++ b/src/gui/painting/qcolortransform.cpp
@@ -612,6 +612,15 @@ static void storeOpaque(QRgba64 *dst, const QRgba64 *src, const QColorVector *bu
static constexpr qsizetype WorkBlockSize = 256;
+template <typename T, int Count = 1>
+class QUninitialized
+{
+public:
+ operator T*() { return reinterpret_cast<T *>(this); }
+private:
+ alignas(T) char data[sizeof(T) * Count];
+};
+
template<typename T>
void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, TransformFlags flags) const
{
@@ -623,7 +632,8 @@ void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, Transf
bool doApplyMatrix = (colorMatrix != QColorMatrix::identity());
- QColorVector buffer[WorkBlockSize];
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+
qsizetype i = 0;
while (i < count) {
const qsizetype len = qMin(count - i, WorkBlockSize);
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index c17bf2ddfd..e5f752b94e 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -669,8 +669,7 @@ static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
{
const uint *src = reinterpret_cast<const uint *>(s);
uint *dest = reinterpret_cast<uint *>(d);
- for (int i = 0; i < count; ++i)
- dest[i] = qRgbSwapRgb30(src[i]);
+ UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
}
template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB()
@@ -5659,44 +5658,63 @@ static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcL
{
if (coverage == 0) {
// nothing
- } else if (coverage == 255) {
- *dst = src;
- } else if (!colorProfile) {
- *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage);
+ } else if (coverage == 255 || !colorProfile) {
+ blend_pixel(*dst, src, coverage);
+ } else if (*dst < 0xff000000) {
+ // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
+ blend_pixel(*dst, src, coverage);
+ } else if (src >= 0xff000000) {
+ grayBlendPixel(dst, coverage, srcLinear, colorProfile);
} 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);
- }
+ // First do naive blend with text-color
+ QRgb s = *dst;
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s);
+ grayBlendPixel(dst, coverage, s64, colorProfile);
}
}
#if QT_CONFIG(raster_64bit)
+
+static inline void grayBlendPixel(QRgba64 &dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile)
+{
+ // Do a gammacorrected gray alphablend...
+ QRgba64 dstColor = dst;
+ if (colorProfile) {
+ if (dstColor.isOpaque())
+ dstColor = colorProfile->toLinear(dstColor);
+ else if (!dstColor.isTransparent())
+ dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
+ }
+
+ blend_pixel(dstColor, srcLinear, coverage);
+
+ if (colorProfile) {
+ if (dstColor.isOpaque())
+ dstColor = colorProfile->fromLinear(dstColor);
+ else if (!dstColor.isTransparent())
+ dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
+ }
+ dst = dstColor;
+}
+
static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
{
if (coverage == 0) {
// nothing
} else if (coverage == 255) {
- dest[x] = src;
+ blend_pixel(dest[x], src);
+ } else if (src.isOpaque()) {
+ grayBlendPixel(dest[x], coverage, srcLinear, colorProfile);
} else {
- QRgba64 dstColor = dest[x];
- if (colorProfile) {
- if (dstColor.isOpaque())
- dstColor = colorProfile->toLinear(dstColor);
- else if (!dstColor.isTransparent())
- dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
- }
-
- dstColor = interpolate255(srcLinear, coverage, dstColor, 255 - coverage);
- if (colorProfile) {
- if (dstColor.isOpaque())
- dstColor = colorProfile->fromLinear(dstColor);
- else if (!dstColor.isTransparent())
- dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
- }
- dest[x] = dstColor;
+ // First do naive blend with text-color
+ QRgba64 s = dest[x];
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ if (colorProfile)
+ s = colorProfile->toLinear(s);
+ grayBlendPixel(dest[x], coverage, s, colorProfile);
}
}
@@ -5715,12 +5733,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
alignas(8) QRgba64 buffer[BufferSize];
const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
@@ -5793,12 +5807,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
quint32 buffer[BufferSize];
const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
@@ -5873,7 +5883,7 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
int mapWidth, int mapHeight, int mapStride,
const QClipData *clip, bool useGammaCorrection)
{
- if (useGammaCorrection) {
+ if (useGammaCorrection || !color.isOpaque()) {
qt_alphamapblit_generic(rasterBuffer, x, y, color, map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
return;
}
@@ -5932,12 +5942,8 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
if (!clip) {
quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
@@ -6032,48 +6038,62 @@ static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha)
#endif
}
-#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)
+static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile)
{
if (coverage == 0xff000000) {
// nothing
- } else if (coverage == 0xffffffff) {
- dest[x] = src;
+ } else if (coverage == 0xffffffff && qAlpha(src) == 255) {
+ blend_pixel(*dst, src);
+ } else if (!colorProfile) {
+ *dst = rgbBlend(*dst, src, coverage);
+ } else if (*dst < 0xff000000) {
+ // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
+ blend_pixel(*dst, src, qRgbAvg(coverage));
+ } else if (srcLinear.isOpaque()) {
+ rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
} else {
- QRgba64 dstColor = dest[x];
- if (dstColor.isOpaque()) {
- if (colorProfile)
- dstColor = colorProfile->toLinear(dstColor);
- dstColor = rgbBlend(dstColor, srcLinear, coverage);
- if (colorProfile)
- dstColor = colorProfile->fromLinear(dstColor);
- dest[x] = dstColor;
- } else {
- // Do a gray alphablend.
- alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile);
- }
+ // First do naive blend with text-color
+ QRgb s = *dst;
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s);
+ rgbBlendPixel(dst, coverage, s64, colorProfile);
}
}
-#endif
-static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile)
+#if QT_CONFIG(raster_64bit)
+static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
+{
+ // Do a gammacorrected RGB alphablend...
+ const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(dst) : dst;
+
+ QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
+
+ dst = colorProfile ? colorProfile->fromLinear(blend) : blend;
+}
+
+static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
{
if (coverage == 0xff000000) {
// nothing
} else if (coverage == 0xffffffff) {
- *dst = src;
- } else if (*dst < 0xff000000) {
- // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
- const int a = qRgbAvg(coverage);
- *dst = INTERPOLATE_PIXEL_255(src, a, *dst, 255 - a);
- } else if (!colorProfile) {
- *dst = rgbBlend(*dst, src, coverage);
- } else {
- rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
+ blend_pixel(dest[x], src);
+ } else if (!dest[x].isOpaque()) {
+ // Do a gray alphablend.
+ alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile);
+ } else if (src.isOpaque()) {
+ rgbBlendPixel(dest[x], coverage, srcLinear, colorProfile);
+ } else {
+ // First do naive blend with text-color
+ QRgba64 s = dest[x];
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ if (colorProfile)
+ s = colorProfile->toLinear(s);
+ rgbBlendPixel(dest[x], coverage, s, colorProfile);
}
}
-#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,
@@ -6088,12 +6108,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
alignas(8) QRgba64 buffer[BufferSize];
const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
@@ -6165,12 +6181,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
quint32 buffer[BufferSize];
const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
@@ -6243,12 +6255,8 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
if (!clip) {
quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
@@ -6774,6 +6782,9 @@ static void qInitDrawhelperFunctions()
qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_ssse3;
+ extern void QT_FASTCALL rbSwap_888_ssse3(uchar *dst, const uchar *src, int count);
+ qPixelLayouts[QImage::Format_RGB888].rbSwap = rbSwap_888_ssse3;
+ qPixelLayouts[QImage::Format_BGR888].rbSwap = rbSwap_888_ssse3;
}
#endif // SSSE3
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 9c5d525722..dd42b96d79 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -671,6 +671,8 @@ static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src)
static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src, const int const_alpha)
{
+ if (const_alpha == 255)
+ return blend_pixel(dst, src);
if (src != 0) {
const quint32 s = BYTE_MUL(src, const_alpha);
dst = s + BYTE_MUL(dst, qAlpha(~s));
diff --git a/src/gui/painting/qdrawhelper_ssse3.cpp b/src/gui/painting/qdrawhelper_ssse3.cpp
index 35d61c3e6c..14d7047bb6 100644
--- a/src/gui/painting/qdrawhelper_ssse3.cpp
+++ b/src/gui/painting/qdrawhelper_ssse3.cpp
@@ -40,7 +40,7 @@
#include <private/qdrawhelper_x86_p.h>
-#ifdef QT_COMPILER_SUPPORTS_SSSE3
+#if defined(QT_COMPILER_SUPPORTS_SSSE3)
#include <private/qdrawingprimitive_sse2_p.h>
@@ -254,6 +254,49 @@ void qt_memfill24_ssse3(quint24 *dest, quint24 color, qsizetype count)
}
}
+void QT_FASTCALL rbSwap_888_ssse3(uchar *dst, const uchar *src, int count)
+{
+ int i = 0;
+
+ const static __m128i shuffleMask1 = _mm_setr_epi8(2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12, /*!!*/15);
+ const static __m128i shuffleMask2 = _mm_setr_epi8(0, /*!!*/1, 4, 3, 2, 7, 6, 5, 10, 9, 8, 13, 12, 11, /*!!*/14, 15);
+ const static __m128i shuffleMask3 = _mm_setr_epi8(/*!!*/0, 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13);
+
+ for (; i + 15 < count; i += 16) {
+ __m128i s1 = _mm_loadu_si128((const __m128i *)src);
+ __m128i s2 = _mm_loadu_si128((const __m128i *)(src + 16));
+ __m128i s3 = _mm_loadu_si128((const __m128i *)(src + 32));
+ s1 = _mm_shuffle_epi8(s1, shuffleMask1);
+ s2 = _mm_shuffle_epi8(s2, shuffleMask2);
+ s3 = _mm_shuffle_epi8(s3, shuffleMask3);
+ _mm_storeu_si128((__m128i *)dst, s1);
+ _mm_storeu_si128((__m128i *)(dst + 16), s2);
+ _mm_storeu_si128((__m128i *)(dst + 32), s3);
+
+ // Now fix the last four misplaced values
+ std::swap(dst[15], dst[17]);
+ std::swap(dst[30], dst[32]);
+
+ src += 48;
+ dst += 48;
+ }
+
+ if (src != dst) {
+ SIMD_EPILOGUE(i, count, 15) {
+ dst[0] = src[2];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ dst += 3;
+ src += 3;
+ }
+ } else {
+ SIMD_EPILOGUE(i, count, 15) {
+ std::swap(dst[0], dst[2]);
+ dst += 3;
+ }
+ }
+}
+
QT_END_NAMESPACE
#endif // QT_COMPILER_SUPPORTS_SSSE3
diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp
index 6cb7b57493..18f212f8e9 100644
--- a/src/gui/painting/qicc.cpp
+++ b/src/gui/painting/qicc.cpp
@@ -687,9 +687,6 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
} else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) {
qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected";
colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65;
- } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromBt2020()) {
- qCDebug(lcIcc) << "fromIccProfile: BT.2020 primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::Bt2020;
}
if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) {
qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected";
@@ -765,10 +762,9 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
qCDebug(lcIcc) << "fromIccProfile: Description" << colorspaceDPtr->description;
}
- if (!colorspaceDPtr->identifyColorSpace())
- colorspaceDPtr->id = QColorSpace::Unknown;
- else
- qCDebug(lcIcc) << "fromIccProfile: Named colorspace detected: " << colorSpace->colorSpaceId();
+ colorspaceDPtr->identifyColorSpace();
+ if (colorspaceDPtr->namedColorSpace)
+ qCDebug(lcIcc) << "fromIccProfile: Named colorspace detected: " << QColorSpace::NamedColorSpace(colorspaceDPtr->namedColorSpace);
colorspaceDPtr->iccProfile = data;
diff --git a/src/gui/painting/qicc_p.h b/src/gui/painting/qicc_p.h
index c3220391f4..2a4658b84b 100644
--- a/src/gui/painting/qicc_p.h
+++ b/src/gui/painting/qicc_p.h
@@ -60,8 +60,8 @@ class QColorSpace;
namespace QIcc {
-Q_GUI_EXPORT bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace);
-Q_GUI_EXPORT QByteArray toIccProfile(const QColorSpace &space);
+bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace);
+QByteArray toIccProfile(const QColorSpace &space);
}
diff --git a/src/gui/painting/qpagesize.cpp b/src/gui/painting/qpagesize.cpp
index a1c9f6e417..c98ca8a1fb 100644
--- a/src/gui/painting/qpagesize.cpp
+++ b/src/gui/painting/qpagesize.cpp
@@ -222,8 +222,6 @@ static const int qt_windowsConversion[][2] = {
{DMPAPER_PENV_10_ROTATED, DMPAPER_PENV_10} // Is = DMPAPER_LAST, use as loop terminator
};
-static const int windowsConversionCount = int(sizeof(qt_windowsConversion) / sizeof(qt_windowsConversion[0]));
-
// Standard sizes data
struct StandardPageSize {
QPageSize::PageSizeId id;
@@ -423,9 +421,9 @@ static QPageSize::PageSizeId qt_idForWindowsID(int windowsId, QSize *match = 0)
if (windowsId <= DMPAPER_NONE || windowsId > DMPAPER_LAST)
return QPageSize::Custom;
// Check if one of the unsupported values, convert to valid value if is
- for (int i = 0; i < windowsConversionCount; ++i) {
- if (qt_windowsConversion[i][0] == windowsId) {
- windowsId = qt_windowsConversion[i][1];
+ for (const auto &it : qt_windowsConversion) {
+ if (it[0] == windowsId) {
+ windowsId = it[1];
break;
}
}
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 5ab5514dd4..8c51981120 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -842,8 +842,8 @@ void QRasterPaintEngine::updateRasterState()
const QPainter::CompositionMode mode = s->composition_mode;
s->flags.fast_text = (s->penData.type == QSpanData::Solid)
&& s->intOpacity == 256
- && (mode == QPainter::CompositionMode_Source
- || (mode == QPainter::CompositionMode_SourceOver
+ && (mode == QPainter::CompositionMode_SourceOver
+ || (mode == QPainter::CompositionMode_Source
&& s->penData.solidColor.isOpaque()));
}
@@ -906,8 +906,11 @@ void QRasterPaintEngine::renderHintsChanged()
s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
#if QT_DEPRECATED_SINCE(5, 14)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
if (s->renderHints & QPainter::HighQualityAntialiasing)
s->flags.antialiased = true;
+QT_WARNING_POP
#endif
s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting);
@@ -2214,7 +2217,7 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
const QClipData *clip = d->clip();
QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
- if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img)) {
+ if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, img.rect())) {
if (!clip) {
d->blitImage(pt, img, d->deviceRect);
return;
@@ -2285,7 +2288,12 @@ namespace {
return NoRotation;
}
- inline bool isPixelAligned(const QRectF &rect) {
+ inline bool isPixelAligned(const QPointF &pt)
+ {
+ return QPointF(pt.toPoint()) == pt;
+ }
+ inline bool isPixelAligned(const QRectF &rect)
+ {
return QRectF(rect.toRect()) == rect;
}
}
@@ -2353,17 +2361,12 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
const QClipData *clip = d->clip();
- if (s->matrix.type() > QTransform::TxTranslate
+ if (s->matrix.type() == QTransform::TxRotate
&& !stretch_sr
&& (!clip || clip->hasRectClip)
&& s->intOpacity == 256
&& (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
- || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
- && d->rasterBuffer->format == img.format()
- && (d->rasterBuffer->format == QImage::Format_RGB16
- || d->rasterBuffer->format == QImage::Format_RGB32
- || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
- && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
+ || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source))
{
RotationType rotationType = qRotationType(s->matrix);
const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp;
@@ -2371,9 +2374,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) {
QRectF transformedTargetRect = s->matrix.mapRect(r);
- if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
- || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
- {
+ if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, transformedTargetRect.topRight(), sr)) {
QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
if (clippedTransformedTargetRect.isNull())
return;
@@ -2507,8 +2508,8 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
fillPath(path, &d->image_filler_xform);
s->matrix = m;
} else {
- if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img)) {
- QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
+ QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
+ if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, sr)) {
if (!clip) {
d->blitImage(pt, img, d->deviceRect, sr.toRect());
return;
@@ -2519,7 +2520,6 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
} else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
if (func) {
- QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
if (!clip) {
d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
return;
@@ -3754,12 +3754,22 @@ bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMod
&& !image.hasAlphaChannel()));
}
-bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image) const
+bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image, const QPointF &pt, const QRectF &sr) const
{
Q_Q(const QRasterPaintEngine);
+
+ if (!(mode == QPainter::CompositionMode_Source
+ || (mode == QPainter::CompositionMode_SourceOver
+ && !image.hasAlphaChannel())))
+ return false;
+
const QRasterPaintEngineState *s = q->state();
+ Q_ASSERT(s->matrix.type() <= QTransform::TxTranslate || s->matrix.type() == QTransform::TxRotate);
- if (!s->flags.fast_images || s->intOpacity != 256 || qt_depthForFormat(rasterBuffer->format) < 8)
+ if (s->intOpacity != 256
+ || image.depth() < 8
+ || ((s->renderHints & (QPainter::SmoothPixmapTransform | QPainter::Antialiasing))
+ && (!isPixelAligned(pt) || !isPixelAligned(sr))))
return false;
QImage::Format dFormat = rasterBuffer->format;
@@ -3767,18 +3777,13 @@ bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mo
// Formats must match or source format must be a subset of destination format
if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) {
if ((sFormat == QImage::Format_RGB32 && dFormat == QImage::Format_ARGB32)
- || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888))
+ || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888)
+ || (sFormat == QImage::Format_RGBX64 && dFormat == QImage::Format_RGBA64))
sFormat = dFormat;
else
sFormat = qt_maybeAlphaVersionWithSameDepth(sFormat); // this returns premul formats
}
- if (dFormat != sFormat)
- return false;
-
- return s->matrix.type() <= QTransform::TxTranslate
- && (mode == QPainter::CompositionMode_Source
- || (mode == QPainter::CompositionMode_SourceOver
- && !image.hasAlphaChannel()));
+ return (dFormat == sFormat);
}
QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index ec4a35087a..089aadc3f7 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -306,7 +306,7 @@ public:
void recalculateFastImages();
bool canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const;
- bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image) const;
+ bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image, const QPointF &pt, const QRectF &sr) const;
QPaintDevice *device;
QScopedPointer<QOutlineMapper> outlineMapper;
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 84b34e390b..3ce54c20be 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -1716,8 +1716,8 @@ void QPainter::restore()
static inline void qt_cleanup_painter_state(QPainterPrivate *d)
{
+ qDeleteAll(d->states);
d->states.clear();
- delete d->state;
d->state = 0;
d->engine = 0;
d->device = 0;
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index c71d82546a..45e90bd99b 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -338,7 +338,16 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
}
}
- if (!d_ptr->context->makeCurrent(window)) {
+ bool current = d_ptr->context->makeCurrent(window);
+
+ if (!current && !d_ptr->context->isValid()) {
+ delete d_ptr->blitter;
+ d_ptr->blitter = nullptr;
+ d_ptr->textureId = 0;
+ current = d_ptr->context->create() && d_ptr->context->makeCurrent(window);
+ }
+
+ if (!current) {
qCWarning(lcQpaBackingStore, "composeAndFlush: makeCurrent() failed");
return;
}
@@ -446,14 +455,22 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
d_ptr->blitter->setRedBlueSwizzle(false);
}
- // There is no way to tell if the OpenGL-rendered content is premultiplied or not.
- // For compatibility, assume that it is not, and use normal alpha blend always.
- if (d_ptr->premultiplied)
- funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
-
// Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
+ bool blendIsPremultiplied = d_ptr->premultiplied;
for (int i = 0; i < textures->count(); ++i) {
- if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
+ const QPlatformTextureList::Flags flags = textures->flags(i);
+ if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending)) {
+ if (!blendIsPremultiplied) {
+ funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ blendIsPremultiplied = true;
+ }
+ } else {
+ if (blendIsPremultiplied) {
+ funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ blendIsPremultiplied = false;
+ }
+ }
+ if (flags.testFlag(QPlatformTextureList::StacksOnTop))
blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset, canUseSrgb);
}
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index 414d2bf0de..4f08b0092f 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -81,7 +81,8 @@ class Q_GUI_EXPORT QPlatformTextureList : public QObject
public:
enum Flag {
StacksOnTop = 0x01,
- TextureIsSrgb = 0x02
+ TextureIsSrgb = 0x02,
+ NeedsPremultipliedAlphaBlending = 0x04
};
Q_DECLARE_FLAGS(Flags, Flag)
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 51eed962f0..82f5be2b65 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -88,60 +88,6 @@ QT_BEGIN_NAMESPACE
Example of using complex regions:
\snippet code/src_gui_painting_qregion.cpp 0
- \section1 Additional License Information
-
- On Embedded Linux and X11 platforms, parts of this class rely on
- code obtained under the following licenses:
-
- \legalese
- Copyright (c) 1987 X Consortium
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- Except as contained in this notice, the name of the X Consortium shall not be
- used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization from the X Consortium.
- \endlegalese
-
- \br
-
- \legalese
- Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of Digital not be
- used in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
-
- DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- SOFTWARE.
- \endlegalese
-
\sa QPainter::setClipRegion(), QPainter::setClipRect(), QPainterPath
*/
diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h
index ca879de27c..d145dbfbea 100644
--- a/src/gui/painting/qrgba64_p.h
+++ b/src/gui/painting/qrgba64_p.h
@@ -284,6 +284,8 @@ static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src)
static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src, const int const_alpha)
{
+ if (const_alpha == 255)
+ return blend_pixel(dst, src);
if (!src.isTransparent()) {
src = multiplyAlpha255(src, const_alpha);
dst = src + multiplyAlpha65535(dst, 65535 - src.alpha());
diff --git a/src/gui/painting/qt_attribution.json b/src/gui/painting/qt_attribution.json
index 9d3debc1b9..7b16e8c211 100644
--- a/src/gui/painting/qt_attribution.json
+++ b/src/gui/painting/qt_attribution.json
@@ -41,5 +41,20 @@
"LicenseId": "MIT",
"LicenseFile": "WEBGRADIENTS_LICENSE.txt",
"Copyright": "Copyright (c) 2017 itmeo"
+ },
+ {
+ "Id": "xserverhelper",
+ "Name": "X Server helper",
+ "QDocModule": "qtgui",
+ "QtUsage": "Used in Qt GUI (QRegion).",
+ "Files": "qregion.cpp",
+
+ "Description": "Code from X11's region.h, Region.c, poly.h, and PolyReg.c",
+ "Homepage": "https://www.x.org/",
+ "License": "X11 License and Historical Permission Notice and Disclaimer",
+ "LicenseId": "X11 AND HPND",
+ "LicenseFile": "XCONSORTIUM_LICENSE.txt",
+ "Copyright": "Copyright (c) 1987, 1988 X Consortium
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts."
}
]