Backed out 6 changesets (bug 1625930) for test_eventemitter_basic.js failures CLOSED TREE

Backed out changeset 30a3da9f613c (bug 1625930)
Backed out changeset d4e4c3ddcc43 (bug 1625930)
Backed out changeset 0133d9c58323 (bug 1625930)
Backed out changeset 1c9cf53f2a89 (bug 1625930)
Backed out changeset f63839eff636 (bug 1625930)
Backed out changeset a6bef105a2c2 (bug 1625930)
This commit is contained in:
Bogdan Tara 2020-07-08 18:08:27 +03:00
Родитель 03b956b20d
Коммит 75881e8400
25 изменённых файлов: 200 добавлений и 584 удалений

Просмотреть файл

@ -27,6 +27,7 @@ class SourceMapURLService {
this._pendingURLSubscriptions = new Map();
this._urlToIDMap = new Map();
this._mapsById = new Map();
this._listeningStylesheetFront = null;
this._sourcesLoading = null;
this._runningCallback = false;
@ -204,16 +205,13 @@ class SourceMapURLService {
this._pendingURLSubscriptions.clear();
this._urlToIDMap.clear();
try {
this._toolbox.resourceWatcher.unwatchResources(
[this._toolbox.resourceWatcher.TYPES.STYLESHEET],
{ onAvailable: this._onResourceAvailable }
if (this._listeningStylesheetFront) {
this._listeningStylesheetFront.off(
"stylesheet-added",
this._onNewStyleSheet
);
} catch (e) {
// If unwatchResources is called before finishing process of watchResources,
// it throws an error during stopping listener.
this._listeningStylesheetFront = null;
}
this._sourcesLoading = null;
}
@ -428,17 +426,39 @@ class SourceMapURLService {
return;
}
this._onResourceAvailable = async ({ resource }) => {
if (this._sourcesLoading === sourcesLoading) {
this._onNewStyleSheet(resource.styleSheet);
}
};
await Promise.all([
this._toolbox.resourceWatcher.watchResources(
[this._toolbox.resourceWatcher.TYPES.STYLESHEET],
{ onAvailable: this._onResourceAvailable }
),
(async () => {
if (!this._target.hasActor("styleSheets")) {
return;
}
try {
const front = await this._target.getFront("stylesheets");
if (this._listeningStylesheetFront) {
this._listeningStylesheetFront.off(
"stylesheet-added",
this._onNewStyleSheet
);
}
this._listeningStylesheetFront = front;
this._listeningStylesheetFront.on(
"stylesheet-added",
this._onNewStyleSheet
);
const sheets = await front.getStyleSheets();
if (this._sourcesLoading === sourcesLoading) {
// If we've cleared the state since starting this request,
// we don't want to populate these.
for (const sheet of sheets) {
this._onNewStyleSheet(sheet);
}
}
} catch (err) {
// Ignore any protocol-based errors.
}
})(),
(async () => {
const { threadFront } = this._toolbox;
if (!threadFront) {

Просмотреть файл

@ -89,8 +89,16 @@ function StyleEditorUI(toolbox, panelDoc, cssProperties) {
this.savedLocations = {};
this._seenSheets = new Map();
// Don't add any style sheets that might arrive via events, until
// the call to initialize. Style sheets can arrive from the server
// at any time, for example if a new style sheet was added, or if
// the style sheet actor was just created and is walking the style
// sheets for the first time. In any case, in |initialize| we're
// going to fetch the list of sheets anyway.
this._suppressAdd = true;
this._onOptionsButtonClick = this._onOptionsButtonClick.bind(this);
this._onOrigSourcesPrefChanged = this._onOrigSourcesPrefChanged.bind(this);
this._onNewDocument = this._onNewDocument.bind(this);
this._onMediaPrefChanged = this._onMediaPrefChanged.bind(this);
this._updateMediaList = this._updateMediaList.bind(this);
this._clear = this._clear.bind(this);
@ -98,18 +106,16 @@ function StyleEditorUI(toolbox, panelDoc, cssProperties) {
this._updateContextMenuItems = this._updateContextMenuItems.bind(this);
this._openLinkNewTab = this._openLinkNewTab.bind(this);
this._copyUrl = this._copyUrl.bind(this);
this._addStyleSheet = this._addStyleSheet.bind(this);
this._onTargetAvailable = this._onTargetAvailable.bind(this);
this._onResourceAvailable = this._onResourceAvailable.bind(this);
this._onTargetDestroyed = this._onTargetDestroyed.bind(this);
this._prefObserver = new PrefObserver("devtools.styleeditor.");
this._prefObserver.on(PREF_MEDIA_SIDEBAR, this._onMediaPrefChanged);
this._sourceMapPrefObserver = new PrefObserver(
"devtools.source-map.client-service."
);
this._sourceMapPrefObserver.on(
PREF_ORIG_SOURCES,
this._onOrigSourcesPrefChanged
);
this._sourceMapPrefObserver.on(PREF_ORIG_SOURCES, this._onNewDocument);
}
StyleEditorUI.prototype = {
@ -138,20 +144,9 @@ StyleEditorUI.prototype = {
await this._toolbox.targetList.watchTargets(
[this._toolbox.targetList.TYPES.FRAME],
this._onTargetAvailable
this._onTargetAvailable,
this._onTargetDestroyed
);
await this._toolbox.resourceWatcher.watchResources(
[this._toolbox.resourceWatcher.TYPES.DOCUMENT_EVENT],
{ onAvailable: this._onResourceAvailable }
);
this._startLoadingStyleSheets();
await this._toolbox.resourceWatcher.watchResources(
[this._toolbox.resourceWatcher.TYPES.STYLESHEET],
{ onAvailable: this._onResourceAvailable }
);
await this._waitForLoadingStyleSheets();
},
async initializeHighlighter(targetFront) {
@ -244,22 +239,41 @@ StyleEditorUI.prototype = {
},
/**
* Be called when changing the original sources pref.
* Refresh editors to reflect the stylesheets in the document.
*/
async _onOrigSourcesPrefChanged() {
this._clear();
// When we toggle the source-map preference, we clear the panel and re-fetch the exact
// same stylesheet resources from ResourceWatcher, but `_addStyleSheet` will trigger
// or ignore the additional source-map mapping.
this._root.classList.add("loading");
for (const resource of this._toolbox.resourceWatcher.getAllResources(
this._toolbox.resourceWatcher.TYPES.STYLESHEET
)) {
await this._handleStyleSheetResource(resource);
async _onNewDocument() {
this._suppressAdd = true;
try {
const stylesheetsFront = await this.currentTarget.getFront("stylesheets");
const styleSheets = await stylesheetsFront.getStyleSheets();
await this._resetStyleSheetList(styleSheets);
} catch (e) {
console.error(e);
}
},
/**
* Add editors for all the given stylesheets to the UI.
*
* @param {array} styleSheets
* Array of StyleSheetFront
*/
async _resetStyleSheetList(styleSheets) {
this._clear();
this._suppressAdd = false;
for (const sheet of styleSheets) {
try {
await this._addStyleSheet(sheet);
} catch (e) {
console.error(e);
this.emit("error", { key: LOAD_ERROR, level: "warning" });
}
}
this._root.classList.remove("loading");
this.emit("stylesheets-refreshed");
this.emit("stylesheets-reset");
},
/**
@ -293,8 +307,9 @@ StyleEditorUI.prototype = {
// Here the keys are style sheet actors, and the values are
// promises that resolve to the sheet's editor. See |_addStyleSheet|.
this._seenSheets = new Map();
this._suppressAdd = true;
this.emit("stylesheets-clear");
this._root.classList.add("loading");
},
/**
@ -312,6 +327,10 @@ StyleEditorUI.prototype = {
* is enabled, then the promise resolves to null.
*/
_addStyleSheet: function(styleSheet, isNew) {
if (this._suppressAdd) {
return null;
}
if (!this._seenSheets.has(styleSheet)) {
const promise = (async () => {
let editor = await this._addStyleSheetEditor(styleSheet, isNew);
@ -474,10 +493,12 @@ StyleEditorUI.prototype = {
);
stream.close();
this._suppressAdd = true;
const stylesheetsFront = await this.currentTarget.getFront(
"stylesheets"
);
const styleSheet = await stylesheetsFront.addStyleSheet(source);
this._suppressAdd = false;
const editor = await this._addStyleSheet(styleSheet, true);
if (editor) {
editor.savedFile = selectedFile;
@ -1154,96 +1175,50 @@ StyleEditorUI.prototype = {
this.selectStyleSheet(source, location.line - 1, location.column - 1);
},
_startLoadingStyleSheets() {
this._root.classList.add("loading");
this._loadingStyleSheets = [];
},
async _waitForLoadingStyleSheets() {
while (this._loadingStyleSheets?.length > 0) {
const pending = this._loadingStyleSheets;
this._loadingStyleSheets = [];
await Promise.all(pending);
}
this._loadingStyleSheets = null;
this._root.classList.remove("loading");
},
async _handleStyleSheetResource({ styleSheet, isNew }) {
try {
await this._addStyleSheet(styleSheet, isNew);
} catch (e) {
console.error(e);
this.emit("error", { key: LOAD_ERROR, level: "warning" });
}
},
async _onResourceAvailable({ targetFront, resource }) {
if (
resource.resourceType === this._toolbox.resourceWatcher.TYPES.STYLESHEET
) {
const onStyleSheetHandled = this._handleStyleSheetResource(resource);
if (this._loadingStyleSheets) {
// In case of reloading/navigating and panel's opening
this._loadingStyleSheets.push(onStyleSheetHandled);
}
await onStyleSheetHandled;
return;
}
if (!resource.targetFront.isTopLevel) {
return;
}
if (resource.name === "dom-loading") {
// will-navigate doesn't work when we navigate to a new process,
// and for now, onTargetAvailable/onTargetDestroyed doesn't fire on navigation and
// only when navigating to another process.
// So we fallback on DOCUMENT_EVENTS to be notified when we navigates. When we
// navigate within the same process as well as when we navigate to a new process.
// (We would probably revisit that in bug 1632141)
this._startLoadingStyleSheets();
this._clear();
} else if (resource.name === "dom-complete") {
await this._waitForLoadingStyleSheets();
}
},
async _onTargetAvailable({ targetFront }) {
if (targetFront.isTopLevel) {
await this.initializeHighlighter(targetFront);
const stylesheetsFront = await targetFront.getFront("stylesheets");
stylesheetsFront.on("stylesheet-added", this._addStyleSheet);
targetFront.on("will-navigate", this._clear);
targetFront.on("navigate", this._onNewDocument);
await this._onNewDocument();
}
},
async _onTargetDestroyed({ targetFront }) {
if (targetFront.isTopLevel) {
this._clear();
}
},
destroy: function() {
this._toolbox.targetList.unwatchTargets(
[this._toolbox.targetList.TYPES.FRAME],
this._onTargetAvailable
this._onTargetAvailable,
this._onTargetDestroyed
);
this._toolbox.resourceWatcher.unwatchResources(
[
this._toolbox.resourceWatcher.TYPES.DOCUMENT_EVENT,
this._toolbox.resourceWatcher.TYPES.STYLESHEET,
],
{ onAvailable: this._onResourceAvailable }
);
this.currentTarget.off("will-navigate", this._clear);
this.currentTarget.off("navigate", this._onNewDocument);
const stylesheetsFront = this.currentTarget.getCachedFront("stylesheets");
if (stylesheetsFront) {
stylesheetsFront.off("stylesheet-added", this._addStyleSheet);
}
this._clearStyleSheetEditors();
this._seenSheets = null;
this._suppressAdd = false;
const sidebar = this._panelDoc.querySelector(".splitview-controller");
const sidebarWidth = sidebar.getAttribute("width");
Services.prefs.setIntPref(PREF_NAV_WIDTH, sidebarWidth);
this._sourceMapPrefObserver.off(
PREF_ORIG_SOURCES,
this._onOrigSourcesPrefChanged
);
this._sourceMapPrefObserver.off(PREF_ORIG_SOURCES, this._onNewDocument);
this._sourceMapPrefObserver.destroy();
this._prefObserver.off(PREF_MEDIA_SIDEBAR, this._onMediaPrefChanged);
this._prefObserver.destroy();

Просмотреть файл

@ -22,21 +22,21 @@ const DOCUMENT_WITH_ONE_STYLESHEET =
add_task(async function() {
const { ui } = await openStyleEditorForURL(DOCUMENT_WITH_ONE_STYLESHEET);
// Spam the _onOrigSourcesPrefChanged callback multiple times before the
// Spam the _onNewDocument callback multiple times before the
// StyleEditorActor has a chance to respond to the first one.
const SPAM_COUNT = 2;
for (let i = 0; i < SPAM_COUNT; ++i) {
ui._onOrigSourcesPrefChanged();
ui._onNewDocument();
}
// Wait for the StyleEditorActor to respond to each "onOrigSourcesPrefChanged"
// Wait for the StyleEditorActor to respond to each "newDocument"
// message.
await new Promise(resolve => {
let loadCount = 0;
ui.on("stylesheets-refreshed", function onReset() {
ui.on("stylesheets-reset", function onReset() {
++loadCount;
if (loadCount == SPAM_COUNT) {
ui.off("stylesheets-refreshed", onReset);
ui.off("stylesheets-reset", onReset);
// No matter how large SPAM_COUNT is, the number of style
// sheets should never be more than the number of style sheets
// in the document.

Просмотреть файл

@ -15,15 +15,18 @@ add_task(async function() {
// switch, with or without fission.
info("Open a page that runs in the parent process");
const { ui } = await openStyleEditorForURL(PARENT_PROCESS_URI);
const { toolbox, ui } = await openStyleEditorForURL(PARENT_PROCESS_URI);
await waitUntil(() => ui.editors.length === 3);
ok(true, `Three style sheets for ${PARENT_PROCESS_URI}`);
info("Navigate to a page that runs in the child process");
const onEditorReady = ui.editors[0].getSourceEditor();
await navigateToAndWaitForStyleSheets(CONTENT_PROCESS_URI, ui, 2);
const onTargetSwitched = toolbox.once("switched-target");
await navigateToAndWaitForStyleSheets(CONTENT_PROCESS_URI, ui);
// We also have to wait for the toolbox to complete the target switching
// in order to avoid pending requests during test teardown.
await onTargetSwitched;
await waitUntil(() => ui.editors.length === 2);
ok(true, `Two sheets present for ${CONTENT_PROCESS_URI}`);
info("Wait until the editor is ready");

Просмотреть файл

@ -16,9 +16,9 @@ add_task(async function() {
await saveFirstInlineStyleSheet(ui);
await testFriendlyNamesAfterSave(ui);
await reloadPageAndWaitForStyleSheets(ui, 2);
await reloadPageAndWaitForStyleSheets(ui);
await testFriendlyNamesAfterSave(ui);
await navigateToAndWaitForStyleSheets(SECOND_TEST_PAGE, ui, 2);
await navigateToAndWaitForStyleSheets(SECOND_TEST_PAGE, ui);
await testFriendlyNamesAfterNavigation(ui);
});

Просмотреть файл

@ -18,7 +18,7 @@ add_task(async function() {
info("Selecting the second editor");
await ui.selectStyleSheet(ui.editors[1].styleSheet, LINE_NO, COL_NO);
await navigateToAndWaitForStyleSheets(NEW_URI, ui, 2);
await navigateToAndWaitForStyleSheets(NEW_URI, ui);
info("Waiting for source editor to be ready.");
await ui.editors[0].getSourceEditor();

Просмотреть файл

@ -16,27 +16,21 @@ add_task(async function() {
info("Selecting the second editor");
await ui.selectStyleSheet(ui.editors[1].styleSheet, LINE_NO, COL_NO);
const selectedStyleSheetIndex = ui.editors[1].styleSheet.styleSheetIndex;
await reloadPageAndWaitForStyleSheets(ui, 2);
await reloadPageAndWaitForStyleSheets(ui);
is(ui.editors.length, 2, "Two sheets present after reload.");
info("Waiting for source editor to be ready.");
const newEditor = findEditor(ui, selectedStyleSheetIndex);
await newEditor.getSourceEditor();
await ui.editors[1].getSourceEditor();
is(
ui.selectedEditor,
newEditor,
"Editor of stylesheet that has styleSheetIndex we selected is selected after reload"
ui.editors[1],
"second editor is selected after reload"
);
const { line, ch } = ui.selectedEditor.sourceEditor.getCursor();
is(line, LINE_NO, "correct line selected");
is(ch, COL_NO, "correct column selected");
});
function findEditor(ui, styleSheetIndex) {
return ui.editors.find(
editor => editor.styleSheet.styleSheetIndex === styleSheetIndex
);
}

Просмотреть файл

@ -127,7 +127,7 @@ function testEditor(editor, possibleNames) {
/* Helpers */
function togglePref(UI) {
const editorsPromise = UI.once("stylesheets-refreshed");
const editorsPromise = UI.once("stylesheets-reset");
const selectedPromise = UI.once("editor-selected");
Services.prefs.setBoolPref(PREF, false);

Просмотреть файл

@ -64,7 +64,7 @@ async function testEditor(editor, expectedName, expectedText) {
/* Helpers */
function togglePref(UI) {
const editorsPromise = UI.once("stylesheets-refreshed");
const editorsPromise = UI.once("stylesheets-reset");
const selectedPromise = UI.once("editor-selected");
Services.prefs.setBoolPref(PREF, false);

Просмотреть файл

@ -46,22 +46,19 @@ var addTab = function(url, win) {
});
};
var navigateToAndWaitForStyleSheets = async function(url, ui, editorCount) {
const onClear = ui.once("stylesheets-clear");
var navigateToAndWaitForStyleSheets = async function(url, ui) {
const onReset = ui.once("stylesheets-reset");
await navigateTo(url);
await onClear;
await waitUntil(() => ui.editors.length === editorCount);
await onReset;
};
var reloadPageAndWaitForStyleSheets = async function(ui, editorCount) {
var reloadPageAndWaitForStyleSheets = async function(ui) {
info("Reloading the page.");
const onClear = ui.once("stylesheets-clear");
const onReset = ui.once("stylesheets-reset");
const browser = gBrowser.selectedBrowser;
await SpecialPowers.spawn(browser, [], () => content.location.reload());
await onClear;
await waitUntil(() => ui.editors.length === editorCount);
await onReset;
};
/**

Просмотреть файл

@ -651,17 +651,22 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
this.parentActor = targetActor;
this._onApplicableStateChanged = this._onApplicableStateChanged.bind(this);
this._onNewStyleSheetActor = this._onNewStyleSheetActor.bind(this);
this._onSheetAdded = this._onSheetAdded.bind(this);
this._onWindowReady = this._onWindowReady.bind(this);
this._transitionSheetLoaded = false;
this.parentActor.on("stylesheet-added", this._onNewStyleSheetActor);
this.parentActor.on("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._onApplicableStateChanged,
this._onSheetAdded,
true
);
@ -683,7 +688,7 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
this.parentActor.chromeEventHandler.removeEventListener(
"StyleSheetApplicableStateChanged",
this._onApplicableStateChanged,
this._onSheetAdded,
true
);
@ -740,7 +745,10 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
// 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
if (sheet.href?.toLowerCase() === "about:preferencestylesheet") {
if (
sheet.href &&
sheet.href.toLowerCase() == "about:preferencestylesheet"
) {
return false;
}
@ -748,32 +756,18 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
},
/**
* Event handler that is called when the state of applicable of style sheet is changed.
* 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.
*
* For now, StyleSheetApplicableStateChanged event will be called at following timings.
* - Append <link> of stylesheet to document
* - Append <style> to document
* - Change disable attribute of stylesheet object
* - Change disable attribute of <link> to false
* When appending <link>, <style> or changing `disable` attribute to false, `applicable`
* is passed as true. The other hand, when changing `disable` to true, this will be
* false.
* NOTE: For now, StyleSheetApplicableStateChanged will not be called when removing the
* link and style element.
*
* @param {StyleSheetApplicableStateChanged}
* @param {Event} evt
* The triggering event.
*/
_onApplicableStateChanged: function({ applicable, stylesheet }) {
if (
// Have interest in applicable stylesheet only.
applicable &&
// No ownerNode means that this stylesheet is *not* associated to a DOM Element.
stylesheet.ownerNode &&
this._shouldListSheet(stylesheet) &&
!this._haveAncestorWithSameURL(stylesheet)
) {
this.parentActor.createStyleSheetActor(stylesheet);
_onSheetAdded: function(evt) {
const sheet = evt.stylesheet;
if (this._shouldListSheet(sheet) && !this._haveAncestorWithSameURL(sheet)) {
this.parentActor.createStyleSheetActor(sheet);
}
},

Просмотреть файл

@ -333,10 +333,6 @@ class EventEmitter {
EventEmitter.emit(this, ...args);
}
}
count(...args) {
return EventEmitter.count(this, ...args);
}
}
module.exports = EventEmitter;

Просмотреть файл

@ -9,5 +9,4 @@ DevToolsModules(
'error-messages.js',
'platform-messages.js',
'root-node.js',
'stylesheet.js',
)

Просмотреть файл

@ -1,39 +0,0 @@
/* 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 {
ResourceWatcher,
} = require("devtools/shared/resources/resource-watcher");
module.exports = async function({ targetFront, onAvailable }) {
if (!targetFront.hasActor("styleSheets")) {
return;
}
const styleSheetsFront = await targetFront.getFront("stylesheets");
try {
const styleSheets = await styleSheetsFront.getStyleSheets();
onAvailable(styleSheets.map(styleSheet => toResource(styleSheet, false)));
styleSheetsFront.on("stylesheet-added", (styleSheet, isNew) => {
onAvailable([toResource(styleSheet, isNew)]);
});
} catch (e) {
// There are cases that the stylesheet front was destroyed already when/while calling
// methods of stylesheet.
// Especially, since source map url service starts to watch the stylesheet resources
// lazily, the possibility will be extended.
console.warn("fetching stylesheets failed", e);
}
};
function toResource(styleSheet, isNew) {
return {
resourceType: ResourceWatcher.TYPES.STYLESHEET,
styleSheet,
isNew,
};
}

Просмотреть файл

@ -41,16 +41,6 @@ class ResourceWatcher {
this._listenerCount = new Map();
}
/**
* Return all specified resources cached in this watcher.
*
* @param {String} resourceType
* @return {Array} resources cached in this watcher
*/
getAllResources(resourceType) {
return this._cache.filter(r => r.resourceType === resourceType);
}
/**
* Request to start retrieving all already existing instances of given
* type of resources and also start watching for the one to be created after.
@ -70,11 +60,7 @@ class ResourceWatcher {
* existing resources.
*/
async watchResources(resources, options) {
const {
onAvailable,
onDestroyed,
ignoreExistingResources = false,
} = options;
const { onAvailable, ignoreExistingResources = false } = options;
// Cache the Watcher once for all, the first time we call `watch()`.
// This `watcher` attribute may be then used in any function of the ResourceWatcher after this.
@ -99,16 +85,8 @@ class ResourceWatcher {
await this._watchAllTargets();
for (const resource of resources) {
// If we are registering the first listener, so start listening from the server about
// this one resource.
if (this._availableListeners.count(resource) === 0) {
await this._startListening(resource);
}
this._availableListeners.on(resource, onAvailable);
if (onDestroyed) {
this._destroyedListeners.on(resource, onDestroyed);
}
await this._startListening(resource);
this._registerListeners(resource, options);
}
if (!ignoreExistingResources) {
@ -124,24 +102,16 @@ class ResourceWatcher {
const { onAvailable, onDestroyed } = options;
for (const resource of resources) {
this._availableListeners.off(resource, onAvailable);
if (onDestroyed) {
this._destroyedListeners.off(resource, onDestroyed);
}
const hadAtLeastOneListener =
this._availableListeners.count(resource) > 0;
this._availableListeners.off(resource, onAvailable);
if (
hadAtLeastOneListener &&
this._availableListeners.count(resource) === 0
) {
this._stopListening(resource);
}
this._stopListening(resource);
}
// Stop watching for targets if we removed the last listener.
let listeners = 0;
for (const count of this._listenerCount.values()) {
for (const count of this._listenerCount) {
listeners += count;
}
if (listeners <= 0) {
@ -149,6 +119,20 @@ class ResourceWatcher {
}
}
/**
* Register listeners to watch for a given type of resource.
*
* @param {Object}
* - {Function} onAvailable: mandatory
* - {Function} onDestroyed: optional
*/
_registerListeners(resource, { onAvailable, onDestroyed }) {
this._availableListeners.on(resource, onAvailable);
if (onDestroyed) {
this._destroyedListeners.on(resource, onDestroyed);
}
}
/**
* Start watching for all already existing and future targets.
*
@ -455,7 +439,6 @@ ResourceWatcher.TYPES = ResourceWatcher.prototype.TYPES = {
PLATFORM_MESSAGE: "platform-message",
DOCUMENT_EVENT: "document-event",
ROOT_NODE: "root-node",
STYLESHEET: "stylesheet",
};
module.exports = { ResourceWatcher };
@ -492,8 +475,6 @@ const LegacyListeners = {
},
[ResourceWatcher.TYPES
.ROOT_NODE]: require("devtools/shared/resources/legacy-listeners/root-node"),
[ResourceWatcher.TYPES
.STYLESHEET]: require("devtools/shared/resources/legacy-listeners/stylesheet"),
};
// Optional transformers for each type of resource.

Просмотреть файл

@ -8,10 +8,6 @@ support-files =
head.js
fission_document.html
fission_iframe.html
style_document.css
style_document.html
style_iframe.css
style_iframe.html
test_service_worker.js
test_sw_page.html
test_sw_page_worker.js
@ -23,11 +19,9 @@ support-files =
[browser_resources_css_messages.js]
[browser_resources_document_events.js]
[browser_resources_error_messages.js]
[browser_resources_getAllResources.js]
[browser_resources_platform_messages.js]
[browser_resources_root_node.js]
[browser_resources_several_resources.js]
[browser_resources_stylesheets.js]
[browser_resources_target_destroy.js]
[browser_target_list_frames.js]
[browser_target_list_getAllTargets.js]

Просмотреть файл

@ -1,103 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test getAllResources function of the ResourceWatcher.
const {
ResourceWatcher,
} = require("devtools/shared/resources/resource-watcher");
const TEST_URI = "data:text/html;charset=utf-8,getAllResources test";
add_task(async function() {
const tab = await addTab(TEST_URI);
const {
client,
resourceWatcher,
targetList,
} = await initResourceWatcherAndTarget(tab);
info("Check the resources gotten from getAllResources at initial");
is(
resourceWatcher.getAllResources(ResourceWatcher.TYPES.CONSOLE_MESSAGE),
0,
"There is no resources at initial"
);
info(
"Start to watch the available resources in order to compare with resources gotten from getAllResources"
);
const availableResources = [];
const onAvailable = ({ resource }) => availableResources.push(resource);
await resourceWatcher.watchResources(
[ResourceWatcher.TYPES.CONSOLE_MESSAGE],
{ onAvailable }
);
info("Check the resources after some resources are available");
const messages = ["a", "b", "c"];
await logMessages(tab.linkedBrowser, messages);
await waitUntil(() => availableResources.length === messages.length);
assertResources(
resourceWatcher.getAllResources(ResourceWatcher.TYPES.CONSOLE_MESSAGE),
availableResources
);
assertResources(
resourceWatcher.getAllResources(ResourceWatcher.TYPES.STYLESHEET),
[]
);
info("Check the resources after reloading");
const onReloaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
gBrowser.reloadTab(tab);
await onReloaded;
assertResources(
resourceWatcher.getAllResources(ResourceWatcher.TYPES.CONSOLE_MESSAGE),
[]
);
info("Append some resources again to test unwatching");
await logMessages(tab.linkedBrowser, messages);
await waitUntil(
() =>
resourceWatcher.getAllResources(ResourceWatcher.TYPES.CONSOLE_MESSAGE)
.length === messages.length
);
info("Check the resources after unwatching");
resourceWatcher.unwatchResources([ResourceWatcher.TYPES.CONSOLE_MESSAGE], {
onAvailable,
});
assertResources(
resourceWatcher.getAllResources(ResourceWatcher.TYPES.CONSOLE_MESSAGE),
[]
);
await targetList.stopListening();
await client.close();
});
function assertResources(resources, expectedResources) {
is(
resources.length,
expectedResources.length,
"Number of the resources is correct"
);
for (let i = 0; i < resources.length; i++) {
const resource = resources[i];
const expectedResource = expectedResources[i];
ok(resource === expectedResource, `The ${i}th resource is correct`);
}
}
function logMessages(browser, messages) {
return ContentTask.spawn(browser, { messages }, args => {
for (const message of args.messages) {
content.console.log(message);
}
});
}

Просмотреть файл

@ -1,148 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test the ResourceWatcher API around STYLESHEET.
const {
ResourceWatcher,
} = require("devtools/shared/resources/resource-watcher");
const STYLE_TEST_URL = URL_ROOT_SSL + "style_document.html";
const EXISTING_RESOURCES = [
{
styleText: "body { color: lime; }",
href: null,
nodeHref:
"https://example.com/browser/devtools/shared/resources/tests/style_document.html",
isNew: false,
},
{
styleText: "body { margin: 1px; }",
href:
"https://example.com/browser/devtools/shared/resources/tests/style_document.css",
nodeHref:
"https://example.com/browser/devtools/shared/resources/tests/style_document.html",
isNew: false,
},
{
styleText: "body { background-color: pink; }",
href: null,
nodeHref:
"https://example.org/browser/devtools/shared/resources/tests/style_iframe.html",
isNew: false,
},
{
styleText: "body { padding: 1px; }",
href:
"https://example.org/browser/devtools/shared/resources/tests/style_iframe.css",
nodeHref:
"https://example.org/browser/devtools/shared/resources/tests/style_iframe.html",
isNew: false,
},
];
const ADDITIONAL_RESOURCE = {
styleText: "body { font-size: 10px; }",
href: null,
nodeHref:
"https://example.com/browser/devtools/shared/resources/tests/style_document.html",
isNew: false,
};
const ADDITIONAL_FROM_ACTOR_RESOURCE = {
styleText: "body { font-size: 10px; }",
href: null,
nodeHref:
"https://example.com/browser/devtools/shared/resources/tests/style_document.html",
isNew: true,
};
add_task(async function() {
const tab = await addTab(STYLE_TEST_URL);
const {
client,
resourceWatcher,
targetList,
} = await initResourceWatcherAndTarget(tab);
info("Check whether ResourceWatcher gets existing stylesheet");
const availableResources = [];
await resourceWatcher.watchResources([ResourceWatcher.TYPES.STYLESHEET], {
onAvailable: ({ resource }) => availableResources.push(resource),
});
is(
availableResources.length,
EXISTING_RESOURCES.length,
"Length of existing resources is correct"
);
for (let i = 0; i < EXISTING_RESOURCES.length; i++) {
const availableResource = availableResources[i];
const expectedResource = EXISTING_RESOURCES[i];
await assertResource(availableResource, expectedResource);
}
info("Check whether ResourceWatcher gets additonal stylesheet");
await ContentTask.spawn(
tab.linkedBrowser,
ADDITIONAL_RESOURCE.styleText,
text => {
const document = content.document;
const stylesheet = document.createElement("style");
stylesheet.textContent = text;
document.body.appendChild(stylesheet);
}
);
await waitUntil(
() => availableResources.length === EXISTING_RESOURCES.length + 1
);
await assertResource(
availableResources[availableResources.length - 1],
ADDITIONAL_RESOURCE
);
info(
"Check whether ResourceWatcher gets additonal stylesheet which is added by DevTool"
);
const styleSheetsFront = await targetList.targetFront.getFront("stylesheets");
await styleSheetsFront.addStyleSheet(
ADDITIONAL_FROM_ACTOR_RESOURCE.styleText
);
await waitUntil(
() => availableResources.length === EXISTING_RESOURCES.length + 2
);
await assertResource(
availableResources[availableResources.length - 1],
ADDITIONAL_FROM_ACTOR_RESOURCE
);
info("Check whether the stylesheet actor is updated correctly or not");
const firstResource = availableResources[0];
await firstResource.styleSheet.update("", false);
await assertResource(
availableResources[0],
Object.assign(EXISTING_RESOURCES[0], { styleText: "" })
);
await targetList.stopListening();
await client.close();
});
async function assertResource(resource, expected) {
const { resourceType, styleSheet, isNew } = resource;
is(
resourceType,
ResourceWatcher.TYPES.STYLESHEET,
"Resource type is correct"
);
ok(styleSheet, "Stylesheet object is in the resource");
const styleText = (await styleSheet.getText()).str.trim();
is(styleText, expected.styleText, "Style text is correct");
is(styleSheet.href, expected.href, "href is correct");
is(styleSheet.nodeHref, expected.nodeHref, "nodeHref is correct");
is(isNew, expected.isNew, "Flag isNew is correct");
}

Просмотреть файл

@ -1 +0,0 @@
body { margin: 1px; }

Просмотреть файл

@ -1,16 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf8">
<title>Test style document</title>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<style>
body { color: lime; }
</style>
<link href="style_document.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<iframe src="https://example.org/browser/devtools/shared/resources/tests/style_iframe.html"></iframe>
</body>
</html>

Просмотреть файл

@ -1 +0,0 @@
body { padding: 1px; }

Просмотреть файл

@ -1,15 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf8">
<title>Test style iframe document</title>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<style>
body { background-color: pink; }
</style>
<link href="style_iframe.css" rel="stylesheet" type="text/css"/>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -6565,7 +6565,23 @@ void Document::StyleSheetApplicableStateChanged(StyleSheet& aSheet) {
}
}
PostStyleSheetApplicableStateChangeEvent(aSheet);
if (StyleSheetChangeEventsEnabled()) {
StyleSheetApplicableStateChangeEventInit init;
init.mBubbles = true;
init.mCancelable = true;
init.mStylesheet = &aSheet;
init.mApplicable = applicable;
RefPtr<StyleSheetApplicableStateChangeEvent> event =
StyleSheetApplicableStateChangeEvent::Constructor(
this, u"StyleSheetApplicableStateChanged"_ns, init);
event->SetTrusted(true);
event->SetTarget(this);
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
asyncDispatcher->mOnlyChromeDispatch = ChromeOnlyDispatch::eYes;
asyncDispatcher->PostDOMEvent();
}
if (!mSSApplicableStateNotificationPending) {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
@ -6577,28 +6593,6 @@ void Document::StyleSheetApplicableStateChanged(StyleSheet& aSheet) {
}
}
void Document::PostStyleSheetApplicableStateChangeEvent(StyleSheet& aSheet) {
if (!StyleSheetChangeEventsEnabled()) {
return;
}
StyleSheetApplicableStateChangeEventInit init;
init.mBubbles = true;
init.mCancelable = true;
init.mStylesheet = &aSheet;
init.mApplicable = aSheet.IsApplicable();
RefPtr<StyleSheetApplicableStateChangeEvent> event =
StyleSheetApplicableStateChangeEvent::Constructor(
this, u"StyleSheetApplicableStateChanged"_ns, init);
event->SetTrusted(true);
event->SetTarget(this);
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
asyncDispatcher->mOnlyChromeDispatch = ChromeOnlyDispatch::eYes;
asyncDispatcher->PostDOMEvent();
}
void Document::NotifyStyleSheetApplicableStateChanged() {
mSSApplicableStateNotificationPending = false;
nsCOMPtr<nsIObserverService> observerService =

Просмотреть файл

@ -1679,8 +1679,6 @@ class Document : public nsINode,
*/
void StyleSheetApplicableStateChanged(StyleSheet&);
void PostStyleSheetApplicableStateChangeEvent(StyleSheet&);
enum additionalSheetType {
eAgentSheet,
eUserSheet,

Просмотреть файл

@ -317,12 +317,6 @@ void SharedStyleSheetCache::LoadCompletedInternal(
"should not get a forced unique inner during parsing");
data->mSheet->SetComplete();
data->ScheduleLoadEventIfNeeded();
} else if (data->mSheet->IsApplicable()) {
if (dom::Document* doc = data->mLoader->GetDocument()) {
// We post these events for devtools, even though the applicable state
// has not actually changed, to make the cache not observable.
doc->PostStyleSheetApplicableStateChangeEvent(*data->mSheet);
}
}
aDatasToNotify.AppendElement(data);