macOS: Respect color space set on NSWindow when flushing backingstore

By default Qt tries to avoid potentially costly color matching by
not assigning an sRGB color space to our backingstore, even if
that's what we in practice fill it with.

We used to do this by assigning the display's color space, which
effectively opts out of color matching, similar to the old behavior
of the device RGB color space (which nowadays implies sRGB).

By picking up the color space from the NSWindow instead, we allow
the user to override the color space to trigger color matching,
for example by explicitly setting it to NSColorSpace.sRGBColorSpace.

NSWindow will fall back to the screen's color space if the window
doesn't have one set.

Task-number: QTBUG-47660
Change-Id: Iac8177e85e86fe9044a41eb2c93fbf26bb83c248
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Tor Arne Vestbø 2019-07-25 16:06:02 +02:00
parent 5b3c09e35f
commit e6498362fd
2 changed files with 28 additions and 13 deletions

View File

@ -49,7 +49,14 @@
QT_BEGIN_NAMESPACE
class QNSWindowBackingStore : public QRasterBackingStore
class QCocoaBackingStore : public QRasterBackingStore
{
protected:
QCocoaBackingStore(QWindow *window);
QCFType<CGColorSpaceRef> colorSpace() const;
};
class QNSWindowBackingStore : public QCocoaBackingStore
{
public:
QNSWindowBackingStore(QWindow *window);
@ -64,7 +71,7 @@ private:
void redrawRoundedBottomCorners(CGRect) const;
};
class QCALayerBackingStore : public QPlatformBackingStore
class QCALayerBackingStore : public QCocoaBackingStore
{
public:
QCALayerBackingStore(QWindow *window);

View File

@ -48,11 +48,24 @@
QT_BEGIN_NAMESPACE
QNSWindowBackingStore::QNSWindowBackingStore(QWindow *window)
QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
: QRasterBackingStore(window)
{
}
QCFType<CGColorSpaceRef> QCocoaBackingStore::colorSpace() const
{
NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view();
return QCFType<CGColorSpaceRef>::constructFromGet(view.window.colorSpace.CGColorSpace);
}
// ----------------------------------------------------------------------------
QNSWindowBackingStore::QNSWindowBackingStore(QWindow *window)
: QCocoaBackingStore(window)
{
}
QNSWindowBackingStore::~QNSWindowBackingStore()
{
}
@ -175,11 +188,10 @@ void QNSWindowBackingStore::flush(QWindow *window, const QRegion &region, const
Q_ASSERT_X(graphicsContext, "QCocoaBackingStore",
"Focusing the view should give us a current graphics context");
// Prevent potentially costly color conversion by assigning the display color space
// to the backingstore image. This does not copy the underlying image data.
CGColorSpaceRef displayColorSpace = view.window.screen.colorSpace.CGColorSpace;
// Tag backingstore image with color space based on the window.
// Note: This does not copy the underlying image data.
QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace(
QCFType<CGImageRef>(m_image.toCGImage()), displayColorSpace);
QCFType<CGImageRef>(m_image.toCGImage()), colorSpace());
// Create temporary image to use for blitting, without copying image data
NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease];
@ -305,7 +317,7 @@ template<class R>
constexpr backwards_t<R> backwards(R&& r) { return {std::forward<R>(r)}; }
QCALayerBackingStore::QCALayerBackingStore(QWindow *window)
: QPlatformBackingStore(window)
: QCocoaBackingStore(window)
{
qCDebug(lcQpaBackingStore) << "Creating QCALayerBackingStore for" << window;
m_buffers.resize(1);
@ -444,11 +456,7 @@ bool QCALayerBackingStore::recreateBackBufferIfNeeded()
<< "based on requested" << m_requestedSize << "and dpr =" << devicePixelRatio;
static auto pixelFormat = QImage::toPixelFormat(QImage::Format_ARGB32_Premultiplied);
NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view();
auto colorSpace = QCFType<CGColorSpaceRef>::constructFromGet(view.window.screen.colorSpace.CGColorSpace);
m_buffers.back().reset(new GraphicsBuffer(requestedBufferSize, devicePixelRatio, pixelFormat, colorSpace));
m_buffers.back().reset(new GraphicsBuffer(requestedBufferSize, devicePixelRatio, pixelFormat, colorSpace()));
return true;
}