213 lines
6.8 KiB
HTML
213 lines
6.8 KiB
HTML
<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 testDOMImplementation()
|
|
{
|
|
var impl = document.implementation.createHTMLDocument('').implementation;
|
|
gc();
|
|
impl.createHTMLDocument(''); // May crash or throw an exception if we collect parent document of impl.
|
|
}
|
|
|
|
function test()
|
|
{
|
|
if (window.testRunner)
|
|
testRunner.dumpAsText();
|
|
|
|
print("DOM OBJECTS BEFORE GARBAGE COLLECTION:");
|
|
generateProperties();
|
|
|
|
gc();
|
|
|
|
print("DOM OBJECTS AFTER GARBAGE COLLECTION:");
|
|
testPropertiesAgain();
|
|
|
|
testEvents();
|
|
testDOMImplementation();
|
|
}
|
|
|
|
// By default, we expect that custom properties are not allowed.
|
|
// If "allow custom" is specified, then custom properties are allowed and survive garbage collection.
|
|
// If "allow custom skip" is specified, this means this property is not guaranteed to survive garbage
|
|
// collection, so we don't test it at all, since there is a chance it might due to conservative GC algorithm.
|
|
// Any uses of "allow custom skip" represent bugs that need to be fixed.
|
|
|
|
var objectsToTest = [
|
|
[ "document.implementation", "allow custom" ], // DOMImplementation
|
|
[ "document", "allow custom" ],
|
|
[ "document.body", "allow custom" ],
|
|
[ "document.body.attributes", "allow custom" ], // NamedNodeMap
|
|
[ "document.getElementsByTagName('body')", "allow custom" ], // NodeList
|
|
[ "document.getElementsByTagName('canvas')[0].getContext('2d')", "allow custom" ], // CanvasRenderingContext2D
|
|
[ "document.getElementsByTagName('canvas')[0].getContext('2d').createLinearGradient(0, 0, 0, 0)" ], // CanvasGradient
|
|
[ "document.getElementsByTagName('select')[0].options", "allow custom" ],
|
|
[ "document.body.childNodes", "allow custom" ],
|
|
|
|
[ "document.all", "allow custom" ],
|
|
[ "document.images", "allow custom" ],
|
|
[ "document.embeds", "allow custom" ],
|
|
[ "document.applets", "allow custom" ],
|
|
[ "document.links", "allow custom" ],
|
|
[ "document.forms", "allow custom" ],
|
|
[ "document.anchors", "allow custom" ],
|
|
[ "document.scripts", "allow custom" ],
|
|
|
|
[ "document.getElementsByTagName('form')[0].elements", "allow custom" ],
|
|
[ "document.getElementsByTagName('table')[0].rows", "allow custom" ],
|
|
[ "document.getElementsByTagName('table')[0].rows[0].cells", "allow custom" ],
|
|
[ "document.getElementsByTagName('table')[0].tBodies", "allow custom" ],
|
|
[ "document.getElementsByTagName('table')[0].tBodies[0].rows", "allow custom" ],
|
|
[ "document.body.children", "allow custom" ],
|
|
[ "document.getElementsByTagName('map')[0].areas", "allow custom" ],
|
|
|
|
[ "document.body.style", "allow custom" ],
|
|
[ "document.body.style.getPropertyCSSValue('color')", "allow custom" ],
|
|
[ "document.styleSheets", "allow custom" ],
|
|
[ "document.styleSheets[0]", "allow custom" ],
|
|
[ "document.styleSheets[0].cssRules", "allow custom"],
|
|
[ "document.styleSheets[0].cssRules[0]", "allow custom" ],
|
|
|
|
[ "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
|
|
];
|
|
|
|
function generateProperties()
|
|
{
|
|
for (var i = 0; i < objectsToTest.length; i++) { // >
|
|
try {
|
|
eval(objectsToTest[i][0] + ".myCustomProperty = 1;");
|
|
} catch(e) {
|
|
print("NOT SUPPORTED: " + objectsToTest[i][0] + "[ " + e.message + " ]");
|
|
}
|
|
var expectedResult = objectsToTest[i][1] ? 1 : undefined;
|
|
try {
|
|
shouldBe(objectsToTest[i][0] + ".myCustomProperty", expectedResult);
|
|
} catch(e) {
|
|
}
|
|
}
|
|
}
|
|
|
|
function testPropertiesAgain()
|
|
{
|
|
for (var i = 0; i < objectsToTest.length; i++) { // >
|
|
if (objectsToTest[i][1] === "allow custom skip")
|
|
continue;
|
|
var expectedResult = objectsToTest[i][1] ? 1 : undefined;
|
|
try {
|
|
shouldBe(objectsToTest[i][0] + ".myCustomProperty", expectedResult);
|
|
} 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>
|