tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_bug507902.html (12993B)


      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 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>
     13 
     14 <iframe id="testFrameElem"></iframe>
     15 
     16 <pre id="test">
     17 <script class="testbody" type="text/javascript">
     18 
     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 //
     29 
     30 // Boilerplate
     31 gWindowUtils = SpecialPowers.getDOMWindowUtils(window);
     32 
     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";
     46 
     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();
     56 
     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 (let 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;
     68 
     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.
     82 
     83  if ((i > 1) && (i < 4)) {
     84    let ctx = can.getContext("2d");
     85    ctx.beginPath();
     86    ctx.rect(0,0, 30, 30);
     87    ctx.clip();
     88   }
     89 
     90 }
     91 
     92 // Stage 1 - Load the reference image for the broken icon
     93 function loadBrokenIconReference() {
     94 
     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");};
     97 
     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");};
    100 
    101  testImageElem.src = baseURL + brokenIconFilename;
    102  stageTransition();
    103 }
    104 
    105 // Stage 2 - Draw the reference image for the broken icon to a canvas
    106 function drawBrokenIconReference() {
    107 
    108  enableBorderAndPad();
    109  drawWindowToCanvas("brokenIconReference");
    110  disableBorderAndPad();
    111 
    112  stageTransition();
    113 }
    114 
    115 // Stage 3 - Load the reference image for the loading icon
    116 function loadLoadingIconReference() {
    117 
    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");};
    120 
    121  testImageElem.src = baseURL + loadIconFilename;
    122  stageTransition();
    123 }
    124 
    125 // Stage 4 - Draw the reference image for the loading icon to a canvas
    126 function drawLoadingIconReference() {
    127 
    128  enableBorderAndPad();
    129  drawWindowToCanvas("loadingIconReference");
    130  disableBorderAndPad();
    131 
    132  stageTransition();
    133 }
    134 
    135 // Stage 5 - Try to load a broken image
    136 function loadBrokenImage() {
    137  resetImage();
    138  testImageElem.src = baseURL + bogusFilename;
    139  stageTransition();
    140 }
    141 
    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 }
    148 
    149 // Stage 7 - Load the reference image for the test image
    150 function loadImageReference() {
    151  resetImage();
    152 
    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");};
    155 
    156  testImageElem.src = baseURL + imageFilename;
    157  stageTransition();
    158 }
    159 
    160 // Stage 8 - Draw the reference image for the test image to a canvas
    161 function drawImageReference() {
    162  drawWindowToCanvas("loadedReference");
    163  stageTransition();
    164 }
    165 
    166 // Stage 9 - Start a load of the test image from the delay-generating server
    167 function startServerLoad() {
    168 
    169  // Reset the image
    170  resetImage();
    171 
    172  // Debugging info so we can figure out the hang
    173  dump("test_bug507902.html DEBUG - starting server load\n");
    174 
    175  // Load the image
    176  testImageElem.src = baseURL + serverFilename;
    177  stageTransition();
    178 }
    179 
    180 // Stage 10 - Draw the screen to a canvas. This should hopefully be the loading
    181 // icon.
    182 function drawLoadingIcon() {
    183 
    184  // Debugging info so we can figure out the hang
    185  dump("test_bug507902.html DEBUG - drawing loading icon\n");
    186 
    187  drawWindowToCanvas("loadingIconTest");
    188  stageTransition();
    189 }
    190 
    191 // Stage 11 - Tell the server to continue.
    192 function signalServerContinue() {
    193 
    194  // Debugging info so we can figure out the hang
    195  dump("test_bug507902.html DEBUG - signaling server to continue\n");
    196 
    197  pingImage.src = baseURL + serverFilename + serverContinueFlag;
    198  stageTransition();
    199 }
    200 
    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 }
    207 
    208 
    209 // Stage 13 - Verify That the appropriate canvases match
    210 function verifyCanvases() {
    211 
    212  // Verify the broken icon
    213  ok(canvasesAreEqual("brokenIconTest", "brokenIconReference"),
    214     "Window drawn on broken load should match broken icon reference");
    215 
    216  // Verify the loading icon
    217  ok(canvasesAreEqual("loadingIconTest", "loadingIconReference"),
    218     "Window drawn mid-load should match loading icon reference");
    219 
    220  // Verify the loaded image
    221  ok(canvasesAreEqual("loadedTest", "loadedReference"),
    222     "Window drawn post-load should match reference image");
    223 
    224  stageTransition();
    225 }
    226 
    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;
    260 
    261 // Transition function called at the end of each stage
    262 function stageTransition() {
    263 
    264  // Debugging info so we can figure out the hang
    265  dump("test_bug507902.html DEBUG - Current Stage: " + currentStage + "\n");
    266 
    267  // What's our transition?
    268  var trans = testStages[currentStage++].trans;
    269 
    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  }
    276 
    277  // Otherwise, get the next function
    278  var nextfn = testStages[currentStage].fn;
    279 
    280  // Switch based on transition
    281  switch (trans) {
    282 
    283    // Continue right away
    284    case "instant":
    285      nextfn();
    286      break;
    287 
    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;
    292 
    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;
    297 
    298    // Timeout
    299    default:
    300      setTimeout(nextfn, trans);
    301      break
    302  }
    303 }
    304 
    305 // Lots if asynchronous behavior here
    306 SimpleTest.waitForExplicitFinish();
    307 
    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");
    310 
    311 // Kick off the test by invoking the first stage. The stages call each other
    312 testStages[0].fn();
    313 
    314 
    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 }
    324 
    325 //
    326 // Makes the canvases visible. Called before the tests finish. This is useful for
    327 // debugging.
    328 //
    329 function makeCanvasesVisible() {
    330  for (let 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 }
    340 
    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 }
    349 
    350 function disableBorderAndPad() {
    351  testImageElem.style.padding = 0;
    352  divContainer.style.border = "0px";
    353  divContainer.style.borderStyle = "";
    354 }
    355 
    356 //
    357 // Helper canvas methods. This is mostly copped directly from the reftest framework
    358 //
    359 
    360 function drawWindowToCanvas(canvasName) {
    361  var win = testFrameElem.contentWindow;
    362  let 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 }
    371 
    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 }
    378 
    379 </script>
    380 </pre>
    381 </body>
    382 </html>