Bug 1157941 - If the current PresShell is suppressed, paint the old one if it is available r=tn,Enn

This commit is contained in:
George Wright 2015-07-21 21:09:02 -04:00
parent 188c522f2c
commit 44888c310e
9 changed files with 100 additions and 32 deletions

View File

@ -18,36 +18,21 @@ function getFocusedLocalName(browser) {
}
add_task(function* () {
gBrowser.selectedTab = gBrowser.addTab(URL);
let browser = gBrowser.selectedBrowser;
yield BrowserTestUtils.browserLoaded(browser);
let testTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
let browser = testTab.linkedBrowser;
is((yield getFocusedLocalName(browser)), "button", "button is focused");
let promiseFocused = ContentTask.spawn(browser, null, function* () {
return new Promise(resolve => {
content.addEventListener("focus", function onFocus({target}) {
if (String(target.location).startsWith("data:")) {
content.removeEventListener("focus", onFocus);
resolve();
}
});
});
});
let blankTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
// The test page loaded, so open an empty tab, select it, then restore
// the test tab. This causes the test page's focused element to be removed
// from its document.
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
gBrowser.removeCurrentTab();
// Wait until the original tab is focused again.
yield promiseFocused;
yield BrowserTestUtils.switchTab(gBrowser, testTab);
// Make sure focus is given to the window because the element is now gone.
is((yield getFocusedLocalName(browser)), "body", "body is focused");
// Cleanup.
gBrowser.removeTab(blankTab);
gBrowser.removeCurrentTab();
});

View File

@ -90,6 +90,10 @@ nsView::~nsView()
mParent->RemoveChild(this);
}
if (mPreviousWindow) {
mPreviousWindow->SetPreviouslyAttachedWidgetListener(nullptr);
}
// Destroy and release the widget
DestroyWidget();
@ -722,6 +726,18 @@ nsresult nsView::DetachFromTopLevelWidget()
NS_PRECONDITION(mWindow, "null mWindow for DetachFromTopLevelWidget!");
mWindow->SetAttachedWidgetListener(nullptr);
nsIWidgetListener* listener = mWindow->GetPreviouslyAttachedWidgetListener();
if (listener && listener->GetView()) {
// Ensure the listener doesn't think it's being used anymore
listener->GetView()->SetPreviousWidget(nullptr);
}
// If the new view's frame is paint suppressed then the window
// will want to use us instead until that's done
mWindow->SetPreviouslyAttachedWidgetListener(this);
mPreviousWindow = mWindow;
mWindow = nullptr;
mWidgetIsTopLevel = false;
@ -1096,3 +1112,9 @@ nsView::HandleEvent(WidgetGUIEvent* aEvent,
return result;
}
bool
nsView::IsPrimaryFramePaintSuppressed()
{
return mFrame ? mFrame->PresContext()->PresShell()->IsPaintingSuppressed() : false;
}

View File

@ -281,6 +281,14 @@ public:
*/
nsIWidget* GetWidget() const { return mWindow; }
/**
* The widget which we have attached a listener to can also have a "previous"
* listener set on it. This is to keep track of the last nsView when navigating
* to a new one so that we can continue to paint that if the new one isn't ready
* yet.
*/
void SetPreviousWidget(nsIWidget* aWidget) { mPreviousWindow = aWidget; }
/**
* Returns true if the view has a widget associated with it.
*/
@ -383,6 +391,8 @@ public:
nsPoint GetOffsetTo(const nsView* aOther, const int32_t aAPD) const;
nsIWidget* GetNearestWidget(nsPoint* aOffset, const int32_t aAPD) const;
bool IsPrimaryFramePaintSuppressed();
private:
explicit nsView(nsViewManager* aViewManager = nullptr,
nsViewVisibility aVisibility = nsViewVisibility_kShow);
@ -450,6 +460,7 @@ private:
nsViewManager *mViewManager;
nsView *mParent;
nsCOMPtr<nsIWidget> mWindow;
nsCOMPtr<nsIWidget> mPreviousWindow;
nsView *mNextSibling;
nsView *mFirstChild;
nsIFrame *mFrame;

View File

@ -440,11 +440,20 @@ nsViewManager::ProcessPendingUpdatesPaint(nsIWidget* aWidget)
}
}
nsView* view = nsView::GetViewFor(aWidget);
if (!view) {
NS_ERROR("FlushDelayedResize destroyed the nsView?");
return;
}
nsIWidgetListener* previousListener = aWidget->GetPreviouslyAttachedWidgetListener();
if (previousListener &&
previousListener != view &&
view->IsPrimaryFramePaintSuppressed()) {
return;
}
if (mPresShell) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
@ -1149,3 +1158,4 @@ nsViewManager::InvalidateHierarchy()
}
}
}

View File

