author | George Wright <george@mozilla.com> |
Tue, 21 Jul 2015 21:09:02 -0400 | |
changeset 254019 | 60f82e40f039995f757ebd373d968433ac6f6ad7 |
parent 254018 | fa5d3f420ee69e56962b68fa40b0596d5ffa12de |
child 254020 | 6713ac169edc7a276a01e5716fd5cdf4dcf4181e |
push id | 62623 |
push user | gwright@mozilla.com |
push date | Wed, 22 Jul 2015 01:12:07 +0000 |
treeherder | mozilla-inbound@60f82e40f039 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | tn, Enn |
bugs | 1157941 |
milestone | 42.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/base/content/test/general/browser_bug427559.js +++ b/browser/base/content/test/general/browser_bug427559.js @@ -13,41 +13,26 @@ const URL = 'data:text/html;charset=utf- function getFocusedLocalName(browser) { return ContentTask.spawn(browser, null, function* () { return content.document.activeElement.localName; }); } 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(); + });
--- a/view/nsView.cpp +++ b/view/nsView.cpp @@ -85,16 +85,20 @@ nsView::~nsView() mViewManager = nullptr; } else if (mParent) { mParent->RemoveChild(this); } + if (mPreviousWindow) { + mPreviousWindow->SetPreviouslyAttachedWidgetListener(nullptr); + } + // Destroy and release the widget DestroyWidget(); delete mDirtyRegion; } class DestroyWidgetRunnable : public nsRunnable { public: @@ -717,16 +721,28 @@ nsresult nsView::AttachToTopLevelWidget( // Detach this view from an attached widget. nsresult nsView::DetachFromTopLevelWidget() { NS_PRECONDITION(mWidgetIsTopLevel, "Not attached currently!"); 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; return NS_OK; } void nsView::SetZIndex(bool aAuto, int32_t aZIndex) @@ -1091,8 +1107,14 @@ nsView::HandleEvent(WidgetGUIEvent* aEve if (view) { nsRefPtr<nsViewManager> vm = view->GetViewManager(); vm->DispatchEvent(aEvent, view, &result); } return result; } + +bool +nsView::IsPrimaryFramePaintSuppressed() +{ + return mFrame ? mFrame->PresContext()->PresShell()->IsPaintingSuppressed() : false; +}
--- a/view/nsView.h +++ b/view/nsView.h @@ -277,16 +277,24 @@ public: * If we believe that all cutout view have a native widget, this * could be a replacement. * @param aWidget out parameter for widget that this view contains, * or nullptr if there is none. */ 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. */ bool HasWidget() const { return mWindow != nullptr; } void SetForcedRepaint(bool aForceRepaint) { mForcedRepaint = aForceRepaint; } @@ -378,16 +386,18 @@ public: virtual nsEventStatus HandleEvent(mozilla::WidgetGUIEvent* aEvent, bool aUseAttachedEvents) override; virtual ~nsView(); 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); bool ForcedRepaint() { return mForcedRepaint; } // Do the actual work of ResetWidgetBounds, unconditionally. Don't // call this method if we have no widget. @@ -445,16 +455,17 @@ private: // If the hierarchy is being removed, aViewManagerParent points to the view // manager for the hierarchy's old parent, and will have its mouse grab // released if it points to any view in this view hierarchy. void InvalidateHierarchy(nsViewManager *aViewManagerParent); nsViewManager *mViewManager; nsView *mParent; nsCOMPtr<nsIWidget> mWindow; + nsCOMPtr<nsIWidget> mPreviousWindow; nsView *mNextSibling; nsView *mFirstChild; nsIFrame *mFrame; nsRegion *mDirtyRegion; int32_t mZIndex; nsViewVisibility mVis; // position relative our parent view origin but in our appunits nscoord mPosX, mPosY;
--- a/view/nsViewManager.cpp +++ b/view/nsViewManager.cpp @@ -435,21 +435,30 @@ nsViewManager::ProcessPendingUpdatesPain : nullptr) { if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) && vm->mRootView->IsEffectivelyVisible() && vm->mPresShell && vm->mPresShell->IsVisible()) { vm->FlushDelayedResize(true); } } 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()) { printf_stderr("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, view, aWidget); } #endif @@ -1144,8 +1153,9 @@ nsViewManager::InvalidateHierarchy() NS_ADDREF(mRootViewManager); NS_ASSERTION(mRootViewManager != this, "Root view had a parent, but it has the same view manager"); } else { mRootViewManager = this; } } } +
--- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -212,17 +212,24 @@ PuppetWidget::Resize(double aWidth, // XXX: roc says that |aRepaint| dictates whether or not to // invalidate the expanded area if (oldBounds.Size() < mBounds.Size() && aRepaint) { nsIntRegion dirty(mBounds); dirty.Sub(dirty, oldBounds); 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); } return NS_OK; } nsresult PuppetWidget::ConfigureChildren(const nsTArray<Configuration>& aConfigurations) @@ -308,18 +315,18 @@ PuppetWidget::DispatchEvent(WidgetGUIEve WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent(); if (keyEvent) { mTabChild->RequestNativeKeyBindings(&autoCache, keyEvent); } } aStatus = nsEventStatus_eIgnore; - if (mAttachedWidgetListener) { - aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents); + if (GetCurrentWidgetListener()) { + aStatus = GetCurrentWidgetListener()->HandleEvent(event, mUseAttachedEvents); } return NS_OK; } nsEventStatus PuppetWidget::DispatchInputEvent(WidgetInputEvent* aEvent) { @@ -907,53 +914,53 @@ PuppetWidget::ClearCachedCursor() mCustomCursor = nullptr; } nsresult PuppetWidget::Paint() { MOZ_ASSERT(!mDirtyRegion.IsEmpty(), "paint event logic messed up"); - if (!mAttachedWidgetListener) + if (!GetCurrentWidgetListener()) return NS_OK; nsIntRegion region = mDirtyRegion; // reset repaint tracking mDirtyRegion.SetEmpty(); mPaintTask.Revoke(); - mAttachedWidgetListener->WillPaintWindow(this); + GetCurrentWidgetListener()->WillPaintWindow(this); - if (mAttachedWidgetListener) { + if (GetCurrentWidgetListener()) { #ifdef DEBUG debug_DumpPaintEvent(stderr, this, region, nsAutoCString("PuppetWidget"), 0); #endif if (mozilla::layers::LayersBackend::LAYERS_CLIENT == mLayerManager->GetBackendType()) { // Do nothing, the compositor will handle drawing if (mTabChild) { mTabChild->NotifyPainted(); } } else { nsRefPtr<gfxContext> ctx = new gfxContext(mDrawTarget); ctx->Rectangle(gfxRect(0,0,0,0)); 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; } void PuppetWidget::SetChild(PuppetWidget* aChild) { @@ -1245,10 +1252,25 @@ PuppetScreenManager::GetNumberOfScreens( NS_IMETHODIMP PuppetScreenManager::GetSystemDefaultScale(float *aDefaultScale) { *aDefaultScale = 1.0f; return NS_OK; } +nsIWidgetListener* +PuppetWidget::GetCurrentWidgetListener() +{ + if (!mPreviouslyAttachedWidgetListener || + !mAttachedWidgetListener) { + return mAttachedWidgetListener; + } + + if (mAttachedWidgetListener->GetView()->IsPrimaryFramePaintSuppressed()) { + return mPreviouslyAttachedWidgetListener; + } + + return mAttachedWidgetListener; +} + } // namespace widget } // namespace mozilla
--- a/widget/PuppetWidget.h +++ b/widget/PuppetWidget.h @@ -269,16 +269,18 @@ private: bool CacheEditorRect(); bool CacheCompositionRects(uint32_t& aStartOffset, nsTArray<mozilla::LayoutDeviceIntRect>& aRectArray, uint32_t& aTargetCauseOffset); bool GetCaretRect(mozilla::LayoutDeviceIntRect& aCaretRect, uint32_t aCaretOffset); uint32_t GetCaretOffset(); + nsIWidgetListener* GetCurrentWidgetListener(); + class PaintTask : public nsRunnable { public: NS_DECL_NSIRUNNABLE explicit PaintTask(PuppetWidget* widget) : mWidget(widget) {} void Revoke() { mWidget = nullptr; } private: PuppetWidget* mWidget; };
--- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -142,16 +142,17 @@ NS_IMPL_ISUPPORTS(nsBaseWidget, nsIWidge // // nsBaseWidget constructor // //------------------------------------------------------------------------- nsBaseWidget::nsBaseWidget() : mWidgetListener(nullptr) , mAttachedWidgetListener(nullptr) +, mPreviouslyAttachedWidgetListener(nullptr) , mLayerManager(nullptr) , mCompositorVsyncDispatcher(nullptr) , mCursor(eCursor_standard) , mUpdateCursor(true) , mBorderStyle(eBorderStyle_none) , mUseAttachedEvents(false) , mBounds(0,0,0,0) , mOriginalBounds(nullptr) @@ -394,16 +395,26 @@ nsBaseWidget::AttachViewToTopLevel(bool return NS_OK; } nsIWidgetListener* nsBaseWidget::GetAttachedWidgetListener() { return mAttachedWidgetListener; } +nsIWidgetListener* nsBaseWidget::GetPreviouslyAttachedWidgetListener() + { + return mPreviouslyAttachedWidgetListener; + } + +void nsBaseWidget::SetPreviouslyAttachedWidgetListener(nsIWidgetListener* aListener) + { + mPreviouslyAttachedWidgetListener = aListener; + } + void nsBaseWidget::SetAttachedWidgetListener(nsIWidgetListener* aListener) { mAttachedWidgetListener = aListener; } //------------------------------------------------------------------------- // // Close this nsBaseWidget
--- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -231,16 +231,18 @@ public: double& aOverriddenDeltaY) override; virtual already_AddRefed<nsIWidget> CreateChild(const nsIntRect &aRect, nsWidgetInitData *aInitData = nullptr, bool aForceUseIWidgetParent = false) override; 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, // but need to be transformed by APZ. nsEventStatus DispatchInputEvent(mozilla::WidgetInputEvent* aEvent) override; // Dispatch an event that must be first be routed through APZ. nsEventStatus DispatchAPZAwareEvent(mozilla::WidgetInputEvent* aEvent) override; @@ -484,16 +486,17 @@ protected: */ void DestroyCompositor(); void DestroyLayerManager(); void FreeShutdownObserver(); nsIWidgetListener* mWidgetListener; nsIWidgetListener* mAttachedWidgetListener; + nsIWidgetListener* mPreviouslyAttachedWidgetListener; nsRefPtr<LayerManager> mLayerManager; nsRefPtr<CompositorChild> mCompositorChild; nsRefPtr<CompositorParent> mCompositorParent; nsRefPtr<mozilla::CompositorVsyncDispatcher> mCompositorVsyncDispatcher; nsRefPtr<APZCTreeManager> mAPZC; nsRefPtr<APZEventState> mAPZEventState; nsRefPtr<SetAllowedTouchBehaviorCallback> mSetAllowedTouchBehaviorCallback; nsRefPtr<WidgetShutdownObserver> mShutdownObserver;
--- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -116,18 +116,18 @@ typedef void* nsNativeWidget; #if defined(MOZ_WIDGET_GTK) // set/get nsPluginNativeWindowGtk, e10s specific #define NS_NATIVE_PLUGIN_OBJECT_PTR 104 #endif // See RegisterPluginWindowForRemoteUpdates #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 * Also used for the -moz-window-shadow CSS property */ #define NS_STYLE_WINDOW_SHADOW_NONE 0 #define NS_STYLE_WINDOW_SHADOW_DEFAULT 1 @@ -1070,16 +1070,18 @@ class nsIWidget : public nsISupports { NS_IMETHOD AttachViewToTopLevel(bool aUseAttachedEvents) = 0; /** * Accessor functions to get and set the attached listener. Used by * nsView in connection with AttachViewToTopLevel above. */ 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 * actions for the widget. */ //@{ virtual nsIWidgetListener* GetWidgetListener() = 0; virtual void SetWidgetListener(nsIWidgetListener* alistener) = 0;