summaryrefslogtreecommitdiffstats
path: root/devtools/server
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server')
-rw-r--r--devtools/server/actors/highlighters/box-model.js15
-rw-r--r--devtools/server/actors/stylesheets.js120
-rw-r--r--devtools/server/actors/webbrowser.js6
3 files changed, 105 insertions, 36 deletions
diff --git a/devtools/server/actors/highlighters/box-model.js b/devtools/server/actors/highlighters/box-model.js
index 35f201a04..ae4284424 100644
--- a/devtools/server/actors/highlighters/box-model.js
+++ b/devtools/server/actors/highlighters/box-model.js
@@ -15,7 +15,10 @@ const {
isNodeValid,
moveInfobar,
} = require("./utils/markup");
-const { setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
+const {
+ setIgnoreLayoutChanges,
+ getCurrentZoom,
+ } = require("devtools/shared/layout/utils");
const inspector = require("devtools/server/actors/inspector");
const nodeConstants = require("devtools/shared/dom-node-constants");
@@ -670,10 +673,14 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
pseudos += ":" + pseudo;
}
- let rect = this._getOuterQuad("border").bounds;
- let dim = parseFloat(rect.width.toPrecision(6)) +
+ // We want to display the original `width` and `height`, instead of the ones affected
+ // by any zoom. Since the infobar can be displayed also for text nodes, we can't
+ // access the computed style for that, and this is why we recalculate them here.
+ let zoom = getCurrentZoom(this.win);
+ let { width, height } = this._getOuterQuad("border").bounds;
+ let dim = parseFloat((width / zoom).toPrecision(6)) +
" \u00D7 " +
- parseFloat(rect.height.toPrecision(6));
+ parseFloat((height / zoom).toPrecision(6));
this.getElement("infobar-tagname").setTextContent(displayName);
this.getElement("infobar-id").setTextContent(id);
diff --git a/devtools/server/actors/stylesheets.js b/devtools/server/actors/stylesheets.js
index f20634e6c..7fcbca8c4 100644
--- a/devtools/server/actors/stylesheets.js
+++ b/devtools/server/actors/stylesheets.js
@@ -13,7 +13,6 @@ 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");
@@ -251,7 +250,7 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
},
destroy: function () {
- if (this._transitionTimeout) {
+ if (this._transitionTimeout && this.window) {
this.window.clearTimeout(this._transitionTimeout);
removePseudoClassLock(
this.document.documentElement, TRANSITION_PSEUDO_CLASS);
@@ -801,6 +800,64 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
protocol.Actor.prototype.initialize.call(this, null);
this.parentActor = tabActor;
+
+ this._onNewStyleSheetActor = this._onNewStyleSheetActor.bind(this);
+ this._onSheetAdded = this._onSheetAdded.bind(this);
+ this._onWindowReady = this._onWindowReady.bind(this);
+
+ events.on(this.parentActor, "stylesheet-added", this._onNewStyleSheetActor);
+ events.on(this.parentActor, "window-ready", this._onWindowReady);
+
+ // We listen for StyleSheetApplicableStateChanged rather than
+ // StyleSheetAdded, because the latter will be sent before the
+ // rules are ready. Using the former (with a check to ensure that
+ // the sheet is enabled) ensures that the sheet is ready before we
+ // try to make an actor for it.
+ this.parentActor.chromeEventHandler
+ .addEventListener("StyleSheetApplicableStateChanged", this._onSheetAdded, true);
+
+ // This is used when creating a new style sheet, so that we can
+ // pass the correct flag when emitting our stylesheet-added event.
+ // See addStyleSheet and _onNewStyleSheetActor for more details.
+ this._nextStyleSheetIsNew = false;
+ },
+
+ destroy: function () {
+ for (let win of this.parentActor.windows) {
+ // This flag only exists for devtools, so we are free to clear
+ // it when we're done.
+ win.document.styleSheetChangeEventsEnabled = false;
+ }
+
+ events.off(this.parentActor, "stylesheet-added", this._onNewStyleSheetActor);
+ events.off(this.parentActor, "window-ready", this._onWindowReady);
+
+ this.parentActor.chromeEventHandler.removeEventListener("StyleSheetAdded",
+ this._onSheetAdded, true);
+
+ protocol.Actor.prototype.destroy.call(this);
+ },
+
+ /**
+ * Event handler that is called when a the tab actor emits window-ready.
+ *
+ * @param {Event} evt
+ * The triggering event.
+ */
+ _onWindowReady: function (evt) {
+ this._addStyleSheets(evt.window);
+ },
+
+ /**
+ * Event handler that is called when a the tab actor emits stylesheet-added.
+ *
+ * @param {StyleSheetActor} actor
+ * The new style sheet actor.
+ */
+ _onNewStyleSheetActor: function (actor) {
+ // Forward it to the client side.
+ events.emit(this, "stylesheet-added", actor, this._nextStyleSheetIsNew);
+ this._nextStyleSheetIsNew = false;
},
/**
@@ -808,23 +865,11 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
* all the style sheets in this document.
*/
getStyleSheets: Task.async(function* () {
- // Iframe document can change during load (bug 1171919). Track their windows
- // instead.
- let windows = [this.window];
let actors = [];
- for (let win of windows) {
+ for (let win of this.parentActor.windows) {
let sheets = yield this._addStyleSheets(win);
actors = actors.concat(sheets);
-
- // Recursively handle style sheets of the documents in iframes.
- 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)
- windows.push(iframe.contentWindow);
- }
- }
}
return actors;
}),
@@ -832,15 +877,13 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
/**
* Check if we should be showing this stylesheet.
*
- * @param {Document} doc
- * Document for which we're checking
* @param {DOMCSSStyleSheet} sheet
* Stylesheet we're interested in
*
* @return boolean
* Whether the stylesheet should be listed.
*/
- _shouldListSheet: function (doc, sheet) {
+ _shouldListSheet: function (sheet) {
// Special case about:PreferenceStyleSheet, as it is generated on the
// fly and the URI is not registered with the about: handler.
// https://bugzilla.mozilla.org/show_bug.cgi?id=935803#c37
@@ -852,6 +895,22 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
},
/**
+ * Event handler that is called when a new style sheet is added to
+ * a document. In particular, StyleSheetApplicableStateChanged is
+ * listened for, because StyleSheetAdded is sent too early, before
+ * the rules are ready.
+ *
+ * @param {Event} evt
+ * The triggering event.
+ */
+ _onSheetAdded: function (evt) {
+ let sheet = evt.stylesheet;
+ if (this._shouldListSheet(sheet)) {
+ this.parentActor.createStyleSheetActor(sheet);
+ }
+ },
+
+ /**
* Add all the stylesheets for the document in this window to the map and
* create an actor for each one if not already created.
*
@@ -865,24 +924,16 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
{
return Task.spawn(function* () {
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(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;
- }
+ // We have to set this flag in order to get the
+ // StyleSheetApplicableStateChanged events. See Document.webidl.
+ doc.styleSheetChangeEventsEnabled = true;
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)) {
+ if (!this._shouldListSheet(sheet)) {
continue;
}
@@ -917,7 +968,7 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
if (rule.type == Ci.nsIDOMCSSRule.IMPORT_RULE) {
// Associated styleSheet may be null if it has already been seen due
// to duplicate @imports for the same URL.
- if (!rule.styleSheet || !this._shouldListSheet(doc, rule.styleSheet)) {
+ if (!rule.styleSheet || !this._shouldListSheet(rule.styleSheet)) {
continue;
}
let actor = this.parentActor.createStyleSheetActor(rule.styleSheet);
@@ -948,6 +999,13 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
* Object with 'styelSheet' property for form on new actor.
*/
addStyleSheet: function (text) {
+ // This is a bit convoluted. The style sheet actor may be created
+ // by a notification from platform. In this case, we can't easily
+ // pass the "new" flag through to createStyleSheetActor, so we set
+ // a flag locally and check it before sending an event to the
+ // client. See |_onNewStyleSheetActor|.
+ this._nextStyleSheetIsNew = true;
+
let parent = this.document.documentElement;
let style = this.document.createElementNS("http://www.w3.org/1999/xhtml", "style");
style.setAttribute("type", "text/css");
diff --git a/devtools/server/actors/webbrowser.js b/devtools/server/actors/webbrowser.js
index 1808895b1..dffe49b91 100644
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -2501,7 +2501,11 @@ DebuggerProgressListener.prototype = {
if (isWindow && isStop) {
// Don't dispatch "navigate" event just yet when there is a redirect to
// about:neterror page.
- if (request.status != Cr.NS_OK) {
+ // Navigating to about:neterror will make `status` be something else than NS_OK.
+ // But for some error like NS_BINDING_ABORTED we don't want to emit any `navigate`
+ // event as the page load has been cancelled and the related page document is going
+ // to be a dead wrapper.
+ if (request.status != Cr.NS_OK && request.status != Cr.NS_BINDING_ABORTED) {
// Instead, listen for DOMContentLoaded as about:neterror is loaded
// with LOAD_BACKGROUND flags and never dispatches load event.
// That may be the same reason why there is no onStateChange event