Bug 862556 - Make nsChildView.mm::DrawWindowOverlay thread safe. r=nrc

This commit is contained in:
Matt Woodrow 2013-04-22 14:40:51 +12:00
parent 2e979da7e3
commit 6a644b8e27
7 changed files with 84 additions and 19 deletions

View File

@ -1160,6 +1160,9 @@ BasicShadowLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags)
{
if (mWidget) {
mWidget->PrepareWindowEffects();
}
BasicLayerManager::EndTransaction(aCallback, aCallbackData, aFlags);
ForwardTransaction();

View File

@ -98,6 +98,7 @@ void
LayerManagerComposite::Destroy()
{
if (!mDestroyed) {
mCompositor->GetWidget()->CleanupWindowEffects();
if (mRoot) {
RootLayer()->Destroy();
}

View File

@ -168,6 +168,8 @@ LayerManagerOGL::Destroy()
mRoot = nullptr;
}
mWidget->CleanupWindowEffects();
if (!mGLContext)
return;
@ -849,6 +851,7 @@ LayerManagerOGL::Render()
#endif
// Allow widget to render a custom background.
mWidget->PrepareWindowEffects();
mWidget->DrawWindowUnderlay(this, rect);
// Reset some state that might of been clobbered by the underlay.

View File

@ -523,7 +523,9 @@ public:
virtual void CreateCompositor();
virtual gfxASurface* GetThebesSurface();
virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect);
virtual void PrepareWindowEffects() MOZ_OVERRIDE;
virtual void CleanupWindowEffects() MOZ_OVERRIDE;
virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) MOZ_OVERRIDE;
virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries);
@ -610,7 +612,21 @@ protected:
nsWeakPtr mAccessible;
#endif
nsRefPtr<gfxASurface> mTempThebesSurface;
mozilla::Mutex mEffectsLock;
// May be accessed from any thread, protected
// by mEffectsLock.
bool mShowsResizeIndicator;
nsIntRect mResizeIndicatorRect;
bool mHasRoundedBottomCorners;
int mDevPixelCornerRadius;
// Compositor thread only
bool mFailedResizerImage;
bool mFailedCornerMaskImage;
nsRefPtr<mozilla::gl::TextureImage> mResizerImage;
nsRefPtr<mozilla::gl::TextureImage> mCornerMaskImage;
@ -623,8 +639,6 @@ protected:
// ** We'll need to reinitialize this if the backing resolution changes. **
CGFloat mBackingScaleFactor;
bool mFailedResizerImage;
bool mFailedCornerMaskImage;
bool mVisible;
bool mDrawing;
bool mPluginDrawing;

View File

