blob: 0be1cae906342e8cd81c30885d171b1e8ed11c1c [file] [log] [blame]
<html>
<head>
<style>
body {
color: black;
padding: 0px 0px 0px 0px;
}
.hidden {
visibility: hidden;
}
</style>
<script>
function print(message, color)
{
var paragraph = document.createElement("div");
paragraph.appendChild(document.createTextNode(message));
paragraph.style.fontFamily = "monospace";
if (color)
paragraph.style.color = color;
document.getElementById("console").appendChild(paragraph);
}
function shouldBe(a, b)
{
var evalA = eval(a);
if (evalA == b)
print("PASS: " + a + " should be " + b + " and is.", "green");
else
print("FAIL: " + a + " should be " + b + " but instead is " + evalA + ".", "red");
}
function gc()
{
if (window.GCController)
return GCController.collect();
for (var i = 0; i < 10000; i++) { // > force garbage collection (FF requires about 9K allocations before a collect)
var s = new String("");
}
}
var event;
function parentEventListener(e)
{
print("DOM EVENT AFTER GARBAGE COLLECTION");
gc();
event = e;
shouldBe("event.myCustomProperty", 1);
event = null; // clear JS reference
}
function childEventListener(e)
{
print("DOM EVENT BEFORE GARBAGE COLLECTION");
e.myCustomProperty = 1;
event = e;
shouldBe("event.myCustomProperty", 1);
event = null; // clear JS reference
}
function testEvents()
{
var parent = document.createElement("p");
var child = document.createElement("p");
parent.appendChild(child);
document.body.appendChild(parent);
if (parent.addEventListener) {
child.addEventListener("click", childEventListener, false);
parent.addEventListener("click", parentEventListener, false);
} else {
child.attachEvent("onclick", childEventListener);
parent.attachEvent("onclick", parentEventListener);
}
if (document.createEvent) {
var event = document.createEvent("MouseEvents");
event.initEvent("click", true, true);
child.dispatchEvent(event);
} else {
child.fireEvent("onclick");
}
}
function test()
{
if (window.layoutTestController)
layoutTestController.dumpAsText();
generateProperties();
print("DOM OBJECTS BEFORE GARBAGE COLLECTION:");
testProperties(expectedResultsBeforeGC);
gc();
print("DOM OBJECTS AFTER GARBAGE COLLECTION:");
testProperties(expectedResultsAfterGC);
testEvents();
}
var objectsToTest = [
"document.implementation", // DOMImplementation
"document",
"document.body",
"document.body.attributes", // NamedNodeMap
"document.getElementsByTagName('body')", // NodeList
"document.getElementsByTagName('canvas')[0].getContext('2d')", // CanvasRenderingContext2D
"document.getElementsByTagName('canvas')[0].getContext('2d').createLinearGradient(0, 0, 0, 0)", // CanvasGradient
"document.getElementsByTagName('canvas')[0].getContext('2d').createPattern(new Image(), 'no-repeat')", // CanvasPattern
"document.getElementsByTagName('select')[0].options",
"document.all",
"document.body.childNodes",
"document.images",
"document.embeds",
"document.applets",
"document.links",
"document.forms",
"document.anchors",
"document.scripts",
"document.getElementsByTagName('form')[0].elements",
"document.getElementsByTagName('table')[0].rows",
"document.getElementsByTagName('table')[0].rows[0].cells",
"document.getElementsByTagName('table')[0].tBodies",
"document.getElementsByTagName('table')[0].tBodies[0].rows",
"document.body.children",
"document.getElementsByTagName('map')[0].areas",
"document.body.style",
"document.body.style.getPropertyCSSValue('color')",
"document.styleSheets",
"document.styleSheets[0]",
"document.styleSheets[0].cssRules",
"document.styleSheets[0].cssRules[0]",
"new XPathEvaluator()", // XPathEvaluator
"new XPathEvaluator().evaluate('/', document, null, 0, null)", // XPathResult
"document.createNSResolver(document)", // XPathNSResolver
"document.createExpression('/', document.createNSResolver(document))" // XPathExpression
// should not cache: NodeIterator, NodeFilter, TreeWalker, XMLHttpRequest
// add to test: DOMRect, MediaList, Counter, Range
];
var expectedResultsBeforeGC = [
1,
1,
1,
1,
undefined,
1,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
1,
1,
1,
1,
undefined,
1,
undefined,
undefined,
undefined,
undefined,
];
var expectedResultsAfterGC = [
undefined,
1,
1,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
];
function generateProperties()
{
for (var i = 0; i < objectsToTest.length; i++) { // >
try {
eval(objectsToTest[i] + ".myCustomProperty = 1;");
} catch(e) {
print("NOT SUPPORTED: " + objectsToTest[i] + "[ " + e.message + " ]");
}
}
}
function testProperties(expectedResults)
{
for (var i = 0; i < objectsToTest.length; i++) { // >
try {
shouldBe(objectsToTest[i] + ".myCustomProperty", expectedResults[i]);
} catch(e) {
}
}
}
</script>
</head>
<body style="color: black" onload="test();">
<p>This page tests whether custom properties on DOM objects persist after garbage collection.</p>
<p>If the test passes, you'll see a series of 'PASS' messages below.</p>
<p>Because neither WinIE nor FF has reasonable or predictable behavior in this scenario, this
test just documents our behavior to ensure that we don't change it accidentally. It is not
a prescription for how things should behave.</p>
<hr>
<div id='console'></div>
<div class='hidden'>
<canvas></canvas>
<select></select>
<object name="object"></object>
<form></form>
<table><tbody><tr></tr></tbody></table>
<map></map>
</div>
</body>
</html>