Bug 1353005 - removed sdk/content/mod and replaced with DOMWindowUtils calls; r=pbro draft
authorMatteo Ferretti <mferretti@mozilla.com>
Tue, 18 Apr 2017 16:09:47 +0200
changeset 566466 78eb02dd28e4fe519fb83e1d24e9ea9158ebc0ee
parent 565181 56e6060973829ae7463ea251b33ea6a7aaaa8028
child 625325 c7120bbc386d6642f2b28db1082decbf334fbfb5
push id55226
push userbmo:zer0@mozilla.com
push dateFri, 21 Apr 2017 16:26:22 +0000
reviewerspbro
bugs1353005
milestone55.0a1
Bug 1353005 - removed sdk/content/mod and replaced with DOMWindowUtils calls; r=pbro MozReview-Commit-ID: 7aj8C0zYr6C
devtools/server/actors/highlighters/simple-outline.js
devtools/server/actors/highlighters/utils/markup.js
devtools/server/actors/inspector.js
devtools/server/actors/stylesheets.js
devtools/shared/layout/utils.js
--- a/devtools/server/actors/highlighters/simple-outline.js
+++ b/devtools/server/actors/highlighters/simple-outline.js
@@ -1,30 +1,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
-  installHelperSheet,
   isNodeValid,
   addPseudoClassLock,
   removePseudoClassLock
 } = require("./utils/markup");
 
+const { loadSheet } = require("devtools/shared/layout/utils");
+
 // SimpleOutlineHighlighter's stylesheet
 const HIGHLIGHTED_PSEUDO_CLASS = ":-moz-devtools-highlighted";
-const SIMPLE_OUTLINE_SHEET = `.__fx-devtools-hide-shortcut__ {
-                                visibility: hidden !important
-                              }
-                              ${HIGHLIGHTED_PSEUDO_CLASS} {
-                                outline: 2px dashed #F06!important;
-                                outline-offset: -2px!important
-                              }`;
+const SIMPLE_OUTLINE_SHEET = `data:text/css;charset=utf-8,
+  __fx-devtools-hide-shortcut__ {
+    visibility: hidden !important
+  }
+  ${HIGHLIGHTED_PSEUDO_CLASS} {
+    outline: 2px dashed #F06!important;
+    outline-offset: -2px!important
+  }`;
 /**
  * The SimpleOutlineHighlighter is a class that has the same API than the
  * BoxModelHighlighter, but adds a pseudo-class on the target element itself
  * to draw a simple css outline around the element.
  * It is used by the HighlighterActor when canvasframe-based highlighters can't
  * be used. This is the case for XUL windows.
  */
 function SimpleOutlineHighlighter(highlighterEnv) {
@@ -43,17 +45,17 @@ SimpleOutlineHighlighter.prototype = {
   /**
    * Show the highlighter on a given node
    * @param {DOMNode} node
    */
   show: function (node) {
     if (isNodeValid(node) && (!this.currentNode || node !== this.currentNode)) {
       this.hide();
       this.currentNode = node;
-      installHelperSheet(node.ownerGlobal, SIMPLE_OUTLINE_SHEET);
+      loadSheet(node.ownerGlobal, SIMPLE_OUTLINE_SHEET);
       addPseudoClassLock(node, HIGHLIGHTED_PSEUDO_CLASS);
     }
     return true;
   },
 
   /**
    * Hide the highlighter, the outline and the infobar.
    */
--- a/devtools/server/actors/highlighters/utils/markup.js
+++ b/devtools/server/actors/highlighters/utils/markup.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Cc, Ci, Cu } = require("chrome");
 const { getCurrentZoom, getWindowDimensions, getViewportDimensions,
-  getRootBindingParent } = require("devtools/shared/layout/utils");
+  getRootBindingParent, loadSheet } = require("devtools/shared/layout/utils");
 const { on, emit } = require("sdk/event/core");
 
 const lazyContainer = {};
 
 loader.lazyRequireGetter(lazyContainer, "CssLogic",
   "devtools/server/css-logic", true);
 exports.getComputedStyle = (node) =>
   lazyContainer.CssLogic.getComputedStyle(node);
