Skip to content

Commit

Permalink
Bug 1157941 - If the current PresShell is suppressed, paint the old o…
Browse files Browse the repository at this point in the history
…ne if it is available r=tn,Enn
  • Loading branch information
George Wright committed Jul 22, 2015
1 parent 82b4915 commit a93e9b3
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 32 deletions.
29 changes: 7 additions & 22 deletions browser/base/content/test/general/browser_bug427559.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();

});
22 changes: 22 additions & 0 deletions view/nsView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ nsView::~nsView()
mParent->RemoveChild(this);
}

if (mPreviousWindow) {
mPreviousWindow->SetPreviouslyAttachedWidgetListener(nullptr);
}

// Destroy and release the widget
DestroyWidget();

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1096,3 +1112,9 @@ nsView::HandleEvent(WidgetGUIEvent* aEvent,

return result;
}

bool
nsView::IsPrimaryFramePaintSuppressed()
{
return mFrame ? mFrame->PresContext()->PresShell()->IsPaintingSuppressed() : false;
}
11 changes: 11 additions & 0 deletions view/nsView.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,14 @@ class nsView final : public nsIWidgetListener
*/
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.
*/
Expand Down Expand Up @@ -383,6 +391,8 @@ class nsView final : public nsIWidgetListener
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);
Expand Down Expand Up @@ -450,6 +460,7 @@ class nsView final : public nsIWidgetListener
nsViewManager *mViewManager;
nsView *mParent;
nsCOMPtr<nsIWidget> mWindow;
nsCOMPtr<nsIWidget> mPreviousWindow;
nsView *mNextSibling;
nsView *mFirstChild;
nsIFrame *mFrame;
Expand Down
10 changes: 10 additions & 0 deletions view/nsViewManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -1149,3 +1158,4 @@ nsViewManager::InvalidateHierarchy()
}
}
}

38 changes: 30 additions & 8 deletions widget/PuppetWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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
2 changes: 2 additions & 0 deletions widget/PuppetWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ class PuppetWidget : public nsBaseWidget
bool GetCaretRect(mozilla::LayoutDeviceIntRect& aCaretRect, uint32_t aCaretOffset);
uint32_t GetCaretOffset();

nsIWidgetListener* GetCurrentWidgetListener();

class PaintTask : public nsRunnable {
public:
NS_DECL_NSIRUNNABLE
Expand Down
11 changes: 11 additions & 0 deletions widget/nsBaseWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions widget/nsBaseWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference
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,
Expand Down Expand Up @@ -489,6 +491,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference

nsIWidgetListener* mWidgetListener;
nsIWidgetListener* mAttachedWidgetListener;
nsIWidgetListener* mPreviouslyAttachedWidgetListener;
nsRefPtr<LayerManager> mLayerManager;
nsRefPtr<CompositorChild> mCompositorChild;
nsRefPtr<CompositorParent> mCompositorParent;
Expand Down
6 changes: 4 additions & 2 deletions widget/nsIWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit a93e9b3

Please sign in to comment.