Bug 1154231 - Part 1. Reclaim cached resources when memory-pressure occurs. r=mattwoodrow
authorKan-Ru Chen <kanru@kanru.info>
Wed, 29 Apr 2015 11:54:04 +0800
changeset 274557 e784bb7b9f21e5431f4913293adc2e85b90f45e2
parent 274556 ad07670653a29076602ae2acf2867bbb28729dd9
child 274558 9c18f3e4d02ae785e942c9a6525a7d7217339b48
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1154231
milestone41.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 1154231 - Part 1. Reclaim cached resources when memory-pressure occurs. r=mattwoodrow
widget/PuppetWidget.cpp
widget/PuppetWidget.h
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -113,16 +113,21 @@ PuppetWidget::Create(nsIWidget        *a
   PuppetWidget* parent = static_cast<PuppetWidget*>(aParent);
   if (parent) {
     parent->SetChild(this);
     mLayerManager = parent->GetLayerManager();
   }
   else {
     Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
   }
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    mMemoryPressureObserver = new MemoryPressureObserver(this);
+    obs->AddObserver(mMemoryPressureObserver, "memory-pressure", false);
+  }
 
   return NS_OK;
 }
 
 void
 PuppetWidget::InitIMEState()
 {
   MOZ_ASSERT(mTabChild);
@@ -148,16 +153,19 @@ PuppetWidget::CreateChild(const nsIntRec
 }
 
 NS_IMETHODIMP
 PuppetWidget::Destroy()
 {
   Base::OnDestroy();
   Base::Destroy();
   mPaintTask.Revoke();
+  if (mMemoryPressureObserver) {
+    mMemoryPressureObserver->Remove();
+  }
   mChild = nullptr;
   if (mLayerManager) {
     mLayerManager->Destroy();
   }
   mLayerManager = nullptr;
   mTabChild = nullptr;
   return NS_OK;
 }
@@ -170,20 +178,16 @@ PuppetWidget::Show(bool aState)
 
   bool wasVisible = mVisible;
   mVisible = aState;
 
   if (mChild) {
     mChild->mVisible = aState;
   }
 
-  if (!mVisible && mLayerManager) {
-    mLayerManager->ClearCachedResources();
-  }
-
   if (!wasVisible && mVisible) {
     Resize(mBounds.width, mBounds.height, false);
     Invalidate(mBounds);
   }
 
   return NS_OK;
 }
 
@@ -1032,16 +1036,45 @@ NS_IMETHODIMP
 PuppetWidget::PaintTask::Run()
 {
   if (mWidget) {
     mWidget->Paint();
   }
   return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS(PuppetWidget::MemoryPressureObserver, nsIObserver)
+
+NS_IMETHODIMP
+PuppetWidget::MemoryPressureObserver::Observe(nsISupports* aSubject,
+                                              const char* aTopic,
+                                              const char16_t* aData)
+{
+  if (!mWidget) {
+    return NS_OK;
+  }
+
+  if (strcmp("memory-pressure", aTopic) == 0) {
+    if (!mWidget->mVisible && mWidget->mLayerManager) {
+      mWidget->mLayerManager->ClearCachedResources();
+    }
+  }
+  return NS_OK;
+}
+
+void
+PuppetWidget::MemoryPressureObserver::Remove()
+{
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, "memory-pressure");
+  }
+  mWidget = nullptr;
+}
+
 bool
 PuppetWidget::NeedsPaint()
 {
   // e10s popups are handled by the parent process, so never should be painted here
   if (XRE_GetProcessType() == GeckoProcessType_Content &&
       Preferences::GetBool("browser.tabs.remote.desktopbehavior", false) &&
       mWindowType == eWindowType_popup) {
     NS_WARNING("Trying to paint an e10s popup in the child process!");
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -274,28 +274,41 @@ private:
   public:
     NS_DECL_NSIRUNNABLE
     explicit PaintTask(PuppetWidget* widget) : mWidget(widget) {}
     void Revoke() { mWidget = nullptr; }
   private:
     PuppetWidget* mWidget;
   };
 
+  class MemoryPressureObserver : public nsIObserver {
+  public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIOBSERVER
+    explicit MemoryPressureObserver(PuppetWidget* aWidget) : mWidget(aWidget) {}
+    void Remove();
+  private:
+    virtual ~MemoryPressureObserver() {}
+    PuppetWidget* mWidget;
+  };
+  friend class MemoryPressureObserver;
+
   // TabChild normally holds a strong reference to this PuppetWidget
   // or its root ancestor, but each PuppetWidget also needs a
   // reference back to TabChild (e.g. to delegate nsIWidget IME calls
   // to chrome) So we hold a weak reference to TabChild here.  Since
   // it's possible for TabChild to outlive the PuppetWidget, we clear
   // this weak reference in Destroy()
   TabChild* mTabChild;
   // The "widget" to which we delegate events if we don't have an
   // event handler.
   nsRefPtr<PuppetWidget> mChild;
   nsIntRegion mDirtyRegion;
   nsRevocableEventPtr<PaintTask> mPaintTask;
+  nsRefPtr<MemoryPressureObserver> mMemoryPressureObserver;
   // XXX/cjones: keeping this around until we teach LayerManager to do
   // retained-content-only transactions
   mozilla::RefPtr<DrawTarget> mDrawTarget;
   // IME
   nsIMEUpdatePreference mIMEPreferenceOfParent;
   // Latest seqno received through events
   uint32_t mIMELastReceivedSeqno;
   // Chrome's seqno value when last blur occurred