@@ -97,33 +97,16 @@ ClassList.prototype = {
  * @return {Boolean}
  */
 function isXUL(window) {
   return window.document.documentElement.namespaceURI === XUL_NS;
 }
 exports.isXUL = isXUL;
 
 /**
- * Inject a helper stylesheet in the window.
- */
-var installedHelperSheets = new WeakMap();
-
-function installHelperSheet(win, source, type = "agent") {
-  if (installedHelperSheets.has(win.document)) {
-    return;
-  }
-  let {Style} = require("sdk/stylesheet/style");
-  let {attach} = require("sdk/content/mod");
-  let style = Style({source, type});
-  attach(style, win);
-  installedHelperSheets.set(win.document, style);
-}
-exports.installHelperSheet = installHelperSheet;
-
-/**
  * Returns true if a DOM node is "valid", where "valid" means that the node isn't a dead
  * object wrapper, is still attached to a document, and is of a given type.
  * @param {DOMNode} node
  * @param {Number} nodeType Optional, defaults to ELEMENT_NODE
  * @return {Boolean}
  */
 function isNodeValid(node, nodeType = Ci.nsIDOMNode.ELEMENT_NODE) {
   // Is it still alive?
@@ -273,25 +256,17 @@ CanvasFrameAnonymousContentHelper.protot
     if (isXUL(this.highlighterEnv.window)) {
       return;
     }
 
     // For now highlighters.css is injected in content as a ua sheet because
     // <style scoped> doesn't work inside anonymous content (see bug 1086532).
     // If it did, highlighters.css would be injected as an anonymous content
     // node using CanvasFrameAnonymousContentHelper instead.
-    if (!installedHelperSheets.has(doc)) {
-      installedHelperSheets.set(doc, true);
-      let source = "@import url('" + STYLESHEET_URI + "');";
-      let url = "data:text/css;charset=utf-8," + encodeURIComponent(source);
-      let winUtils = this.highlighterEnv.window
-                         .QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIDOMWindowUtils);
-      winUtils.loadSheetUsingURIString(url, winUtils.AGENT_SHEET);
-    }
+    loadSheet(this.highlighterEnv.window, STYLESHEET_URI);
 
     let node = this.nodeBuilder();
 
     // It was stated that hidden documents don't accept
     // `insertAnonymousContent` calls yet. That doesn't seems the case anymore,
     // at least on desktop. Therefore, removing the code that was dealing with
     // that scenario, fixes when we're adding anonymous content in a tab that
     // is not the active one (see bug 1260043 and bug 1260044)
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -67,17 +67,18 @@ const {
   HighlighterEnvironment
 } = require("devtools/server/actors/highlighters");
 const {EyeDropper} = require("devtools/server/actors/highlighters/eye-dropper");
 const {
   isAnonymous,
   isNativeAnonymous,
   isXBLAnonymous,
   isShadowAnonymous,
-  getFrameElement
+  getFrameElement,
+  loadSheet
 } = require("devtools/shared/layout/utils");
 const {getLayoutChangesObserver, releaseLayoutChangesObserver} = require("devtools/server/actors/reflow");
 const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
 const {colorUtils} = require("devtools/shared/css/color");
 
 const {EventParsers} = require("devtools/server/event-parsers");
 const {nodeSpec, nodeListSpec, walkerSpec, inspectorSpec} = require("devtools/shared/specs/inspector");
 
@@ -122,17 +123,17 @@ const PSEUDO_SELECTORS = [
   [":empty", 0],
   [":target", 0],
   [":enabled", 0],
   [":disabled", 0],
   [":checked", 1],
   ["::selection", 0]
 ];
 
-var HELPER_SHEET = `
+var HELPER_SHEET = `data:text/css;charset=utf-8,
   .__fx-devtools-hide-shortcut__ {
     visibility: hidden !important;
   }
 
   :-moz-devtools-highlighted {
     outline: 2px dashed #F06!important;
     outline-offset: -2px !important;
   }
@@ -1858,36 +1859,22 @@ var WalkerActor = protocol.ActorClassWit
       return false;
     }
     DOMUtils.addPseudoClassLock(node.rawNode, pseudo, enabled);
     this._activePseudoClassLocks.add(node);
     this._queuePseudoClassMutation(node);
     return true;
   },
 
