Tests for bug 359608 - Animated GIFs are animated even when user navigates to another page.r=joe,a=blocker

This commit is contained in:
Alon Zakai 2010-09-07 17:34:18 -07:00
Родитель f1741c27cf
Коммит 4549ab9547
11 изменённых файлов: 404 добавлений и 5 удалений

Просмотреть файл

@ -50,6 +50,7 @@ EXPORTS = ImageErrors.h ImageLogging.h
XPIDLSRCS = \
imgICache.idl \
imgIContainer.idl \
imgIContainerDebug.idl \
imgIContainerObserver.idl \
imgIDecoderObserver.idl \
imgIEncoder.idl \

Просмотреть файл

@ -0,0 +1,58 @@
/** -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alon Zakai <azakai@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
/**
* This interface is used in debug builds (and only there) in
* order to let automatic tests running JavaScript access
* internal state of imgContainers. This lets us test
* things like animation.
*/
[scriptable, uuid(52cbb839-6e63-4a70-b21a-1db4ca706c49)]
interface imgIContainerDebug : nsISupports
{
/**
* The # of frames this imgContainer has been notified about.
* That is equal to the # of times the animation timer has
* fired, and is usually equal to the # of frames actually
* drawn (but actual drawing might be disabled).
*/
readonly attribute PRUint32 framesNotified;
};

Просмотреть файл

@ -166,8 +166,13 @@ DiscardingEnabled()
namespace mozilla {
namespace imagelib {
#ifndef DEBUG
NS_IMPL_ISUPPORTS4(RasterImage, imgIContainer, nsITimerCallback, nsIProperties,
nsISupportsWeakReference)
#else
NS_IMPL_ISUPPORTS5(RasterImage, imgIContainer, nsITimerCallback, nsIProperties,
imgIContainerDebug, nsISupportsWeakReference)
#endif
//******************************************************************************
RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
@ -181,6 +186,9 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
mDecoder(nsnull),
mWorker(nsnull),
mBytesDecoded(0),
#ifdef DEBUG
mFramesNotified(0),
#endif
mHasSize(PR_FALSE),
mDecodeOnDraw(PR_FALSE),
mMultipart(PR_FALSE),
@ -1406,6 +1414,10 @@ RasterImage::SetSourceSizeHint(PRUint32 sizeHint)
NS_IMETHODIMP
RasterImage::Notify(nsITimer *timer)
{
#ifdef DEBUG
mFramesNotified++;
#endif
// This should never happen since the timer is only set up in StartAnimation()
// after mAnim is checked to exist.
NS_ABORT_IF_FALSE(mAnim, "Need anim for Notify()");
@ -2732,5 +2744,19 @@ RasterImage::ShouldAnimate()
mAnimationMode != kDontAnimMode && !mAnimationFinished;
}
//******************************************************************************
/* readonly attribute PRUint32 framesNotified; */
#ifdef DEBUG
NS_IMETHODIMP
RasterImage::GetFramesNotified(PRUint32 *aFramesNotified)
{
NS_ENSURE_ARG_POINTER(aFramesNotified);
*aFramesNotified = mFramesNotified;
return NS_OK;
}
#endif
} // namespace imagelib
} // namespace mozilla

Просмотреть файл

