Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 <!DOCTYPE HTML>
2 <html>
3 <!--
4 https://bugzilla.mozilla.org/show_bug.cgi?id=507902
5 -->
6 <head>
7 <title>Test for Bug 507902</title>
8 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
10 </head>
11 <body>
12 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=507902">Mozilla Bug 507902</a>
14 <iframe id="testFrameElem"></iframe>
16 <pre id="test">
17 <script class="testbody" type="text/javascript">
19 //
20 // Mochitest to test nsImageFrame icons
21 //
22 // The 'loading' icon should be displayed up until we have enough image
23 // data to determine the frame size.
24 //
25 // The 'broken' icon should be displayed when the URL is invalid (either
26 // a bad server or a file that fails to be sniffed to an appropriate
27 // mimetype).
28 //
30 // Boilerplate
31 gWindowUtils = SpecialPowers.getDOMWindowUtils(window);
33 // URL + paths
34 //
35 // We have a separate copy of the icons in the test directory to
36 // avoid any firefox caching mechanisms that might affect the
37 // behavior of the load.
38 var us = window.location.href;
39 var baseURL = us.substring(0, us.lastIndexOf('/') + 1);
40 var loadIconFilename = "file_LoadingImageReference.png";
41 var imageFilename = "file_Dolske.png";
42 var brokenIconFilename = "file_BrokenImageReference.png";
43 var serverFilename = "file_IconTestServer.sjs";
44 var serverContinueFlag = "?continue=true";
45 var bogusFilename = "oneuponatimewhendolskewasyoung.png";
47 // Our test image element, inside a div, inside an iframe
48 var testFrameElem = document.getElementById("testFrameElem");
49 var innerDoc = testFrameElem.contentWindow.document;
50 var divContainer = innerDoc.createElement("div");
51 divContainer.style.cssFloat = "left";
52 innerDoc.body.appendChild(divContainer);
53 var testImageElem = new Image();
54 divContainer.appendChild(testImageElem);
55 var pingImage = new Image();
57 // Set up the canvases
58 var canvases = {};
59 var canvasNames = [ "brokenIconTest", "brokenIconReference",
60 "loadingIconTest", "loadingIconReference",
61 "loadedTest", "loadedReference" ];
62 var windowElem = document.documentElement;
63 for (var i in canvasNames) {
64 var can = document.createElement("canvas");
65 can.setAttribute("width", windowElem.getAttribute("width"));
66 can.setAttribute("height", windowElem.getAttribute("height"));
67 canvases[canvasNames[i]] = can;
69 // When the image frame has no idea how to size itself, it sizes itself
70 // to dimensions capable of displaying the alt feedback icons. However, if
71 // the image has been loaded before, something (I don't know what) seems to
72 // remember the size of the last successful image for that URL. So when we
73 // create a new image frame for that URL, it uses that size until it hears
74 // something different. This happens through a refresh (not sure if this is
75 // desired behavior). This means that if you refresh the test, the "loading"
76 // icon for the test image will appear with a border that stretches further
77 // right and down, because that URL previously displayed an image with larger
78 // dimensions. This causes the verify stage to fail. To allow for
79 // successful test refreshes (only useful for people, not automated tests),
80 // we add a clipping region so that we see the left and top borders, along
81 // with the image, but not the bottom and right borders.
83 if ((i > 1) && (i < 4)) {
84 var ctx = can.getContext("2d");
85 ctx.beginPath();
86 ctx.rect(0,0, 30, 30);
87 ctx.clip();
88 }
90 }
92 // Stage 1 - Load the reference image for the broken icon
93 function loadBrokenIconReference() {
95 // Debugging - Let's see if setting onload after src is a problem
96 testImageElem.onload = function(event) { dump("test_bug507902.html DEBUG - uh oh, placeholder onload 1 called\n");};
98 // Debug - Figure out if we're getting an onerror instead of onload
99 testImageElem.onerror = function(event) {dump("test_bug507902.html DEBUG - Got onerror for testImageElem!\n");};
101 testImageElem.src = baseURL + brokenIconFilename;
102 stageTransition();
103 }
105 // Stage 2 - Draw the reference image for the broken icon to a canvas
106 function drawBrokenIconReference() {
108 enableBorderAndPad();
109 drawWindowToCanvas("brokenIconReference");
110 disableBorderAndPad();
112 stageTransition();
113 }
115 // Stage 3 - Load the reference image for the loading icon
116 function loadLoadingIconReference() {
118 // Debugging - Let's see if setting onload after src is a problem
119 testImageElem.onload = function(event) { dump("test_bug507902.html DEBUG - uh oh, placeholder onload 3 called\n");};
121 testImageElem.src = baseURL + loadIconFilename;
122 stageTransition();
123 }
125 // Stage 4 - Draw the reference image for the loading icon to a canvas
126 function drawLoadingIconReference() {
128 enableBorderAndPad();
129 drawWindowToCanvas("loadingIconReference");
130 disableBorderAndPad();
132 stageTransition();
133 }
135 // Stage 5 - Try to load a broken image
136 function loadBrokenImage() {
137 resetImage();
138 testImageElem.src = baseURL + bogusFilename;
139 stageTransition();
140 }
142 // Stage 6 - Draw the screen to a canvas. This should hopefully
143 // be the broken icon.
144 function drawBrokenIcon() {
145 drawWindowToCanvas("brokenIconTest");
146 stageTransition();
147 }
149 // Stage 7 - Load the reference image for the test image
150 function loadImageReference() {
151 resetImage();
153 // Debugging - Let's see if setting onload after src is a problem
154 testImageElem.onload = function(event) { dump("test_bug507902.html DEBUG - uh oh, placeholder onload 7 called\n");};
156 testImageElem.src = baseURL + imageFilename;
157 stageTransition();
158 }
160 // Stage 8 - Draw the reference image for the test image to a canvas
161 function drawImageReference() {
162 drawWindowToCanvas("loadedReference");
163 stageTransition();
164 }
166 // Stage 9 - Start a load of the test image from the delay-generating server
167 function startServerLoad() {
169 // Reset the image
170 resetImage();
172 // Debugging info so we can figure out the hang
173 dump("test_bug507902.html DEBUG - starting server load\n");
175 // Load the image
176 testImageElem.src = baseURL + serverFilename;
177 stageTransition();
178 }
180 // Stage 10 - Draw the screen to a canvas. This should hopefully be the loading
181 // icon.
182 function drawLoadingIcon() {
184 // Debugging info so we can figure out the hang
185 dump("test_bug507902.html DEBUG - drawing loading icon\n");
187 drawWindowToCanvas("loadingIconTest");
188 stageTransition();
189 }
191 // Stage 11 - Tell the server to continue.
192 function signalServerContinue() {
194 // Debugging info so we can figure out the hang
195 dump("test_bug507902.html DEBUG - signaling server to continue\n");
197 pingImage.src = baseURL + serverFilename + serverContinueFlag;
198 stageTransition();
199 }
201 // Stage 12 - Draw the screen to a canvas. This should hopefully be the loaded
202 // test image.
203 function drawLoadedImage() {
204 drawWindowToCanvas("loadedTest");
205 stageTransition();
206 }
209 // Stage 13 - Verify That the appropriate canvases match
210 function verifyCanvases() {
212 // Verify the broken icon
213 ok(canvasesAreEqual("brokenIconTest", "brokenIconReference"),
214 "Window drawn on broken load should match broken icon reference");
216 // Verify the loading icon
217 ok(canvasesAreEqual("loadingIconTest", "loadingIconReference"),
218 "Window drawn mid-load should match loading icon reference");
220 // Verify the loaded image
221 ok(canvasesAreEqual("loadedTest", "loadedReference"),
222 "Window drawn post-load should match reference image");
224 stageTransition();
225 }
227 // We have a bunch of different things that need to happen in order
228 // with different transitions. We make a "stage table" here where
229 // each entry contains the stage function ('fn') and a transition
230 // ('trans'), which can be one of the following:
231 // "instant" - Just calls the next stage directly
232 // "onload" - Sets the next stage as an onload event for the image element
233 // "onerror" - Sets the next stage as an onerror event for the image element
234 // integer - Sets the next stage to be called after the given timeout duration
235 // "finish" - Finish the test
236 var testStages = [
237 { "fn" : loadBrokenIconReference, "trans" : "onload"},
238 { "fn" : drawBrokenIconReference, "trans" : "instant"},
239 { "fn" : loadLoadingIconReference, "trans" : "onload" },
240 { "fn" : drawLoadingIconReference, "trans" : "instant" },
241 { "fn" : loadBrokenImage, "trans" : "onerror" },
242 { "fn" : drawBrokenIcon, "trans" : "instant" },
243 { "fn" : loadImageReference, "trans" : "onload" },
244 { "fn" : drawImageReference, "trans" : "instant" },
245 // XXXbholley - We use a timeout here because resetting the
246 // image doesn't seem to be quite synchronous. If we make
247 // this transition "instant", then the drawImage call draws
248 // an empty (0,0,0,0) rect to the canvas and we're left with
249 // whatever was there before. I don't know of any good event
250 // mechanism to figure out when the image frame is bootstrapped
251 // enough to display the loading image, so I did trial-and-error
252 // with timeouts. 50ms seems to be enough time for things to work
253 // reliably, so *= 6 for good measure.
254 { "fn" : startServerLoad, "trans" : 300 },
255 { "fn" : drawLoadingIcon, "trans" : "instant" },
256 { "fn" : signalServerContinue, "trans" : "onload" },
257 { "fn" : drawLoadedImage, "trans" : "instant" },
258 { "fn" : verifyCanvases, "trans" : "finish" } ];
259 var currentStage = 0;
261 // Transition function called at the end of each stage
262 function stageTransition() {
264 // Debugging info so we can figure out the hang
265 dump("test_bug507902.html DEBUG - Current Stage: " + currentStage + "\n");
267 // What's our transition?
268 var trans = testStages[currentStage++].trans;
270 // If the transition is finish, stop now before we access out of bounds
271 if (trans == "finish") {
272 makeCanvasesVisible(); // Useful for debugging
273 SimpleTest.finish();
274 return;
275 }
277 // Otherwise, get the next function
278 var nextfn = testStages[currentStage].fn;
280 // Switch based on transition
281 switch (trans) {
283 // Continue right away
284 case "instant":
285 nextfn();
286 break;
288 // Continue after we get an onload event on the test image
289 case "onload":
290 testImageElem.onload = function(event) {testImageElem.onload = undefined; nextfn();};
291 break;
293 // Continue after we get an onerror event on the test image
294 case "onerror":
295 testImageElem.onerror = function(event) {testImageElem.onerror = undefined; nextfn();};
296 break;
298 // Timeout
299 default:
300 setTimeout(nextfn, trans);
301 break
302 }
303 }
305 // Lots if asynchronous behavior here
306 SimpleTest.waitForExplicitFinish();
308 // Catch somebody's eye
309 dump("This test is failing intermittently, see bug 510001 - If you see orange here, please paste the following debugging output on the bug!\n");
311 // Kick off the test by invoking the first stage. The stages call each other
312 testStages[0].fn();
315 // We need to get rid of the old image element and make a new one. If we
316 // don't, the "current/pending" machinery will display the old image until
317 // the new one is loaded, so we won't see the loading icon.
318 function resetImage() {
319 divContainer.removeChild(testImageElem);
320 testImageElem = null;
321 testImageElem = new Image();
322 divContainer.appendChild(testImageElem);
323 }
325 //
326 // Makes the canvases visible. Called before the tests finish. This is useful for
327 // debugging.
328 //
329 function makeCanvasesVisible() {
330 for (var i = 0; i < canvasNames.length - 1; i += 2) {
331 var title = document.createElement("h3");
332 title.innerHTML = canvasNames[i] + ", " + canvasNames[i+1] + ":";
333 document.body.appendChild(title);
334 var myDiv = document.createElement("div");
335 myDiv.appendChild(canvases[canvasNames[i]]);
336 myDiv.appendChild(canvases[canvasNames[i+1]]);
337 document.body.appendChild(myDiv);
338 }
339 }
341 //
342 // Enables and disables bordering/padding to mimic the look of alt feedback icons
343 //
344 function enableBorderAndPad() {
345 divContainer.style.border = "1px";
346 divContainer.style.borderStyle = "inset";
347 testImageElem.style.padding = "3px";
348 }
350 function disableBorderAndPad() {
351 testImageElem.style.padding = 0;
352 divContainer.style.border = "0px";
353 divContainer.style.borderStyle = "";
354 }
356 //
357 // Helper canvas methods. This is mostly copped directly from the reftest framework
358 //
360 function drawWindowToCanvas(canvasName) {
361 var win = testFrameElem.contentWindow;
362 var ctx = canvases[canvasName].getContext("2d");
363 // drawWindow always draws one canvas pixel for each CSS pixel in the source
364 // window, so scale the drawing to show the zoom (making each canvas pixel be one
365 // device pixel instead)
366 ctx.drawWindow(win, win.scrollX, win.scrollY,
367 Math.ceil(canvases[canvasName].width),
368 Math.ceil(canvases[canvasName].height),
369 "rgb(255,255,255)");
370 }
372 function canvasesAreEqual(canvas1Name, canvas2Name) {
373 var c1 = canvases[canvas1Name];
374 var c2 = canvases[canvas2Name];
375 var differences = gWindowUtils.compareCanvases(c1, c2, {});
376 return (differences == 0);
377 }
379 </script>
380 </pre>
381 </body>
382 </html>