OS X - Cocoa backing store and drawRect

m_backingStore pointer has a limited 'lifetime' - usually
it is set in -flushBackingStore:region:offset: method, then -drawRect:
is invoked/forced by -setNeedsDisplayInRect:, after that it's dangerous to
have a non-null pointer to a backing store (and we reset it).
But if Cocoa invokes drawRect (due to some reason) our null backing store pointer is also
not good. This patch instead is using a shared resource (QImage) from a backing store.
This patch also makes getBackingStoreCGImage() redundant - -drawRect: was the only
place we called it.

Task-number: QTBUG-42206
Change-Id: Ie7726336f05d07c52f660f6326ae5cef114201dd
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
bb10
Timur Pocheptsov 2014-10-28 11:41:34 +01:00
parent 148aa0e3e3
commit 916dfcb827
4 changed files with 13 additions and 30 deletions

View File

@ -51,12 +51,9 @@ public:
QPaintDevice *paintDevice();
void flush(QWindow *widget, const QRegion &region, const QPoint &offset);
#ifndef QT_NO_OPENGL
QImage toImage() const Q_DECL_OVERRIDE;
#endif
QImage toImage() const;
void resize (const QSize &size, const QRegion &);
bool scroll(const QRegion &area, int dx, int dy);
CGImageRef getBackingStoreCGImage();
qreal getBackingStoreDevicePixelRatio();
private:

View File

@ -96,12 +96,10 @@ void QCocoaBackingStore::flush(QWindow *win, const QRegion &region, const QPoint
}
}
#ifndef QT_NO_OPENGL
QImage QCocoaBackingStore::toImage() const
{
return m_qImage;
}
#endif
void QCocoaBackingStore::resize(const QSize &size, const QRegion &)
{
@ -121,17 +119,6 @@ bool QCocoaBackingStore::scroll(const QRegion &area, int dx, int dy)
return true;
}
CGImageRef QCocoaBackingStore::getBackingStoreCGImage()
{
if (!m_cgImage)
m_cgImage = qt_mac_toCGImage(m_qImage);
// Warning: do not retain/release/cache the returned image from
// outside the backingstore since it shares data with a QImage and
// needs special memory considerations.
return m_cgImage;
}
qreal QCocoaBackingStore::getBackingStoreDevicePixelRatio()
{
return m_qImage.devicePixelRatio();

View File

@ -51,7 +51,8 @@ QT_END_NAMESPACE
Q_FORWARD_DECLARE_OBJC_CLASS(QNSViewMouseMoveHelper);
@interface QT_MANGLE_NAMESPACE(QNSView) : NSView <NSTextInputClient> {
QCocoaBackingStore* m_backingStore;
QImage m_backingStore;
qreal m_pixelRatio;
QPoint m_backingStoreOffset;
CGImageRef m_maskImage;
uchar *m_maskData;

View File

@ -143,7 +143,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
{
self = [super initWithFrame : NSMakeRect(0,0, 300,300)];
if (self) {
m_backingStore = 0;
m_pixelRatio = 1.;
m_maskImage = 0;
m_shouldInvalidateWindowShadow = false;
m_window = 0;
@ -466,8 +466,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
- (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset
{
m_backingStore = backingStore;
m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio();
m_backingStore = backingStore->toImage();
m_pixelRatio = backingStore->getBackingStoreDevicePixelRatio();
m_backingStoreOffset = offset * m_pixelRatio;
foreach (QRect rect, region.rects()) {
[self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
}
@ -531,7 +532,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
if (m_platformWindow->m_drawContentBorderGradient)
NSDrawWindowBackground(dirtyRect);
if (!m_backingStore)
if (m_backingStore.isNull())
return;
// Calculate source and target rects. The target rect is the dirtyRect:
@ -539,11 +540,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
// The backing store source rect will be larger on retina displays.
// Scale dirtyRect by the device pixel ratio:
const qreal devicePixelRatio = m_backingStore->getBackingStoreDevicePixelRatio();
CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * devicePixelRatio,
dirtyRect.origin.y * devicePixelRatio,
dirtyRect.size.width * devicePixelRatio,
dirtyRect.size.height * devicePixelRatio);
CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * m_pixelRatio,
dirtyRect.origin.y * m_pixelRatio,
dirtyRect.size.width * m_pixelRatio,
dirtyRect.size.height * m_pixelRatio);
NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext];
CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort];
@ -569,7 +569,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
dirtyBackingRect.size.width,
dirtyBackingRect.size.height
);
CGImageRef bsCGImage = m_backingStore->getBackingStoreCGImage();
CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore);
CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect);
// Optimization: Copy frame buffer content instead of blending for
@ -586,8 +586,6 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
CGImageRelease(subMask);
[self invalidateWindowShadowIfNeeded];
m_backingStore = 0;
}
- (BOOL) isFlipped