Bug 1171919 - Fix intermittent browser_styleeditor_bug_740541_iframes.js by keeping track of windows instead of documents. r=bgrins, a=ritu
authorSami Jaktholm <sjakthol@outlook.com>
Sun, 12 Jul 2015 11:20:22 +0300
changeset 281627 b0e1b21da2ff169e5a1de77aced8284de63781e2
parent 281626 7dd48c16b76bf82e070735192bd64d0d275f0f76
child 281628 c2a9f6033b62f32ed5495ec5bd66065c86b1228e
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgrins, ritu
bugs1171919
milestone41.0a2
Bug 1171919 - Fix intermittent browser_styleeditor_bug_740541_iframes.js by keeping track of windows instead of documents. r=bgrins, a=ritu When an iframe is created, it receives a dummy about:blank contentDocument with readyState == "uninitialized". When the frame starts to load, that dummy document is replaced with the real document. If the actor stored a reference to the dummy document it will either a) find no sheets or b) fail if the dummy document was already GC'd. These changes modify the actor to track the windows of the frames instead of their documents. If it encounters a window that has an uninitialized or still loading contentDocument it waits for the DOMContentLoaded event before taking a reference to the content document of the frame window.
toolkit/devtools/server/actors/stylesheets.js
--- a/toolkit/devtools/server/actors/stylesheets.js
+++ b/toolkit/devtools/server/actors/stylesheets.js
@@ -72,29 +72,31 @@ let StyleSheetsActor = exports.StyleShee
     this.parentActor = tabActor;
   },
 
   /**
    * Protocol method for getting a list of StyleSheetActors representing
    * all the style sheets in this document.
    */
   getStyleSheets: method(Task.async(function* () {
-    let documents = [this.document];
+    // Iframe document can change during load (bug 1171919). Track their windows
+    // instead.
+    let windows = [this.window];
     let actors = [];
 
-    for (let doc of documents) {
-      let sheets = yield this._addStyleSheets(doc);
+    for (let win of windows) {
+      let sheets = yield this._addStyleSheets(win);
       actors = actors.concat(sheets);
 
       // Recursively handle style sheets of the documents in iframes.
-      for (let iframe of doc.querySelectorAll("iframe, browser, frame")) {
-        if (iframe.contentDocument) {
+      for (let iframe of win.document.querySelectorAll("iframe, browser, frame")) {
+        if (iframe.contentDocument && iframe.contentWindow) {
           // Sometimes, iframes don't have any document, like the
           // one that are over deeply nested (bug 285395)
-          documents.push(iframe.contentDocument);
+          windows.push(iframe.contentWindow);
         }
       }
     }
     return actors;
   }), {
     request: {},
     response: { styleSheets: RetVal("array:stylesheet") }
   }),
@@ -117,31 +119,39 @@ let StyleSheetsActor = exports.StyleShee
     if (sheet.href && sheet.href.toLowerCase() == "about:preferencestylesheet") {
       return false;
     }
 
     return true;
   },
 
   /**
-   * Add all the stylesheets for this document to the map and create an actor
-   * for each one if not already created.
+   * Add all the stylesheets for the document in this window to the map and
+   * create an actor for each one if not already created.
    *
-   * @param {Document} doc
-   *        Document for which to add stylesheets
+   * @param {Window} win
+   *        Window for which to add stylesheets
    *
    * @return {Promise}
    *         Promise that resolves to an array of StyleSheetActors
    */
-  _addStyleSheets: function(doc)
+  _addStyleSheets: function(win)
   {
     return Task.spawn(function*() {
-      if (doc.readyState === "loading") {
+      let doc = win.document;
+      // readyState can be uninitialized if an iframe has just been created but
+      // it has not started to load yet.
+      if (doc.readyState === "loading" || doc.readyState === "uninitialized") {
         // Wait for the document to load first.
-        yield listenOnce(doc.defaultView, "DOMContentLoaded", true);
+        yield listenOnce(win, "DOMContentLoaded", true);
+
+        // Make sure we have the actual document for this window. If the
+        // readyState was initially uninitialized, the initial dummy document
+        // was replaced with the actual document (bug 1171919).
+        doc = win.document;
       }
 
       let isChrome = Services.scriptSecurityManager.isSystemPrincipal(doc.nodePrincipal);
       let styleSheets = isChrome ? DOMUtils.getAllStyleSheets(doc) : doc.styleSheets;
       let actors = [];
       for (let i = 0; i < styleSheets.length; i++) {
         let sheet = styleSheets[i];
         if (!this._shouldListSheet(doc, sheet)) {