@ -241,9 +241,12 @@ nsChildView::nsChildView() : nsBaseWidget()
, mView(nullptr)
, mParentView(nullptr)
, mParentWidget(nullptr)
, mBackingScaleFactor(0.0)
, mEffectsLock("WidgetEffects")
, mShowsResizeIndicator(false)
, mHasRoundedBottomCorners(false)
, mFailedResizerImage(false)
, mFailedCornerMaskImage(false)
, mBackingScaleFactor(0.0)
, mVisible(false)
, mDrawing(false)
, mPluginDrawing(false)
@ -271,8 +274,7 @@ nsChildView::~nsChildView()
NS_WARN_IF_FALSE(mOnDestroyCalled, "nsChildView object destroyed without calling Destroy()");
mResizerImage = nullptr;
mCornerMaskImage = nullptr;
DestroyCompositor();
// An nsChildView object that was in use can be destroyed without Destroy()
// ever being called on it. So we also need to do a quick, safe cleanup
@ -1851,6 +1853,24 @@ nsChildView::GetThebesSurface()
return mTempThebesSurface;
}
void
nsChildView::PrepareWindowEffects()
{
MutexAutoLock lock(mEffectsLock);
mShowsResizeIndicator = ShowsResizeIndicator(&mResizeIndicatorRect);
mHasRoundedBottomCorners = [mView isKindOfClass:[ChildView class]] &&
[(ChildView*)mView hasRoundedBottomCorners];
CGFloat cornerRadius = [(ChildView*)mView bottomCornerRadius];
mDevPixelCornerRadius = cornerRadius * BackingScaleFactor();
}
void
nsChildView::CleanupWindowEffects()
{
mResizerImage = nullptr;
mCornerMaskImage = nullptr;
}
void
nsChildView::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
{
@ -1899,14 +1919,15 @@ DrawResizer(CGContextRef aCtx)
void
nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, nsIntRect aRect)
{
nsIntRect resizeRect;
if (!ShowsResizeIndicator(&resizeRect) || mFailedResizerImage) {
if (!mShowsResizeIndicator || mFailedResizerImage) {
return;
}
if (!mResizerImage) {
MutexAutoLock lock(mEffectsLock);
mResizerImage =
aManager->gl()->CreateTextureImage(nsIntSize(resizeRect.width, resizeRect.height),
aManager->gl()->CreateTextureImage(nsIntSize(mResizeIndicatorRect.width,
mResizeIndicatorRect.height),
gfxASurface::CONTENT_COLOR_ALPHA,
LOCAL_GL_CLAMP_TO_EDGE,
TextureImage::UseNearestFilter);
@ -1915,7 +1936,7 @@ nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, nsIntRect aRect)
if (!mResizerImage)
return;
nsIntRegion update(nsIntRect(0, 0, resizeRect.width, resizeRect.height));
nsIntRegion update(nsIntRect(0, 0, mResizeIndicatorRect.width, mResizeIndicatorRect.height));
gfxASurface *asurf = mResizerImage->BeginUpdate(update);
if (!asurf) {
mResizerImage = nullptr;
@ -1970,17 +1991,16 @@ DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius)
void
nsChildView::MaybeDrawRoundedBottomCorners(GLManager* aManager, nsIntRect aRect)
{
if (![mView isKindOfClass:[ChildView class]] ||
![(ChildView*)mView hasRoundedBottomCorners] ||
if (!mHasRoundedBottomCorners ||
mFailedCornerMaskImage)
return;
CGFloat cornerRadius = [(ChildView*)mView bottomCornerRadius];
int devPixelCornerRadius = cornerRadius * BackingScaleFactor();
MutexAutoLock lock(mEffectsLock);
if (!mCornerMaskImage) {
mCornerMaskImage =
aManager->gl()->CreateTextureImage(nsIntSize(devPixelCornerRadius, devPixelCornerRadius),
aManager->gl()->CreateTextureImage(nsIntSize(mDevPixelCornerRadius,
mDevPixelCornerRadius),
gfxASurface::CONTENT_COLOR_ALPHA,
LOCAL_GL_CLAMP_TO_EDGE,
TextureImage::UseNearestFilter);
@ -1989,7 +2009,7 @@ nsChildView::MaybeDrawRoundedBottomCorners(GLManager* aManager, nsIntRect aRect)
if (!mCornerMaskImage)
return;
nsIntRegion update(nsIntRect(0, 0, devPixelCornerRadius, devPixelCornerRadius));
nsIntRegion update(nsIntRect(0, 0, mDevPixelCornerRadius, mDevPixelCornerRadius));
gfxASurface *asurf = mCornerMaskImage->BeginUpdate(update);
if (!asurf) {
mCornerMaskImage = nullptr;
@ -2007,7 +2027,7 @@ nsChildView::MaybeDrawRoundedBottomCorners(GLManager* aManager, nsIntRect aRect)
}
nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
DrawTopLeftCornerMask(image->GetCGContext(), devPixelCornerRadius);
DrawTopLeftCornerMask(image->GetCGContext(), mDevPixelCornerRadius);
mCornerMaskImage->EndUpdate();
}
@ -2019,8 +2039,8 @@ nsChildView::MaybeDrawRoundedBottomCorners(GLManager* aManager, nsIntRect aRect)
ShaderProgramOGL *program = aManager->GetProgram(mCornerMaskImage->GetShaderProgramType());
program->Activate();
program->SetLayerQuadRect(nsIntRect(0, 0, // aRect.x, aRect.y,
devPixelCornerRadius,
devPixelCornerRadius));
mDevPixelCornerRadius,
mDevPixelCornerRadius));
program->SetLayerOpacity(1.0);
program->SetRenderOffset(nsIntPoint(0,0));
program->SetTextureUnit(0);

View File

@ -1153,13 +1153,35 @@ class nsIWidget : public nsISupports {
LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
bool* aAllowRetaining = nullptr) = 0;
/**
* Called before each layer manager transaction to allow any preparation
* for DrawWindowUnderlay/Overlay that needs to be on the main thread.
*
* Always called on the main thread.
*/
virtual void PrepareWindowEffects() = 0;
/**
* Called when shutting down the LayerManager to clean-up any cached resources.
*
* Always called from the compositing thread, which may be the main-thread if
* OMTC is not enabled.
*/
virtual void CleanupWindowEffects() = 0;
/**
* Called before the LayerManager draws the layer tree.
*
* Always called from the compositing thread, which may be the main-thread if
* OMTC is not enabled.
*/
virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) = 0;
/**
* Called after the LayerManager draws the layer tree
*
* Always called from the compositing thread, which may be the main-thread if
* OMTC is not enabled.
*/
virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) = 0;

View File

@ -113,6 +113,8 @@ public:
virtual CompositorParent* NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight);
virtual void CreateCompositor();
virtual void CreateCompositor(int aWidth, int aHeight);
virtual void PrepareWindowEffects() {}
virtual void CleanupWindowEffects() {}
virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) {}
virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) {}
virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) {}