Bug 666317 - Discard decoded images on a memory-pressure notification. r=joe

This commit is contained in:
Justin Lebar 2011-06-30 17:13:56 -04:00
parent 8968056a3a
commit 7566d381e7
6 changed files with 95 additions and 0 deletions

View File

@ -117,6 +117,35 @@ DiscardTracker::Remove(DiscardTrackerNode *node)
node->prev = node->next = nsnull;
}
/*
* Discard all the images we're tracking.
*/
void
DiscardTracker::DiscardAll()
{
if (!sInitialized)
return;
// Remove the sentinel from the list so that the only elements in the list
// which don't track an image are the head and tail.
Remove(&sSentinel);
// Discard all tracked images.
for (DiscardTrackerNode *node = sHead.next;
node != &sTail; node = sHead.next) {
NS_ABORT_IF_FALSE(node->curr, "empty node!");
Remove(node);
node->curr->Discard();
}
// Add the sentinel back to the (now empty) list.
Reset(&sSentinel);
// Because the sentinel is the only element in the list, the next timer event
// would be a no-op. Disable the timer as an optimization.
TimerOff();
}
/**
* Initialize the tracker.
*/

View File

@ -76,6 +76,7 @@ class DiscardTracker
static void Remove(struct DiscardTrackerNode *node);
static void Shutdown();
static void ReloadTimeout();
static void DiscardAll();
private:
static nsresult Initialize();
static nsresult TimerOn();

View File

@ -724,6 +724,7 @@ NS_IMETHODIMP
imgCacheObserver::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData)
{
if (strcmp(aTopic, "memory-pressure") == 0) {
DiscardTracker::DiscardAll();
mLoader.MinimizeCaches();
} else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
strcmp(aTopic, "chrome-flush-caches") == 0) {

View File

@ -49,6 +49,8 @@ _BROWSER_FILES = head.js \
imageX2.html \
animated.gif \
animated2.gif \
browser_bug666317.js \
big.png \
$(NULL)
libs:: $(_BROWSER_FILES)

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@ -0,0 +1,62 @@
waitForExplicitFinish();
let pageSource =
'<html><body>' +
'<img id="testImg" src="' + TESTROOT + 'big.png">' +
'</body></html>';
let oldDiscardingPref, oldTab, newTab;
let prefBranch = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.getBranch('image.mem.');
function isImgDecoded() {
let img = gBrowser.getBrowserForTab(newTab).contentWindow
.document.getElementById('testImg');
img.QueryInterface(Ci.nsIImageLoadingContent);
let request = img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
return request.imageStatus & Ci.imgIRequest.STATUS_FRAME_COMPLETE ? true : false;
}
// Ensure that the image is decoded by drawing it to a canvas.
function forceDecodeImg() {
let doc = gBrowser.getBrowserForTab(newTab).contentWindow.document;
let img = doc.getElementById('testImg');
let canvas = doc.createElement('canvas');
let ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
}
function test() {
// Enable the discarding pref.
oldDiscardingPref = prefBranch.getBoolPref('discardable');
prefBranch.setBoolPref('discardable', true);
// Create and focus a new tab.
oldTab = gBrowser.selectedTab;
newTab = gBrowser.addTab('data:text/html,' + pageSource);
gBrowser.selectedTab = newTab;
// Run step2 after the tab loads.
gBrowser.getBrowserForTab(newTab)
.addEventListener("pageshow", step2 );
}
function step2() {
// Check that the image is decoded.
forceDecodeImg();
ok(isImgDecoded(), 'Image should initially be decoded.');
// Focus the old tab, then fire a memory-pressure notification. This should
// cause the decoded image in the new tab to be discarded.
gBrowser.selectedTab = oldTab;
var os = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
os.notifyObservers(null, 'memory-pressure', 'heap-minimize');
ok(!isImgDecoded(), 'Image should be discarded.');
// And we're done.
gBrowser.removeTab(newTab);
prefBranch.setBoolPref('discardable', oldDiscardingPref);
finish();
}