Bug 1005392 - Fix typeaheadfind leak. r=enndeakin
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 07 May 2014 13:55:00 -0400
changeset 182562 07dfcb557d3200d7b1e20bf50483793efaabcea1
parent 182561 e85bfba14a5bded7d6df2c97677ea664a492d30b
child 182563 fc69e8ac0db2a49249b68b0a3714da377d32bbde
push id43344
push usercbook@mozilla.com
push dateMon, 12 May 2014 11:48:14 +0000
treeherdermozilla-inbound@bb0df5c0ba1e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersenndeakin
bugs1005392
milestone32.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
Bug 1005392 - Fix typeaheadfind leak. r=enndeakin
toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
toolkit/components/typeaheadfind/nsTypeAheadFind.h
--- a/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
+++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCOMPtr.h"
 #include "nsMemory.h"
 #include "nsIServiceManager.h"
 #include "mozilla/ModuleUtils.h"
+#include "mozilla/Services.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsCURILoader.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsNetUtil.h"
 #include "nsIURL.h"
 #include "nsIURI.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
@@ -70,16 +71,17 @@ NS_IMPL_CYCLE_COLLECTION(nsTypeAheadFind
 
 static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
 
 #define NS_FIND_CONTRACTID "@mozilla.org/embedcomp/rangefind;1"
 
 nsTypeAheadFind::nsTypeAheadFind():
   mStartLinksOnlyPref(false),
   mCaretBrowsingOn(false),
+  mDidAddObservers(false),
   mLastFindLength(0),
   mIsSoundInitialized(false),
   mCaseSensitive(false)
 {
 }
 
 nsTypeAheadFind::~nsTypeAheadFind()
 {
@@ -98,24 +100,31 @@ nsTypeAheadFind::Init(nsIDocShell* aDocS
   mSearchRange = nullptr;
   mStartPointRange = nullptr;
   mEndPointRange = nullptr;
   if (!prefInternal || !EnsureFind())
     return NS_ERROR_FAILURE;
 
   SetDocShell(aDocShell);
 
-  // ----------- Listen to prefs ------------------
-  nsresult rv = prefInternal->AddObserver("accessibility.browsewithcaret", this, true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (!mDidAddObservers) {
+    mDidAddObservers = true;
+    // ----------- Listen to prefs ------------------
+    nsresult rv = prefInternal->AddObserver("accessibility.browsewithcaret", this, true);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-  // ----------- Get initial preferences ----------
-  PrefsReset();
+    // ----------- Get initial preferences ----------
+    PrefsReset();
 
-  return rv;
+    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+    if (os) {
+      os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true);
+    }
+  }
+  return NS_OK;
 }
 
 nsresult
 nsTypeAheadFind::PrefsReset()
 {
   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
   NS_ENSURE_TRUE(prefBranch, NS_ERROR_FAILURE);
 
@@ -164,31 +173,36 @@ nsTypeAheadFind::SetDocShell(nsIDocShell
 
   mWebBrowserFind = do_GetInterface(aDocShell);
   NS_ENSURE_TRUE(mWebBrowserFind, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIPresShell> presShell;
   presShell = aDocShell->GetPresShell();
   mPresShell = do_GetWeakReference(presShell);
 
+  ReleaseStrongMemberVariables();
+  return NS_OK;
+}
+
+void
+nsTypeAheadFind::ReleaseStrongMemberVariables()
+{
   mStartFindRange = nullptr;
   mStartPointRange = nullptr;
   mSearchRange = nullptr;
   mEndPointRange = nullptr;
 
   mFoundLink = nullptr;
   mFoundEditable = nullptr;
   mFoundRange = nullptr;
   mCurrentWindow = nullptr;
 
   mSelectionController = nullptr;
 
   mFind = nullptr;
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTypeAheadFind::SetSelectionModeAndRepaint(int16_t aToggle)
 {
   nsCOMPtr<nsISelectionController> selectionController = 
     do_QueryReferent(mSelectionController);
   if (!selectionController) {
@@ -218,18 +232,22 @@ nsTypeAheadFind::CollapseSelection()
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTypeAheadFind::Observe(nsISupports *aSubject, const char *aTopic,
                          const char16_t *aData)
 {
-  if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID))
+  if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     return PrefsReset();
+  } else if (!nsCRT::strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) &&
+             SameCOMIdentity(aSubject, mCurrentWindow)) {
+    ReleaseStrongMemberVariables();
+  }
 
   return NS_OK;
 }
 
 void
 nsTypeAheadFind::SaveFind()
 {
   if (mWebBrowserFind)
@@ -455,17 +473,17 @@ nsTypeAheadFind::FindItNow(nsIPresShell 
       }
 
       nsCOMPtr<nsIDocument> document =
         do_QueryInterface(presShell->GetDocument());
       NS_ASSERTION(document, "Wow, presShell doesn't have document!");
       if (!document)
         return NS_ERROR_UNEXPECTED;
 
-      nsCOMPtr<nsPIDOMWindow> window = document->GetWindow();
+      nsCOMPtr<nsPIDOMWindow> window = document->GetInnerWindow();
       NS_ASSERTION(window, "document has no window");
       if (!window)
         return NS_ERROR_UNEXPECTED;
 
       nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
       if (usesIndependentSelection) {
         /* If a search result is found inside an editable element, we'll focus
          * the element only if focus is in our content window, i.e.
--- a/toolkit/components/typeaheadfind/nsTypeAheadFind.h
+++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.h
@@ -65,24 +65,27 @@ protected:
                                bool aIsFirstVisiblePreferred,
                                bool aFindPrev, nsIPresShell **aPresShell,
                                nsPresContext **aPresContext);
 
   // Get the pres shell from mPresShell and return it only if it is still
   // attached to the DOM window.
   NS_HIDDEN_(already_AddRefed<nsIPresShell>) GetPresShell();
 
+  void ReleaseStrongMemberVariables();
+
   // Current find state
   nsString mTypeAheadBuffer;
   nsCString mNotFoundSoundURL;
 
   // PRBools are used instead of PRPackedBools because the address of the
   // boolean variable is getting passed into a method.
   bool mStartLinksOnlyPref;
   bool mCaretBrowsingOn;
+  bool mDidAddObservers;
   nsCOMPtr<nsIDOMElement> mFoundLink;     // Most recent elem found, if a link
   nsCOMPtr<nsIDOMElement> mFoundEditable; // Most recent elem found, if editable
   nsCOMPtr<nsIDOMRange> mFoundRange;      // Most recent range found
   nsCOMPtr<nsIDOMWindow> mCurrentWindow;
   // mLastFindLength is the character length of the last find string.  It is used for
   // disabling the "not found" sound when using backspace or delete
   uint32_t mLastFindLength;