1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
<!DOCTYPE HTML>
<html>
<head>
<title>Test that img.decode works on finished, discarded animated images</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/WindowSnapshot.js"></script>
<script type="text/javascript" src="imgutils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1629490">Mozilla Bug 1629490</a>
<div id="container">
<img id="finitepng" src="finite-apng.png">
</div>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
window.onload = runTest;
let discardCallback = undefined;
let frameUpdateCallback = undefined;
async function runTest() {
const kUsingWebRender = SpecialPowers.DOMWindowUtils.layerManagerType.startsWith("WebRender");
let img = document.getElementById("finitepng");
await img.decode();
while (!isItGreen(img)) {
// We hit an optimized path in WebRender that doesn't cause a repaint on the
// main thread and doesn't seem to send MozAfterPaints.
//
// https://searchfox.org/mozilla-central/rev/b7f3977978922d44c7d92ae01c0d4cc2baca7bc2/layout/style/ImageLoader.cpp#553
await new Promise(resolve => {
if (kUsingWebRender) {
requestAnimationFrame(() => {
requestAnimationFrame(resolve);
});
} else {
window.addEventListener("MozAfterPaint", resolve, { once: true });
}
});
}
addCallbacks(img);
let iterationsLeft = 26;
while (iterationsLeft > 0) {
let discardPromise = new Promise(resolve => {
discardCallback = resolve;
});
document.getElementById("container").style.display = "none";
document.documentElement.offsetLeft; // force that style to take effect
requestDiscard(img);
await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); });
await discardPromise;
await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); });
let waitForFrameUpdate = new Promise(resolve => {
frameUpdateCallback = resolve;
});
document.getElementById("container").style.display = "";
document.documentElement.offsetLeft; // force that style to take effect
await img.decode();
await new Promise(resolve => requestAnimationFrame(resolve));
await waitForFrameUpdate;
ok(isItGreen(img), "should be green");
iterationsLeft--;
await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); });
}
removeObserver(img);
SimpleTest.finish();
}
function isItGreen(img) {
let rect = img.getBoundingClientRect();
let r = {left: rect.left + 5, top: rect.top + 5, width: 5, height: 5};
let c = SpecialPowers.snapshotWindowWithOptions(window, r);
let d = c.getContext('2d').getImageData(0,0,5,5).data;
let isGreen = true;
for (let i = 0; i < 5*5; i++) {
if (d[4*i] != 0 || d[4*i + 1] != 128 || d[4*i + 2] != 0 || d[4*i + 3] != 255) {
isGreen = false;
}
}
return isGreen;
}
let scriptedObserver = undefined;
let imgLoadingContent = undefined;
function addCallbacks(anImage) {
var observer = new ImageDecoderObserverStub();
observer.discard = function () {
if (discardCallback != undefined) {
let localDiscardCallback = discardCallback;
discardCallback = undefined;
setTimeout(localDiscardCallback, 0);
}
};
observer.frameUpdate = function () {
if (frameUpdateCallback != undefined) {
let localFrameUpdateCallback = frameUpdateCallback;
frameUpdateCallback = undefined;
setTimeout(localFrameUpdateCallback, 0);
}
};
observer = SpecialPowers.wrapCallbackObject(observer);
scriptedObserver = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
.getService(SpecialPowers.Ci.imgITools)
.createScriptedObserver(observer);
imgLoadingContent = SpecialPowers.wrap(anImage);
imgLoadingContent.addObserver(scriptedObserver);
}
function removeObserver(anImage) {
imgLoadingContent.removeObserver(scriptedObserver);
}
function requestDiscard(anImage) {
var request = SpecialPowers.wrap(anImage)
.getRequest(SpecialPowers.Ci.nsIImageLoadingContent.CURRENT_REQUEST);
setTimeout(() => request.requestDiscard(), 0);
}
</script>
</body>
</html>
|