@ -217,7 +217,14 @@ PuppetWidget::Resize(double aWidth,
InvalidateRegion(this, dirty);
}
// call WindowResized() on both the current listener, and possibly
// also the previous one if we're in a state where we're drawing that one
// because the current one is paint suppressed
if (!oldBounds.IsEqualEdges(mBounds) && mAttachedWidgetListener) {
if (GetCurrentWidgetListener() &&
GetCurrentWidgetListener() != mAttachedWidgetListener) {
GetCurrentWidgetListener()->WindowResized(this, mBounds.width, mBounds.height);
}
mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
}
@ -313,8 +320,8 @@ PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus)
aStatus = nsEventStatus_eIgnore;
if (mAttachedWidgetListener) {
aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents);
if (GetCurrentWidgetListener()) {
aStatus = GetCurrentWidgetListener()->HandleEvent(event, mUseAttachedEvents);
}
return NS_OK;
@ -912,7 +919,7 @@ PuppetWidget::Paint()
{
MOZ_ASSERT(!mDirtyRegion.IsEmpty(), "paint event logic messed up");
if (!mAttachedWidgetListener)
if (!GetCurrentWidgetListener())
return NS_OK;
nsIntRegion region = mDirtyRegion;
@ -921,9 +928,9 @@ PuppetWidget::Paint()
mDirtyRegion.SetEmpty();
mPaintTask.Revoke();
mAttachedWidgetListener->WillPaintWindow(this);
GetCurrentWidgetListener()->WillPaintWindow(this);
if (mAttachedWidgetListener) {
if (GetCurrentWidgetListener()) {
#ifdef DEBUG
debug_DumpPaintEvent(stderr, this, region,
nsAutoCString("PuppetWidget"), 0);
@ -940,15 +947,15 @@ PuppetWidget::Paint()
ctx->Clip();
AutoLayerManagerSetup setupLayerManager(this, ctx,
BufferMode::BUFFER_NONE);
mAttachedWidgetListener->PaintWindow(this, region);
GetCurrentWidgetListener()->PaintWindow(this, region);
if (mTabChild) {
mTabChild->NotifyPainted();
}
}
}
if (mAttachedWidgetListener) {
mAttachedWidgetListener->DidPaintWindow();
if (GetCurrentWidgetListener()) {
GetCurrentWidgetListener()->DidPaintWindow();
}
return NS_OK;
@ -1250,5 +1257,20 @@ PuppetScreenManager::GetSystemDefaultScale(float *aDefaultScale)
return NS_OK;
}
nsIWidgetListener*
PuppetWidget::GetCurrentWidgetListener()
{
if (!mPreviouslyAttachedWidgetListener ||
!mAttachedWidgetListener) {
return mAttachedWidgetListener;
}
if (mAttachedWidgetListener->GetView()->IsPrimaryFramePaintSuppressed()) {
return mPreviouslyAttachedWidgetListener;
}
return mAttachedWidgetListener;
}
} // namespace widget
} // namespace mozilla

View File

@ -274,6 +274,8 @@ private:
bool GetCaretRect(mozilla::LayoutDeviceIntRect& aCaretRect, uint32_t aCaretOffset);
uint32_t GetCaretOffset();
nsIWidgetListener* GetCurrentWidgetListener();
class PaintTask : public nsRunnable {
public:
NS_DECL_NSIRUNNABLE

View File

@ -147,6 +147,7 @@ NS_IMPL_ISUPPORTS(nsBaseWidget, nsIWidget, nsISupportsWeakReference)
nsBaseWidget::nsBaseWidget()
: mWidgetListener(nullptr)
, mAttachedWidgetListener(nullptr)
, mPreviouslyAttachedWidgetListener(nullptr)
, mLayerManager(nullptr)
, mCompositorVsyncDispatcher(nullptr)
, mCursor(eCursor_standard)
@ -399,6 +400,16 @@ nsIWidgetListener* nsBaseWidget::GetAttachedWidgetListener()
return mAttachedWidgetListener;
}
nsIWidgetListener* nsBaseWidget::GetPreviouslyAttachedWidgetListener()
{
return mPreviouslyAttachedWidgetListener;
}
void nsBaseWidget::SetPreviouslyAttachedWidgetListener(nsIWidgetListener* aListener)
{
mPreviouslyAttachedWidgetListener = aListener;
}
void nsBaseWidget::SetAttachedWidgetListener(nsIWidgetListener* aListener)
{
mAttachedWidgetListener = aListener;

View File

@ -236,6 +236,8 @@ public:
NS_IMETHOD AttachViewToTopLevel(bool aUseAttachedEvents) override;
virtual nsIWidgetListener* GetAttachedWidgetListener() override;
virtual void SetAttachedWidgetListener(nsIWidgetListener* aListener) override;
virtual nsIWidgetListener* GetPreviouslyAttachedWidgetListener() override;
virtual void SetPreviouslyAttachedWidgetListener(nsIWidgetListener* aListener) override;
NS_IMETHOD_(TextEventDispatcher*) GetTextEventDispatcher() override final;
// Helper function for dispatching events which are not processed by APZ,
@ -489,6 +491,7 @@ protected:
nsIWidgetListener* mWidgetListener;
nsIWidgetListener* mAttachedWidgetListener;
nsIWidgetListener* mPreviouslyAttachedWidgetListener;
nsRefPtr<LayerManager> mLayerManager;
nsRefPtr<CompositorChild> mCompositorChild;
nsRefPtr<CompositorParent> mCompositorParent;

View File

@ -121,8 +121,8 @@ typedef void* nsNativeWidget;
#define NS_NATIVE_PLUGIN_ID 105
#define NS_IWIDGET_IID \
{ 0x22b4504e, 0xddba, 0x4211, \
{ 0xa1, 0x49, 0x6e, 0x11, 0x73, 0xc4, 0x11, 0x45 } }
{ 0x483BF75C, 0xF909, 0x45C3, \
{ 0x95, 0xBE, 0x41, 0x89, 0xDB, 0xCE, 0x2E, 0x13 } };
/*
* Window shadow styles
@ -1075,6 +1075,8 @@ class nsIWidget : public nsISupports {
*/
virtual void SetAttachedWidgetListener(nsIWidgetListener* aListener) = 0;
virtual nsIWidgetListener* GetAttachedWidgetListener() = 0;
virtual void SetPreviouslyAttachedWidgetListener(nsIWidgetListener* aListener) = 0;
virtual nsIWidgetListener* GetPreviouslyAttachedWidgetListener() = 0;
/**
* Accessor functions to get and set the listener which handles various