diff options
author | Allan Sandfeld Jensen <[email protected]> | 2020-12-14 17:48:57 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <[email protected]> | 2021-01-25 17:21:54 +0100 |
commit | fdc7eb80dd5753bc1fc145dc9bd0689cd65e251d (patch) | |
tree | f8f80675b1187cb899c2bab90f3d53f950ca9108 | |
parent | 4e2a94236998cd05753167953d9167793baf9942 (diff) |
Add QPlatformScreen::colorSpace()
Added for macOS and X11 screens
Task-number: QTBUG-90535
Change-Id: Ifafe7a07ee2abc3c42cd12785db2d7329878375b
Reviewed-by: Tor Arne Vestbø <[email protected]>
-rw-r--r-- | src/gui/kernel/qplatformscreen.h | 2 | ||||
-rw-r--r-- | src/gui/util/qedidparser.cpp | 84 | ||||
-rw-r--r-- | src/gui/util/qedidparser_p.h | 11 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoascreen.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoascreen.mm | 5 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbatom.cpp | 1 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbatom.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 34 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.h | 2 |
9 files changed, 142 insertions, 1 deletions
diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h index 0045e9c40d8..4e1ea4b3a9a 100644 --- a/src/gui/kernel/qplatformscreen.h +++ b/src/gui/kernel/qplatformscreen.h @@ -57,6 +57,7 @@ #include <QtCore/qrect.h> #include <QtCore/qobject.h> +#include <QtGui/qcolorspace.h> #include <QtGui/qcursor.h> #include <QtGui/qimage.h> #include <QtGui/qwindowdefs.h> @@ -114,6 +115,7 @@ public: virtual int depth() const = 0; virtual QImage::Format format() const = 0; + virtual QColorSpace colorSpace() const { return QColorSpace::SRgb; } virtual QSizeF physicalSize() const; virtual QDpi logicalDpi() const; diff --git a/src/gui/util/qedidparser.cpp b/src/gui/util/qedidparser.cpp index 7ca514e7c6b..553ca208071 100644 --- a/src/gui/util/qedidparser.cpp +++ b/src/gui/util/qedidparser.cpp @@ -52,6 +52,9 @@ #define EDID_OFFSET_SERIAL 0x0c #define EDID_PHYSICAL_WIDTH 0x15 #define EDID_OFFSET_PHYSICAL_HEIGHT 0x16 +#define EDID_TRANSFER_FUNCTION 0x17 +#define EDID_FEATURE_SUPPORT 0x18 +#define EDID_CHROMATICITIES_BLOCK 0x19 QT_BEGIN_NAMESPACE @@ -152,6 +155,87 @@ bool QEdidParser::parse(const QByteArray &blob) // Physical size physicalSize = QSizeF(data[EDID_PHYSICAL_WIDTH], data[EDID_OFFSET_PHYSICAL_HEIGHT]) * 10; + // Gamma and transfer function + const uint igamma = data[EDID_TRANSFER_FUNCTION]; + if (igamma != 0xff) { + gamma = 1.0 + (igamma / 100.0f); + useTables = false; + } else { + gamma = 0.0; // Defined in DI-EXT + useTables = true; + } + sRgb = data[EDID_FEATURE_SUPPORT] & 0x04; + + // Chromaticities + int rx = (data[EDID_CHROMATICITIES_BLOCK] >> 6) & 0x03; + int ry = (data[EDID_CHROMATICITIES_BLOCK] >> 4) & 0x03; + int gx = (data[EDID_CHROMATICITIES_BLOCK] >> 2) & 0x03; + int gy = (data[EDID_CHROMATICITIES_BLOCK] >> 0) & 0x03; + int bx = (data[EDID_CHROMATICITIES_BLOCK + 1] >> 6) & 0x03; + int by = (data[EDID_CHROMATICITIES_BLOCK + 1] >> 4) & 0x03; + int wx = (data[EDID_CHROMATICITIES_BLOCK + 1] >> 2) & 0x03; + int wy = (data[EDID_CHROMATICITIES_BLOCK + 1] >> 0) & 0x03; + rx |= data[EDID_CHROMATICITIES_BLOCK + 2] << 2; + ry |= data[EDID_CHROMATICITIES_BLOCK + 3] << 2; + gx |= data[EDID_CHROMATICITIES_BLOCK + 4] << 2; + gy |= data[EDID_CHROMATICITIES_BLOCK + 5] << 2; + bx |= data[EDID_CHROMATICITIES_BLOCK + 6] << 2; + by |= data[EDID_CHROMATICITIES_BLOCK + 7] << 2; + wx |= data[EDID_CHROMATICITIES_BLOCK + 8] << 2; + wy |= data[EDID_CHROMATICITIES_BLOCK + 9] << 2; + + redChromaticity.setX(rx * (1.0f / 1024.0f)); + redChromaticity.setY(ry * (1.0f / 1024.0f)); + greenChromaticity.setX(gx * (1.0f / 1024.0f)); + greenChromaticity.setY(gy * (1.0f / 1024.0f)); + blueChromaticity.setX(bx * (1.0f / 1024.0f)); + blueChromaticity.setY(by * (1.0f / 1024.0f)); + whiteChromaticity.setX(wx * (1.0f / 1024.0f)); + whiteChromaticity.setY(wy * (1.0f / 1024.0f)); + + // Find extensions + for (uint i = 1; i < length / 128; ++i) { + uint extensionId = data[i * 128]; + if (extensionId == 0x40) { // DI-EXT + // 0x0E (sub-pixel layout) + // 0x20->0x22 (bits per color) + // 0x51->0x7e Transfer characteristics + const uchar desc = data[i * 128 + 0x51]; + const uchar len = desc & 0x3f; + if ((desc & 0xc0) == 0x40) { + if (len > 45) + return false; + QList<uint16_t> whiteTRC; + whiteTRC.reserve(len + 1); + for (uint j = 0; j < len; ++j) + whiteTRC[j] = data[0x52 + j] * 0x101; + whiteTRC[len] = 0xffff; + tables.append(whiteTRC); + } else if ((desc & 0xc0) == 0x80) { + if (len > 15) + return false; + QList<uint16_t> redTRC; + QList<uint16_t> greenTRC; + QList<uint16_t> blueTRC; + blueTRC.reserve(len + 1); + greenTRC.reserve(len + 1); + redTRC.reserve(len + 1); + for (uint j = 0; j < len; ++j) + blueTRC[j] = data[0x52 + j] * 0x101; + blueTRC[len] = 0xffff; + for (uint j = 0; j < len; ++j) + greenTRC[j] = data[0x61 + j] * 0x101; + greenTRC[len] = 0xffff; + for (uint j = 0; j < len; ++j) + redTRC[j] = data[0x70 + j] * 0x101; + redTRC[len] = 0xffff; + tables.append(redTRC); + tables.append(greenTRC); + tables.append(blueTRC); + } + } + } + return true; } diff --git a/src/gui/util/qedidparser_p.h b/src/gui/util/qedidparser_p.h index 363ab251af2..14c736f4cc0 100644 --- a/src/gui/util/qedidparser_p.h +++ b/src/gui/util/qedidparser_p.h @@ -40,8 +40,9 @@ #ifndef QEDIDPARSER_P_H #define QEDIDPARSER_P_H -#include <QtCore/QSize> #include <QtCore/QMap> +#include <QtCore/QPointF> +#include <QtCore/QSize> // // W A R N I N G @@ -72,6 +73,14 @@ public: QString model; QString serialNumber; QSizeF physicalSize; + qreal gamma; + QPointF redChromaticity; + QPointF greenChromaticity; + QPointF blueChromaticity; + QPointF whiteChromaticity; + QList<QList<uint16_t>> tables; + bool sRgb; + bool useTables; private: QMap<QString, QString> m_vendorCache; diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h index ffbb67b677a..b109c24f639 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.h +++ b/src/plugins/platforms/cocoa/qcocoascreen.h @@ -66,6 +66,7 @@ public: QRect availableGeometry() const override { return m_availableGeometry; } int depth() const override { return m_depth; } QImage::Format format() const override { return m_format; } + QColorSpace colorSpace() const override { return m_colorSpace; } qreal devicePixelRatio() const override { return m_devicePixelRatio; } QSizeF physicalSize() const override { return m_physicalSize; } QDpi logicalDpi() const override { return m_logicalDpi; } @@ -122,6 +123,7 @@ private: int m_depth = 0; QString m_name; QImage::Format m_format; + QColorSpace m_colorSpace; QSizeF m_physicalSize; QCocoaCursor *m_cursor; qreal m_devicePixelRatio = 0; diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index 70d02d1a0d7..77de7511021 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -330,6 +330,11 @@ void QCocoaScreen::update(CGDirectDisplayID displayId) m_format = QImage::Format_RGB32; m_depth = NSBitsPerPixelFromDepth(nsScreen.depth); + m_colorSpace = QColorSpace::fromIccProfile(QByteArray::fromNSData(nsScreen.colorSpace.ICCProfileData)); + if (!m_colorSpace.isValid()) { + qWarning() << "macOS generated a color-profile Qt couldn't parse. This shouldn't happen."; + m_colorSpace = QColorSpace::SRgb; + } CGSize size = CGDisplayScreenSize(m_displayId); m_physicalSize = QSizeF(size.width, size.height); diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp index 780816605ad..60da23cfac3 100644 --- a/src/plugins/platforms/xcb/qxcbatom.cpp +++ b/src/plugins/platforms/xcb/qxcbatom.cpp @@ -234,6 +234,7 @@ static const char *xcb_atomnames = { "EDID\0" "EDID_DATA\0" "XFree86_DDC_EDID1_RAWDATA\0" + "_ICC_PROFILE\0" // \0\0 terminates loop. }; diff --git a/src/plugins/platforms/xcb/qxcbatom.h b/src/plugins/platforms/xcb/qxcbatom.h index 9cf93ec314a..c9e5c0fd25d 100644 --- a/src/plugins/platforms/xcb/qxcbatom.h +++ b/src/plugins/platforms/xcb/qxcbatom.h @@ -240,6 +240,8 @@ public: EDID_DATA, XFree86_DDC_EDID1_RAWDATA, + _ICC_PROFILE, + NAtoms }; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 9f20df9b356..3c57ffc7b08 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -547,6 +547,17 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe m_cursor = new QXcbCursor(connection, this); + { + // Read colord ICC data (from GNOME settings) + auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), + false, screen()->root, + connection->atom(QXcbAtom::_ICC_PROFILE), + XCB_ATOM_CARDINAL, 0, 8192); + if (reply->format == 8 && reply->type == XCB_ATOM_CARDINAL) { + QByteArray data(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), reply->value_len); + m_colorSpace = QColorSpace::fromIccProfile(data); + } + } if (connection->hasXRandr()) { // Parse EDID QByteArray edid = getEdid(); if (m_edid.parse(edid)) { @@ -558,6 +569,27 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe m_edid.model.toLatin1().constData(), m_edid.serialNumber.toLatin1().constData(), m_edid.physicalSize.width(), m_edid.physicalSize.height()); + if (!m_colorSpace.isValid()) { + if (m_edid.sRgb) + m_colorSpace = QColorSpace::SRgb; + else { + if (!m_edid.useTables) { + m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity, + m_edid.greenChromaticity, m_edid.blueChromaticity, + QColorSpace::TransferFunction::Gamma, m_edid.gamma); + } else { + if (m_edid.tables.length() == 1) { + m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity, + m_edid.greenChromaticity, m_edid.blueChromaticity, + m_edid.tables[0]); + } else if (m_edid.tables.length() == 3) { + m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity, + m_edid.greenChromaticity, m_edid.blueChromaticity, + m_edid.tables[0], m_edid.tables[1], m_edid.tables[2]); + } + } + } + } } else { // This property is defined by the xrandr spec. Parsing failure indicates a valid error, // but keep this as debug, for details see 4f515815efc318ddc909a0399b71b8a684962f38. @@ -565,6 +597,8 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe "edid data: " << edid; } } + if (!m_colorSpace.isValid()) + m_colorSpace = QColorSpace::SRgb; } QXcbScreen::~QXcbScreen() diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index aabf227a099..9ca68d1ecad 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -160,6 +160,7 @@ public: QRect availableGeometry() const override; int depth() const override { return screen()->root_depth; } QImage::Format format() const override; + QColorSpace colorSpace() const override { return m_colorSpace; } QSizeF physicalSize() const override { return m_sizeMillimeters; } QDpi logicalDpi() const override; QDpi logicalBaseDpi() const override { return QDpi(96, 96); } @@ -226,6 +227,7 @@ private: QSizeF m_sizeMillimeters; QRect m_geometry; QRect m_availableGeometry; + QColorSpace m_colorSpace; Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; QXcbCursor *m_cursor; qreal m_refreshRate = 60.0; |