зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1910338: Remove PlacesUIUtils.loadFavicon() function r=places-reviewers,mak
Differential Revision: https://phabricator.services.mozilla.com/D218041
This commit is contained in:
Родитель
3c9b3372cc
Коммит
501ed2bbfe
|
@ -5,7 +5,6 @@
|
|||
|
||||
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||
|
||||
import { clearTimeout, setTimeout } from "resource://gre/modules/Timer.sys.mjs";
|
||||
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
|
||||
|
||||
const lazy = {};
|
||||
|
@ -23,229 +22,11 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||
Weave: "resource://services-sync/main.sys.mjs",
|
||||
});
|
||||
|
||||
const gInContentProcess =
|
||||
Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT;
|
||||
const FAVICON_REQUEST_TIMEOUT = 60 * 1000;
|
||||
// Map from windows to arrays of data about pending favicon loads.
|
||||
let gFaviconLoadDataMap = new Map();
|
||||
|
||||
const ITEM_CHANGED_BATCH_NOTIFICATION_THRESHOLD = 10;
|
||||
|
||||
// copied from utilityOverlay.js
|
||||
const TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
|
||||
|
||||
let InternalFaviconLoader = {
|
||||
/**
|
||||
* Actually cancel the request, and clear the timeout for cancelling it.
|
||||
*
|
||||
* @param {object} options
|
||||
* The options object containing:
|
||||
* @param {object} options.uri
|
||||
* The URI of the favicon to cancel.
|
||||
* @param {number} options.timerID
|
||||
* The timer ID of the timeout to be cancelled
|
||||
* @param {*} options.callback
|
||||
* The request callback
|
||||
* @param {string} reason
|
||||
* The reason for cancelling the request.
|
||||
*/
|
||||
_cancelRequest({ uri, timerID, callback }, reason) {
|
||||
// Break cycle
|
||||
let request = callback.request;
|
||||
delete callback.request;
|
||||
// Ensure we don't time out.
|
||||
clearTimeout(timerID);
|
||||
try {
|
||||
request.cancel();
|
||||
} catch (ex) {
|
||||
console.error(
|
||||
`When cancelling a request for ${uri.spec} because ${reason}, it was already canceled!`
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called for every inner that gets destroyed, only in the parent process.
|
||||
*
|
||||
* @param {number} innerID
|
||||
* The innerID of the window.
|
||||
*/
|
||||
removeRequestsForInner(innerID) {
|
||||
for (let [window, loadDataForWindow] of gFaviconLoadDataMap) {
|
||||
let newLoadDataForWindow = loadDataForWindow.filter(loadData => {
|
||||
let innerWasDestroyed = loadData.innerWindowID == innerID;
|
||||
if (innerWasDestroyed) {
|
||||
this._cancelRequest(
|
||||
loadData,
|
||||
"the inner window was destroyed or a new favicon was loaded for it"
|
||||
);
|
||||
}
|
||||
// Keep the items whose inner is still alive.
|
||||
return !innerWasDestroyed;
|
||||
});
|
||||
// Map iteration with for...of is safe against modification, so
|
||||
// now just replace the old value:
|
||||
gFaviconLoadDataMap.set(window, newLoadDataForWindow);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a toplevel chrome window unloads. We use this to tidy up after ourselves,
|
||||
* avoid leaks, and cancel any remaining requests. The last part should in theory be
|
||||
* handled by the inner-window-destroyed handlers. We clean up just to be on the safe side.
|
||||
*
|
||||
* @param {DOMWindow} win
|
||||
* The window that was unloaded.
|
||||
*/
|
||||
onUnload(win) {
|
||||
let loadDataForWindow = gFaviconLoadDataMap.get(win);
|
||||
if (loadDataForWindow) {
|
||||
for (let loadData of loadDataForWindow) {
|
||||
this._cancelRequest(loadData, "the chrome window went away");
|
||||
}
|
||||
}
|
||||
gFaviconLoadDataMap.delete(win);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a particular favicon load's loading data from our map tracking
|
||||
* load data per chrome window.
|
||||
*
|
||||
* @param {DOMWindow} win
|
||||
* the chrome window in which we should look for this load
|
||||
* @param {object} filterData
|
||||
* the data we should use to find this particular load to remove.
|
||||
* @param {number} filterData.innerWindowID
|
||||
* The inner window ID of the window.
|
||||
* @param {string} filterData.uri
|
||||
* The URI of the favicon to cancel.
|
||||
* @param {*} filterData.callback
|
||||
* The request callback
|
||||
*
|
||||
* @returns {object|null}
|
||||
* the loadData object we removed, or null if we didn't find any.
|
||||
*/
|
||||
_removeLoadDataFromWindowMap(win, { innerWindowID, uri, callback }) {
|
||||
let loadDataForWindow = gFaviconLoadDataMap.get(win);
|
||||
if (loadDataForWindow) {
|
||||
let itemIndex = loadDataForWindow.findIndex(loadData => {
|
||||
return (
|
||||
loadData.innerWindowID == innerWindowID &&
|
||||
loadData.uri.equals(uri) &&
|
||||
loadData.callback.request == callback.request
|
||||
);
|
||||
});
|
||||
if (itemIndex != -1) {
|
||||
let loadData = loadDataForWindow[itemIndex];
|
||||
loadDataForWindow.splice(itemIndex, 1);
|
||||
return loadData;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a function to use as a nsIFaviconDataCallback, so we can remove cancelling
|
||||
* information when the request succeeds. Note that right now there are some edge-cases,
|
||||
* such as about: URIs with chrome:// favicons where the success callback is not invoked.
|
||||
* This is OK: we will 'cancel' the request after the timeout (or when the window goes
|
||||
* away) but that will be a no-op in such cases.
|
||||
*
|
||||
* @param {DOMWindow} win
|
||||
* The chrome window in which the request was made.
|
||||
* @param {number} id
|
||||
* The inner window ID of the window.
|
||||
* @returns {object}
|
||||
*/
|
||||
_makeCompletionCallback(win, id) {
|
||||
return {
|
||||
onComplete(uri) {
|
||||
let loadData = InternalFaviconLoader._removeLoadDataFromWindowMap(win, {
|
||||
uri,
|
||||
innerWindowID: id,
|
||||
callback: this,
|
||||
});
|
||||
if (loadData) {
|
||||
clearTimeout(loadData.timerID);
|
||||
}
|
||||
delete this.request;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
ensureInitialized() {
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._initialized = true;
|
||||
|
||||
Services.obs.addObserver(windowGlobal => {
|
||||
this.removeRequestsForInner(windowGlobal.innerWindowId);
|
||||
}, "window-global-destroyed");
|
||||
},
|
||||
|
||||
loadFavicon(browser, principal, pageURI, uri, expiration, iconURI) {
|
||||
this.ensureInitialized();
|
||||
let { ownerGlobal: win, innerWindowID } = browser;
|
||||
if (!gFaviconLoadDataMap.has(win)) {
|
||||
gFaviconLoadDataMap.set(win, []);
|
||||
let unloadHandler = event => {
|
||||
let doc = event.target;
|
||||
let eventWin = doc.defaultView;
|
||||
if (eventWin == win) {
|
||||
win.removeEventListener("unload", unloadHandler);
|
||||
this.onUnload(win);
|
||||
}
|
||||
};
|
||||
win.addEventListener("unload", unloadHandler, true);
|
||||
}
|
||||
|
||||
let callback = this._makeCompletionCallback(win, innerWindowID);
|
||||
if (iconURI?.schemeIs("data")) {
|
||||
lazy.PlacesUtils.favicons.setFaviconForPage(
|
||||
pageURI,
|
||||
uri,
|
||||
iconURI,
|
||||
lazy.PlacesUtils.toPRTime(expiration),
|
||||
() => {
|
||||
callback.onComplete(uri);
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// First we do the actual setAndFetch call:
|
||||
let loadType = lazy.PrivateBrowsingUtils.isWindowPrivate(win)
|
||||
? lazy.PlacesUtils.favicons.FAVICON_LOAD_PRIVATE
|
||||
: lazy.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE;
|
||||
|
||||
let request = lazy.PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
pageURI,
|
||||
uri,
|
||||
false,
|
||||
loadType,
|
||||
callback,
|
||||
principal
|
||||
);
|
||||
|
||||
// Now register the result so we can cancel it if/when necessary.
|
||||
if (!request) {
|
||||
// The favicon service can return with success but no-op (and leave request
|
||||
// as null) if the icon is the same as the page (e.g. for images) or if it is
|
||||
// the favicon for an error page. In this case, we do not need to do anything else.
|
||||
return;
|
||||
}
|
||||
callback.request = request;
|
||||
let loadData = { innerWindowID, uri, callback };
|
||||
loadData.timerID = setTimeout(() => {
|
||||
this._cancelRequest(loadData, "it timed out");
|
||||
this._removeLoadDataFromWindowMap(win, loadData);
|
||||
}, FAVICON_REQUEST_TIMEOUT);
|
||||
let loadDataForWindow = gFaviconLoadDataMap.get(win);
|
||||
loadDataForWindow.push(loadData);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Collects all information for a bookmark and performs editmethods
|
||||
*/
|
||||
|
@ -665,43 +446,6 @@ export var PlacesUIUtils = {
|
|||
await PlacesUIUtils.showBookmarkDialog(bookmarkDialogInfo, win);
|
||||
},
|
||||
|
||||
/**
|
||||
* set and fetch a favicon. Can only be used from the parent process.
|
||||
*
|
||||
* @param {object} browser
|
||||
* The XUL browser element for which we're fetching a favicon.
|
||||
* @param {Principal} principal
|
||||
* The loading principal to use for the fetch.
|
||||
* @param {URI} pageURI
|
||||
* The page URI associated to this favicon load.
|
||||
* @param {URI} uri
|
||||
* The URI to fetch.
|
||||
* @param {number} expiration
|
||||
* An optional expiration time.
|
||||
* @param {URI} iconURI
|
||||
* An optional data: URI holding the icon's data.
|
||||
*/
|
||||
loadFavicon(
|
||||
browser,
|
||||
principal,
|
||||
pageURI,
|
||||
uri,
|
||||
expiration = 0,
|
||||
iconURI = null
|
||||
) {
|
||||
if (gInContentProcess) {
|
||||
throw new Error("Can't track loads from within the child process!");
|
||||
}
|
||||
InternalFaviconLoader.loadFavicon(
|
||||
browser,
|
||||
principal,
|
||||
pageURI,
|
||||
uri,
|
||||
expiration,
|
||||
iconURI
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the closet ancestor places view for the given DOM node
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче