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._pendingURLSubscriptions = new Map();
this._urlToIDMap = new Map(); this._urlToIDMap = new Map();
this._mapsById = new Map(); this._mapsById = new Map();
this._listeningStylesheetFront = null;
this._sourcesLoading = null; this._sourcesLoading = null;
this._runningCallback = false; this._runningCallback = false;
@ -204,16 +205,13 @@ class SourceMapURLService {
this._pendingURLSubscriptions.clear(); this._pendingURLSubscriptions.clear();
this._urlToIDMap.clear(); this._urlToIDMap.clear();
try { if (this._listeningStylesheetFront) {
this._toolbox.resourceWatcher.unwatchResources( this._listeningStylesheetFront.off(
[this._toolbox.resourceWatcher.TYPES.STYLESHEET], "stylesheet-added",
{ onAvailable: this._onResourceAvailable } this._onNewStyleSheet
); );
} catch (e) { this._listeningStylesheetFront = null;
// If unwatchResources is called before finishing process of watchResources,
// it throws an error during stopping listener.
} }
this._sourcesLoading = null; this._sourcesLoading = null;
} }
@ -428,17 +426,39 @@ class SourceMapURLService {
return; return;
} }
this._onResourceAvailable = async ({ resource }) => {
if (this._sourcesLoading === sourcesLoading) {
this._onNewStyleSheet(resource.styleSheet);
}
};
await Promise.all([ await Promise.all([
this._toolbox.resourceWatcher.watchResources( (async () => {
[this._toolbox.resourceWatcher.TYPES.STYLESHEET], if (!this._target.hasActor("styleSheets")) {
{ onAvailable: this._onResourceAvailable } 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 () => { (async () => {
const { threadFront } = this._toolbox; const { threadFront } = this._toolbox;
if (!threadFront) { if (!threadFront) {

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

@ -89,8 +89,16 @@ function StyleEditorUI(toolbox, panelDoc, cssProperties) {
this.savedLocations = {}; this.savedLocations = {};
this._seenSheets = new Map(); 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._onOptionsButtonClick = this._onOptionsButtonClick.bind(this);
this._onOrigSourcesPrefChanged = this._onOrigSourcesPrefChanged.bind(this); this._onNewDocument = this._onNewDocument.bind(this);
this._onMediaPrefChanged = this._onMediaPrefChanged.bind(this); this._onMediaPrefChanged = this._onMediaPrefChanged.bind(this);
this._updateMediaList = this._updateMediaList.bind(this); this._updateMediaList = this._updateMediaList.bind(this);
this._clear = this._clear.bind(this); this._clear = this._clear.bind(this);
@ -98,18 +106,16 @@ function StyleEditorUI(toolbox, panelDoc, cssProperties) {
this._updateContextMenuItems = this._updateContextMenuItems.bind(this); this._updateContextMenuItems = this._updateContextMenuItems.bind(this);
this._openLinkNewTab = this._openLinkNewTab.bind(this); this._openLinkNewTab = this._openLinkNewTab.bind(this);
this._copyUrl = this._copyUrl.bind(this); this._copyUrl = this._copyUrl.bind(this);
this._addStyleSheet = this._addStyleSheet.bind(this);
this._onTargetAvailable = this._onTargetAvailable.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 = new PrefObserver("devtools.styleeditor.");
this._prefObserver.on(PREF_MEDIA_SIDEBAR, this._onMediaPrefChanged); this._prefObserver.on(PREF_MEDIA_SIDEBAR, this._onMediaPrefChanged);
this._sourceMapPrefObserver = new PrefObserver( this._sourceMapPrefObserver = new PrefObserver(
"devtools.source-map.client-service." "devtools.source-map.client-service."
); );
this._sourceMapPrefObserver.on( this._sourceMapPrefObserver.on(PREF_ORIG_SOURCES, this._onNewDocument);
PREF_ORIG_SOURCES,
this._onOrigSourcesPrefChanged
);
} }
StyleEditorUI.prototype = { StyleEditorUI.prototype = {
@ -138,20 +144,9 @@ StyleEditorUI.prototype = {
await this._toolbox.targetList.watchTargets( await this._toolbox.targetList.watchTargets(
[this._toolbox.targetList.TYPES.FRAME], [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) { 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() { async _onNewDocument() {
this._clear(); this._suppressAdd = true;
// When we toggle the source-map preference, we clear the panel and re-fetch the exact try {
// same stylesheet resources from ResourceWatcher, but `_addStyleSheet` will trigger const stylesheetsFront = await this.currentTarget.getFront("stylesheets");
// or ignore the additional source-map mapping. const styleSheets = await stylesheetsFront.getStyleSheets();
this._root.classList.add("loading"); await this._resetStyleSheetList(styleSheets);
for (const resource of this._toolbox.resourceWatcher.getAllResources( } catch (e) {
this._toolbox.resourceWatcher.TYPES.STYLESHEET console.error(e);
)) {
await this._handleStyleSheetResource(resource);
} }
},
/**
* 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._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 // Here the keys are style sheet actors, and the values are
// promises that resolve to the sheet's editor. See |_addStyleSheet|. // promises that resolve to the sheet's editor. See |_addStyleSheet|.
this._seenSheets = new Map(); 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. * is enabled, then the promise resolves to null.
*/ */
_addStyleSheet: function(styleSheet, isNew) { _addStyleSheet: function(styleSheet, isNew) {
if (this._suppressAdd) {
return null;
}
if (!this._seenSheets.has(styleSheet)) { if (!this._seenSheets.has(styleSheet)) {
const promise = (async () => { const promise = (async () => {
let editor = await this._addStyleSheetEditor(styleSheet, isNew); let editor = await this._addStyleSheetEditor(styleSheet, isNew);
@ -474,10 +493,12 @@ StyleEditorUI.prototype = {
); );
stream.close(); stream.close();
this._suppressAdd = true;
const stylesheetsFront = await this.currentTarget.getFront( const stylesheetsFront = await this.currentTarget.getFront(
"stylesheets" "stylesheets"
); );
const styleSheet = await stylesheetsFront.addStyleSheet(source); const styleSheet = await stylesheetsFront.addStyleSheet(source);
this._suppressAdd = false;
const editor = await this._addStyleSheet(styleSheet, true); const editor = await this._addStyleSheet(styleSheet, true);
if (editor) { if (editor) {
editor.savedFile = selectedFile; editor.savedFile = selectedFile;
@ -1154,96 +1175,50 @@ StyleEditorUI.prototype = {
this.selectStyleSheet(source, location.line - 1, location.column - 1); 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 }) { async _onTargetAvailable({ targetFront }) {
if (targetFront.isTopLevel) { if (targetFront.isTopLevel) {
await this.initializeHighlighter(targetFront); 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() { destroy: function() {
this._toolbox.targetList.unwatchTargets( this._toolbox.targetList.unwatchTargets(
[this._toolbox.targetList.TYPES.FRAME], [this._toolbox.targetList.TYPES.FRAME],
this._onTargetAvailable this._onTargetAvailable,
this._onTargetDestroyed
); );
this._toolbox.resourceWatcher.unwatchResources( this.currentTarget.off("will-navigate", this._clear);
[ this.currentTarget.off("navigate", this._onNewDocument);
this._toolbox.resourceWatcher.TYPES.DOCUMENT_EVENT,
this._toolbox.resourceWatcher.TYPES.STYLESHEET, const stylesheetsFront = this.currentTarget.getCachedFront("stylesheets");
], if (stylesheetsFront) {
{ onAvailable: this._onResourceAvailable } stylesheetsFront.off("stylesheet-added", this._addStyleSheet);
); }
this._clearStyleSheetEditors(); this._clearStyleSheetEditors();
this._seenSheets = null; this._seenSheets = null;
this._suppressAdd = false;
const sidebar = this._panelDoc.querySelector(".splitview-controller"); const sidebar = this._panelDoc.querySelector(".splitview-controller");
const sidebarWidth = sidebar.getAttribute("width"); const sidebarWidth = sidebar.getAttribute("width");
Services.prefs.setIntPref(PREF_NAV_WIDTH, sidebarWidth); Services.prefs.setIntPref(PREF_NAV_WIDTH, sidebarWidth);
this._sourceMapPrefObserver.off( this._sourceMapPrefObserver.off(PREF_ORIG_SOURCES, this._onNewDocument);
PREF_ORIG_SOURCES,
this._onOrigSourcesPrefChanged
);
this._sourceMapPrefObserver.destroy(); this._sourceMapPrefObserver.destroy();
this._prefObserver.off(PREF_MEDIA_SIDEBAR, this._onMediaPrefChanged); this._prefObserver.off(PREF_MEDIA_SIDEBAR, this._onMediaPrefChanged);
this._prefObserver.destroy(); this._prefObserver.destroy();

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

@ -22,21 +22,21 @@ const DOCUMENT_WITH_ONE_STYLESHEET =
add_task(async function() { add_task(async function() {
const { ui } = await openStyleEditorForURL(DOCUMENT_WITH_ONE_STYLESHEET); 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. // StyleEditorActor has a chance to respond to the first one.
const SPAM_COUNT = 2; const SPAM_COUNT = 2;
for (let i = 0; i < SPAM_COUNT; ++i) { 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. // message.
await new Promise(resolve => { await new Promise(resolve => {
let loadCount = 0; let loadCount = 0;
ui.on("stylesheets-refreshed", function onReset() { ui.on("stylesheets-reset", function onReset() {
++loadCount; ++loadCount;
if (loadCount == SPAM_COUNT) { 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 // No matter how large SPAM_COUNT is, the number of style
// sheets should never be more than the number of style sheets // sheets should never be more than the number of style sheets
// in the document. // in the document.

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

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

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

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

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

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

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

@ -16,27 +16,21 @@ add_task(async function() {
info("Selecting the second editor"); info("Selecting the second editor");
await ui.selectStyleSheet(ui.editors[1].styleSheet, LINE_NO, COL_NO); 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."); info("Waiting for source editor to be ready.");
const newEditor = findEditor(ui, selectedStyleSheetIndex); await ui.editors[1].getSourceEditor();
await newEditor.getSourceEditor();
is( is(
ui.selectedEditor, ui.selectedEditor,
newEditor, ui.editors[1],
"Editor of stylesheet that has styleSheetIndex we selected is selected after reload" "second editor is selected after reload"
); );
const { line, ch } = ui.selectedEditor.sourceEditor.getCursor(); const { line, ch } = ui.selectedEditor.sourceEditor.getCursor();
is(line, LINE_NO, "correct line selected"); is(line, LINE_NO, "correct line selected");
is(ch, COL_NO, "correct column 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 */ /* Helpers */
function togglePref(UI) { function togglePref(UI) {
const editorsPromise = UI.once("stylesheets-refreshed"); const editorsPromise = UI.once("stylesheets-reset");
const selectedPromise = UI.once("editor-selected"); const selectedPromise = UI.once("editor-selected");
Services.prefs.setBoolPref(PREF, false); Services.prefs.setBoolPref(PREF, false);

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

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

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

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

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

@ -651,17 +651,22 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
this.parentActor = targetActor; this.parentActor = targetActor;
this._onApplicableStateChanged = this._onApplicableStateChanged.bind(this);
this._onNewStyleSheetActor = this._onNewStyleSheetActor.bind(this); this._onNewStyleSheetActor = this._onNewStyleSheetActor.bind(this);
this._onSheetAdded = this._onSheetAdded.bind(this);
this._onWindowReady = this._onWindowReady.bind(this); this._onWindowReady = this._onWindowReady.bind(this);
this._transitionSheetLoaded = false; this._transitionSheetLoaded = false;
this.parentActor.on("stylesheet-added", this._onNewStyleSheetActor); this.parentActor.on("stylesheet-added", this._onNewStyleSheetActor);
this.parentActor.on("window-ready", this._onWindowReady); 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( this.parentActor.chromeEventHandler.addEventListener(
"StyleSheetApplicableStateChanged", "StyleSheetApplicableStateChanged",
this._onApplicableStateChanged, this._onSheetAdded,
true true
); );
@ -683,7 +688,7 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
this.parentActor.chromeEventHandler.removeEventListener( this.parentActor.chromeEventHandler.removeEventListener(
"StyleSheetApplicableStateChanged", "StyleSheetApplicableStateChanged",
this._onApplicableStateChanged, this._onSheetAdded,
true true
); );
@ -740,7 +745,10 @@ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
// Special case about:PreferenceStyleSheet, as it is generated on the // Special case about:PreferenceStyleSheet, as it is generated on the
// fly and the URI is not registered with the about: handler. // fly and the URI is not registered with the about: handler.
// https://bugzilla.mozilla.org/show_bug.cgi?id=935803#c37 // 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; 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. * @param {Event} evt
* - 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}
* The triggering event. * The triggering event.
*/ */
_onApplicableStateChanged: function({ applicable, stylesheet }) { _onSheetAdded: function(evt) {
if ( const sheet = evt.stylesheet;
// Have interest in applicable stylesheet only. if (this._shouldListSheet(sheet) && !this._haveAncestorWithSameURL(sheet)) {
applicable && this.parentActor.createStyleSheetActor(sheet);
// 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);
} }
}, },

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

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

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

@ -9,5 +9,4 @@ DevToolsModules(
'error-messages.js', 'error-messages.js',
'platform-messages.js', 'platform-messages.js',
'root-node.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(); 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 * Request to start retrieving all already existing instances of given
* type of resources and also start watching for the one to be created after. * type of resources and also start watching for the one to be created after.
@ -70,11 +60,7 @@ class ResourceWatcher {
* existing resources. * existing resources.
*/ */
async watchResources(resources, options) { async watchResources(resources, options) {
const { const { onAvailable, ignoreExistingResources = false } = options;
onAvailable,
onDestroyed,
ignoreExistingResources = false,
} = options;
// Cache the Watcher once for all, the first time we call `watch()`. // 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. // This `watcher` attribute may be then used in any function of the ResourceWatcher after this.
@ -99,16 +85,8 @@ class ResourceWatcher {
await this._watchAllTargets(); await this._watchAllTargets();
for (const resource of resources) { for (const resource of resources) {
// If we are registering the first listener, so start listening from the server about await this._startListening(resource);
// this one resource. this._registerListeners(resource, options);
if (this._availableListeners.count(resource) === 0) {
await this._startListening(resource);
}
this._availableListeners.on(resource, onAvailable);
if (onDestroyed) {
this._destroyedListeners.on(resource, onDestroyed);
}
} }
if (!ignoreExistingResources) { if (!ignoreExistingResources) {
@ -124,24 +102,16 @@ class ResourceWatcher {
const { onAvailable, onDestroyed } = options; const { onAvailable, onDestroyed } = options;
for (const resource of resources) { for (const resource of resources) {
this._availableListeners.off(resource, onAvailable);
if (onDestroyed) { if (onDestroyed) {
this._destroyedListeners.off(resource, onDestroyed); this._destroyedListeners.off(resource, onDestroyed);
} }
this._stopListening(resource);
const hadAtLeastOneListener =
this._availableListeners.count(resource) > 0;
this._availableListeners.off(resource, onAvailable);
if (
hadAtLeastOneListener &&
this._availableListeners.count(resource) === 0
) {
this._stopListening(resource);
}
} }
// Stop watching for targets if we removed the last listener. // Stop watching for targets if we removed the last listener.
let listeners = 0; let listeners = 0;
for (const count of this._listenerCount.values()) { for (const count of this._listenerCount) {
listeners += count; listeners += count;
} }
if (listeners <= 0) { 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. * Start watching for all already existing and future targets.
* *
@ -455,7 +439,6 @@ ResourceWatcher.TYPES = ResourceWatcher.prototype.TYPES = {
PLATFORM_MESSAGE: "platform-message", PLATFORM_MESSAGE: "platform-message",
DOCUMENT_EVENT: "document-event", DOCUMENT_EVENT: "document-event",
ROOT_NODE: "root-node", ROOT_NODE: "root-node",
STYLESHEET: "stylesheet",
}; };
module.exports = { ResourceWatcher }; module.exports = { ResourceWatcher };
@ -492,8 +475,6 @@ const LegacyListeners = {
}, },
[ResourceWatcher.TYPES [ResourceWatcher.TYPES
.ROOT_NODE]: require("devtools/shared/resources/legacy-listeners/root-node"), .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. // Optional transformers for each type of resource.

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

@ -8,10 +8,6 @@ support-files =
head.js head.js
fission_document.html fission_document.html
fission_iframe.html fission_iframe.html
style_document.css
style_document.html
style_iframe.css
style_iframe.html
test_service_worker.js test_service_worker.js
test_sw_page.html test_sw_page.html
test_sw_page_worker.js test_sw_page_worker.js
@ -23,11 +19,9 @@ support-files =
[browser_resources_css_messages.js] [browser_resources_css_messages.js]
[browser_resources_document_events.js] [browser_resources_document_events.js]
[browser_resources_error_messages.js] [browser_resources_error_messages.js]
[browser_resources_getAllResources.js]
[browser_resources_platform_messages.js] [browser_resources_platform_messages.js]
[browser_resources_root_node.js] [browser_resources_root_node.js]
[browser_resources_several_resources.js] [browser_resources_several_resources.js]
[browser_resources_stylesheets.js]
[browser_resources_target_destroy.js] [browser_resources_target_destroy.js]
[browser_target_list_frames.js] [browser_target_list_frames.js]
[browser_target_list_getAllTargets.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) { if (!mSSApplicableStateNotificationPending) {
MOZ_RELEASE_ASSERT(NS_IsMainThread()); 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() { void Document::NotifyStyleSheetApplicableStateChanged() {
mSSApplicableStateNotificationPending = false; mSSApplicableStateNotificationPending = false;
nsCOMPtr<nsIObserverService> observerService = nsCOMPtr<nsIObserverService> observerService =

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

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

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

@ -317,12 +317,6 @@ void SharedStyleSheetCache::LoadCompletedInternal(
"should not get a forced unique inner during parsing"); "should not get a forced unique inner during parsing");
data->mSheet->SetComplete(); data->mSheet->SetComplete();
data->ScheduleLoadEventIfNeeded(); 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); aDatasToNotify.AppendElement(data);