-  _installHelperSheet: function (node) {
-    if (!this.installedHelpers) {
-      this.installedHelpers = new WeakMap();
-    }
-    let win = node.rawNode.ownerGlobal;
-    if (!this.installedHelpers.has(win)) {
-      let { Style } = require("sdk/stylesheet/style");
-      let { attach } = require("sdk/content/mod");
-      let style = Style({source: HELPER_SHEET, type: "agent" });
-      attach(style, win);
-      this.installedHelpers.set(win, style);
-    }
-  },
-
   hideNode: function (node) {
     if (isNodeDead(node)) {
       return;
     }
 
-    this._installHelperSheet(node);
+    loadSheet(node.rawNode.ownerGlobal, HELPER_SHEET);
     node.rawNode.classList.add(HIDDEN_CLASS);
   },
 
   unhideNode: function (node) {
     if (isNodeDead(node)) {
       return;
     }
 
--- a/devtools/server/actors/stylesheets.js
+++ b/devtools/server/actors/stylesheets.js
@@ -12,17 +12,17 @@ const {Task} = require("devtools/shared/
 const events = require("sdk/event/core");
 const protocol = require("devtools/shared/protocol");
 const {LongStringActor} = require("devtools/server/actors/string");
 const {fetch} = require("devtools/shared/DevToolsUtils");
 const {listenOnce} = require("devtools/shared/async-utils");
 const {originalSourceSpec, mediaRuleSpec, styleSheetSpec,
        styleSheetsSpec} = require("devtools/shared/specs/stylesheets");
 const {SourceMapConsumer} = require("source-map");
-const { installHelperSheet,
+const {
   addPseudoClassLock, removePseudoClassLock } = require("devtools/server/actors/highlighters/utils/markup");
 
 loader.lazyGetter(this, "CssLogic", () => require("devtools/shared/inspector/css-logic"));
 
 XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
 
--- a/devtools/shared/layout/utils.js
+++ b/devtools/shared/layout/utils.js
@@ -2,16 +2,22 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci, Cc } = require("chrome");
 const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
 
+const SHEET_TYPE = {
+  "agent": "AGENT_SHEET",
+  "user": "USER_SHEET",
+  "author": "AUTHOR_SHEET"
+};
+
 loader.lazyRequireGetter(this, "setIgnoreLayoutChanges", "devtools/server/actors/reflow", true);
 exports.setIgnoreLayoutChanges = (...args) =>
   this.setIgnoreLayoutChanges(...args);
 
 /**
  * Returns the `DOMWindowUtils` for the window given.
  *
  * @param {DOMWindow} win
@@ -710,8 +716,54 @@ function getWindowFor(node) {
       return node.defaultView;
     }
     return node.ownerDocument.defaultView;
   } else if (node instanceof Ci.nsIDOMWindow) {
     return node;
   }
   return null;
 }
+
+/**
+ * Synchronously loads a style sheet from `uri` and adds it to the list of
+ * additional style sheets of the document.
+ * The sheets added takes effect immediately, and only on the document of the
+ * `window` given.
+ *
+ * @param {DOMWindow} window
+ * @param {String} url
+ * @param {String} [type="agent"]
+ */
+function loadSheet(window, url, type = "agent") {
+  if (!(type in SHEET_TYPE)) {
+    type = "agent";
+  }
+
+  let windowUtils = utilsFor(window);
+  try {
+    windowUtils.loadSheetUsingURIString(url, windowUtils[SHEET_TYPE[type]]);
+  } catch (e) {
+    // The method fails if the url is already loaded.
+  }
+}
+exports.loadSheet = loadSheet;
+
+/**
+ * Remove the document style sheet at `sheetURI` from the list of additional
+ * style sheets of the document. The removal takes effect immediately.
+ *
+ * @param {DOMWindow} window
+ * @param {String} url
+ * @param {String} [type="agent"]
+ */
+function removeSheet(window, url, type = "agent") {
+  if (!(type in SHEET_TYPE)) {
+    type = "agent";
+  }
+
+  let windowUtils = utilsFor(window);
+  try {
+    windowUtils.removeSheetUsingURIString(url, windowUtils[SHEET_TYPE[type]]);
+  } catch (e) {
+    // The method fails if the url is already removed.
+  }
+}
+exports.removeSheet = removeSheet;