diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index d22717fa44e..a8b5c13908e 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -737,8 +737,10 @@ this._lastRelatedTab = null; var oldBrowser = this.mCurrentBrowser; - if (oldBrowser) + if (oldBrowser) { oldBrowser.setAttribute("type", "content-targetable"); + oldBrowser.docShell.isActive = false; + } var updatePageReport = false; if (!oldBrowser || @@ -747,6 +749,7 @@ updatePageReport = true; newBrowser.setAttribute("type", "content-primary"); + newBrowser.docShell.isActive = true; this.mCurrentBrowser = newBrowser; this.mCurrentTab = this.selectedTab; @@ -1189,6 +1192,10 @@ flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL; try { b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData); + + // We start our browsers out as inactive, and then maintain + // activeness in the tab switcher. + b.docShell.isActive = false; } catch (ex) { } } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 5897b636502..6232babf443 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -703,6 +703,7 @@ nsDocShell::nsDocShell(): mAllowAuth(PR_TRUE), mAllowKeywordFixup(PR_FALSE), mIsOffScreenBrowser(PR_FALSE), + mIsActive(PR_TRUE), mFiredUnloadEvent(PR_FALSE), mEODForCurrentDocument(PR_FALSE), mURIResultedInDocument(PR_FALSE), @@ -2496,6 +2497,10 @@ nsDocShell::SetDocLoaderParent(nsDocLoader * aParent) { SetAllowImages(value); } + if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) + { + SetIsActive(value); + } if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) { value = PR_FALSE; } @@ -4618,6 +4623,40 @@ nsDocShell::GetIsOffScreenBrowser(PRBool *aIsOffScreen) return NS_OK; } +NS_IMETHODIMP +nsDocShell::SetIsActive(PRBool aIsActive) +{ + // We disallow setting active on chrome docshells. + if (mItemType == nsIDocShellTreeItem::typeChrome) + return NS_ERROR_INVALID_ARG; + + // Keep track ourselves. + mIsActive = aIsActive; + + // Tell the PresShell about it. + nsCOMPtr pshell; + GetPresShell(getter_AddRefs(pshell)); + if (pshell) + pshell->SetIsActive(aIsActive); + + // Recursively tell all of our children + PRInt32 n = mChildList.Count(); + for (PRInt32 i = 0; i < n; ++i) { + nsCOMPtr docshell = do_QueryInterface(ChildAt(i)); + if (docshell) + docshell->SetIsActive(aIsActive); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::GetIsActive(PRBool *aIsActive) +{ + *aIsActive = mIsActive; + return NS_OK; +} + NS_IMETHODIMP nsDocShell::SetVisibility(PRBool aVisibility) { @@ -6909,7 +6948,10 @@ nsDocShell::RestoreFromHistory() PRBool allowDNSPrefetch; childShell->GetAllowDNSPrefetch(&allowDNSPrefetch); - + + // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning + // that the child inherits our state. Among other things, this means + // that the child inherits our mIsActive, which is what we want. AddChild(childItem); childShell->SetAllowPlugins(allowPlugins); diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index b2f3a1bdbbf..d85ef0de8d9 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -787,6 +787,7 @@ protected: PRPackedBool mAllowAuth; PRPackedBool mAllowKeywordFixup; PRPackedBool mIsOffScreenBrowser; + PRPackedBool mIsActive; // This boolean is set to true right before we fire pagehide and generally // unset when we embed a new content viewer. While it's true no navigation diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index ab652596c46..84ae7b65026 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -71,7 +71,7 @@ interface nsIPrincipal; interface nsIWebBrowserPrint; interface nsIVariant; -[scriptable, uuid(8ac6b880-776a-44d4-b271-a7e64ae3debd)] +[scriptable, uuid(bf6db598-3833-400b-9e53-ec220cb2496c)] interface nsIDocShell : nsISupports { /** @@ -521,4 +521,11 @@ interface nsIDocShell : nsISupports * current docshell. */ readonly attribute boolean canExecuteScripts; + + /** + * Sets whether a docshell is active. An active docshell is one that is + * visible, and thus is not a good candidate for certain optimizations + * like image frame discarding. Docshells are active unless told otherwise. + */ + attribute boolean isActive; }; diff --git a/embedding/browser/webBrowser/nsIWebBrowser.idl b/embedding/browser/webBrowser/nsIWebBrowser.idl index f3741680d8a..de4b877b696 100644 --- a/embedding/browser/webBrowser/nsIWebBrowser.idl +++ b/embedding/browser/webBrowser/nsIWebBrowser.idl @@ -52,7 +52,7 @@ interface nsIWeakReference; * to register any listeners. The interface may also be used at runtime * to obtain the content DOM window and from that the rest of the DOM. */ -[scriptable, uuid(69E5DF00-7B8B-11d3-AF61-00A024FFC08C)] +[scriptable, uuid(33e9d001-caab-4ba9-8961-54902f197202)] interface nsIWebBrowser : nsISupports { /** @@ -165,4 +165,15 @@ interface nsIWebBrowser : nsISupports * @see nsIDOMWindow */ readonly attribute nsIDOMWindow contentDOMWindow; + + /** + * Whether this web browser is active. Active means that it's visible + * enough that we want to avoid certain optimizations like discarding + * decoded image data and throttling the refresh driver. In Firefox, + * this corresponds to the visible tab. + * + * Defaults to true. For optimal performance, set it to false when + * appropriate. + */ + attribute boolean isActive; }; diff --git a/embedding/browser/webBrowser/nsWebBrowser.cpp b/embedding/browser/webBrowser/nsWebBrowser.cpp index 26688005245..5626b04e750 100644 --- a/embedding/browser/webBrowser/nsWebBrowser.cpp +++ b/embedding/browser/webBrowser/nsWebBrowser.cpp @@ -108,6 +108,7 @@ nsWebBrowser::nsWebBrowser() : mDocShellTreeOwner(nsnull), mContentType(typeContentWrapper), mActivating(PR_FALSE), mShouldEnableHistory(PR_TRUE), + mIsActive(PR_TRUE), mParentNativeWindow(nsnull), mProgressListener(nsnull), mBackgroundColor(0), @@ -419,6 +420,23 @@ NS_IMETHODIMP nsWebBrowser::GetContentDOMWindow(nsIDOMWindow **_retval) return rv; } +NS_IMETHODIMP nsWebBrowser::GetIsActive(PRBool *rv) +{ + *rv = mIsActive; + return NS_OK; +} + +NS_IMETHODIMP nsWebBrowser::SetIsActive(PRBool aIsActive) +{ + // Set our copy of the value + mIsActive = aIsActive; + + // If we have a docshell, pass on the request + if (mDocShell) + return mDocShell->SetIsActive(aIsActive); + return NS_OK; +} + //***************************************************************************** // nsWebBrowser::nsIDocShellTreeItem //***************************************************************************** @@ -1631,6 +1649,12 @@ NS_IMETHODIMP nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) // By default, do not allow DNS prefetch, so we don't break our frozen // API. Embeddors who decide to enable it should do so manually. mDocShell->SetAllowDNSPrefetch(PR_FALSE); + + // It's possible to call setIsActive() on us before we have a docshell. + // If we're getting a docshell now, pass along our desired value. The + // default here (true) matches the default of the docshell, so this is + // a no-op unless setIsActive(false) has been called on us. + mDocShell->SetIsActive(mIsActive); } else { diff --git a/embedding/browser/webBrowser/nsWebBrowser.h b/embedding/browser/webBrowser/nsWebBrowser.h index 6fab484f246..9ebc7a8d138 100644 --- a/embedding/browser/webBrowser/nsWebBrowser.h +++ b/embedding/browser/webBrowser/nsWebBrowser.h @@ -169,6 +169,7 @@ protected: PRUint32 mContentType; PRPackedBool mActivating; PRPackedBool mShouldEnableHistory; + PRPackedBool mIsActive; nativeWindow mParentNativeWindow; nsIWebProgressListener *mProgressListener; nsCOMPtr mWebProgress; diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index c39968be5fd..a40bc156c6b 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -954,6 +954,16 @@ public: return mObservesMutationsForPrint; } + void SetIsActive(PRBool aIsActive) + { + mIsActive = aIsActive; + } + + PRBool IsActive() + { + return mIsActive; + } + // mouse capturing static CapturingContentInfo gCaptureInfo; @@ -1083,6 +1093,7 @@ protected: PRPackedBool mIsReflowing; PRPackedBool mPaintingSuppressed; // For all documents we initially lock down painting. PRPackedBool mIsThemeSupportDisabled; // Whether or not form controls should use nsITheme in this shell. + PRPackedBool mIsActive; #ifdef ACCESSIBILITY /** diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 12f32eb6221..dba069dd71b 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1362,6 +1362,9 @@ public: static PRInt64 SizeOfBidiMemoryReporter(void *) { return EstimateShellsMemory(LiveShellBidiSizeEnumerator); } + +protected: + void QueryIsActive(); }; class nsAutoCauseReflowNotifier @@ -1595,6 +1598,7 @@ PresShell::PresShell() #endif mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES; mIsThemeSupportDisabled = PR_FALSE; + mIsActive = PR_TRUE; #ifdef DEBUG mPresArenaAllocCount = 0; #endif @@ -1801,6 +1805,9 @@ PresShell::Init(nsIDocument* aDocument, } #endif // MOZ_SMIL + // Get our activeness from the docShell. + QueryIsActive(); + return NS_OK; } @@ -7306,6 +7313,10 @@ PresShell::Thaw() mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull); UnsuppressPainting(); + + // Get the activeness of our presshell, as this might have changed + // while we were in the bfcache + QueryIsActive(); } void @@ -8943,3 +8954,16 @@ void nsIPresShell::ReleaseStatics() delete sLiveShells; sLiveShells = nsnull; } + +// Asks our docshell whether we're active. +void PresShell::QueryIsActive() +{ + nsCOMPtr container = mPresContext->GetContainer(); + nsCOMPtr docshell(do_QueryInterface(container)); + if (docshell) { + PRBool isActive; + nsresult rv = docshell->GetIsActive(&isActive); + if (NS_SUCCEEDED(rv)) + SetIsActive(isActive); + } +}