@ -64,6 +64,9 @@
#include "imgFrame.h"
#include "nsThreadUtils.h"
#include "DiscardTracker.h"
#ifdef DEBUG
#include "imgIContainerDebug.h"
#endif
class imgIDecoder;
class nsIInputStream;
@ -145,16 +148,22 @@ namespace imagelib {
class imgDecodeWorker;
class Decoder;
class RasterImage : public mozilla::imagelib::Image,
public nsITimerCallback,
public nsIProperties,
public nsSupportsWeakReference
class RasterImage : public mozilla::imagelib::Image
, public nsITimerCallback
, public nsIProperties
, public nsSupportsWeakReference
#ifdef DEBUG
, public imgIContainerDebug
#endif
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGICONTAINER
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSIPROPERTIES
#ifdef DEBUG
NS_DECL_IMGICONTAINERDEBUG
#endif
RasterImage(imgStatusTracker* aStatusTracker = nsnull);
virtual ~RasterImage();
@ -473,6 +482,10 @@ private: // data
nsRefPtr<imgDecodeWorker> mWorker;
PRUint32 mBytesDecoded;
#ifdef DEBUG
PRUint32 mFramesNotified;
#endif
// Boolean flags (clustered together to conserve space):
PRPackedBool mHasSize:1; // Has SetSize() been called?
PRPackedBool mDecodeOnDraw:1; // Decoding on draw?

Просмотреть файл

@ -48,6 +48,8 @@ MODULE = test_libpr0n
XPCSHELL_TESTS = unit
DIRS += mochitest
DIRS += mochitest \
browser \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,55 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# the Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = modules/libpr0n/test/browser
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = head.js \
browser_image.js \
image.html \
imageX2.html \
animated.gif \
$(NULL)
libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

Двоичные данные
modules/libpr0n/test/browser/animated.gif Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 70 KiB

Просмотреть файл

@ -0,0 +1,175 @@
waitForExplicitFinish();
// A hold on the current timer, so it doens't get GCed out from
// under us
var gTimer;
// Browsing to a new URL - pushing us into the bfcache - should cause
// animations to stop, and resume when we return
function testBFCache() {
function theTest() {
var abort = false;
var chances, gImage, gFrames;
gBrowser.selectedTab = gBrowser.addTab();
switchToTabHavingURI(TESTROOT + "image.html", true, function(aBrowser) {
var window = aBrowser.contentWindow;
// If false, we are in an optimized build, and we abort this and
// all further tests
if (!actOnMozImage(window.document, "img1", function(image) {
gImage = image;
gFrames = gImage.framesNotified;
})) {
gBrowser.removeCurrentTab();
abort = true;
}
goer.next();
});
yield;
if (abort) {
finish();
yield; // optimized build
}
// Let animation run for a bit
chances = 120;
do {
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() {
if (gImage.framesNotified >= 10) {
goer.send(true);
} else {
chances--;
goer.send(chances == 0); // maybe if we wait a bit, it will happen
}
}, 500, Ci.nsITimer.TYPE_ONE_SHOT);
} while (!(yield));
is(chances > 0, true, "Must have animated a few frames so far");
// Browse elsewhere; push our animating page into the bfcache
gBrowser.loadURI("about:blank");
// Wait a bit for page to fully load, then wait a while and
// see that no animation occurs.
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() {
gFrames = gImage.framesNotified;
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() {
// Might have a few stray frames, until other page totally loads
is(gImage.framesNotified == gFrames, true, "Must have not animated in bfcache!");
goer.next();
}, 4000, Ci.nsITimer.TYPE_ONE_SHOT);
}, 0, Ci.nsITimer.TYPE_ONE_SHOT); // delay of 0 - wait for next event loop
yield;
// Go back
gBrowser.goBack();
chances = 120;
do {
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() {
if (gImage.framesNotified - gFrames >= 10) {
goer.send(true);
} else {
chances--;
goer.send(chances == 0); // maybe if we wait a bit, it will happen
}
}, 500, Ci.nsITimer.TYPE_ONE_SHOT);
} while (!(yield));
is(chances > 0, true, "Must have animated once out of bfcache!");
gBrowser.removeCurrentTab();
nextTest();
}
var goer = theTest();
goer.next();
}
// Check that imgContainers are shared on the same page and
// between tabs
function testSharedContainers() {
function theTest() {
var gImages = [];
var gFrames;
gBrowser.selectedTab = gBrowser.addTab();
switchToTabHavingURI(TESTROOT + "image.html", true, function(aBrowser) {
actOnMozImage(aBrowser.contentWindow.window.document, "img1", function(image) {
gImages[0] = image;
gFrames = image.framesNotified; // May in theory have frames from last test
// in this counter - so subtract them out
});
goer.next();
});
yield;
// Load next tab somewhat later
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() {
gBrowser.selectedTab = gBrowser.addTab();
goer.next();
}, 1500, Ci.nsITimer.TYPE_ONE_SHOT);
yield;
switchToTabHavingURI(TESTROOT + "imageX2.html", true, function(aBrowser) {
[1,2].forEach(function(i) {
actOnMozImage(aBrowser.contentWindow.window.document, "img"+i, function(image) {
gImages[i] = image;
});
});
goer.next();
});
yield;
chances = 120;
do {
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() {
if (gImages[0].framesNotified - gFrames >= 10) {
goer.send(true);
} else {
chances--;
goer.send(chances == 0); // maybe if we wait a bit, it will happen
}
}, 500, Ci.nsITimer.TYPE_ONE_SHOT);
} while (!(yield));
is(chances > 0, true, "Must have been animating while showing several images");
// Check they all have the same frame counts
var theFrames = null;
[0,1,2].forEach(function(i) {
var frames = gImages[i].framesNotified;
if (theFrames == null) {
theFrames = frames;
} else {
is(theFrames, frames, "Sharing the same imgContainer means *exactly* the same frame counts!");
}
});
gBrowser.removeCurrentTab();
gBrowser.removeCurrentTab();
nextTest();
}
var goer = theTest();
goer.next();
}
var tests = [testBFCache, testSharedContainers];
function nextTest() {
if (tests.length == 0) {
finish();
return;
}
tests.shift()();
}
function test() {
nextTest();
}

Просмотреть файл

@ -0,0 +1,41 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const RELATIVE_DIR = "modules/libpr0n/test/browser/";
const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR;
const TESTROOT2 = "http://example.org/browser/" + RELATIVE_DIR;
const CHROMEROOT = "chrome://mochikit/content/browser/" + RELATIVE_DIR;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function getImageLoading(doc, id) {
var htmlImg = doc.getElementById(id);
return htmlImg.QueryInterface(Ci.nsIImageLoadingContent);
}
// Tries to get the Moz debug image, imgIContainerDebug. Only works
// in a debug build. If we succeed, we call func().
function actOnMozImage(doc, id, func) {
var imgContainer = getImageLoading(doc, id).getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST).image;
var mozImage;
try {
mozImage = imgContainer.QueryInterface(Ci.imgIContainerDebug);
}
catch (e) {
return false;
}
func(mozImage);
return true;
}
function awaitImageContainer(doc, id, func) {
getImageLoading(doc, id).addObserver({
QueryInterface: XPCOMUtils.generateQI([Ci.imgIDecoderObserver]),
onStartContainer: function(aRequest, aContainer) {
getImageLoading(doc, id).removeObserver(this);
func(aContainer);
},
});
}

Просмотреть файл

@ -0,0 +1,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Imagelib2 animation tests</title>
</head>
<body>
<p>Page with image</p>
<img src="animated.gif" id="img1">
</body>
</html>

Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Imagelib2 animation tests</title>
</head>
<body>
<p>Page with images</p>
<img src="animated.gif" id="img1">
<br>
<img src="animated.gif" id="img2">
</body>
</html>