forked from mirrors/gecko-dev
***
Bug 1514594: Part 3a - Change ChromeUtils.import to return an exports object; not pollute global. r=mccr8
This changes the behavior of ChromeUtils.import() to return an exports object,
rather than a module global, in all cases except when `null` is passed as a
second argument, and changes the default behavior not to pollute the global
scope with the module's exports. Thus, the following code written for the old
model:
ChromeUtils.import("resource://gre/modules/Services.jsm");
is approximately the same as the following, in the new model:
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
Since the two behaviors are mutually incompatible, this patch will land with a
scripted rewrite to update all existing callers to use the new model rather
than the old.
***
Bug 1514594: Part 3b - Mass rewrite all JS code to use the new ChromeUtils.import API. rs=Gijs
This was done using the followng script:
https://bitbucket.org/kmaglione/m-c-rewrites/src/tip/processors/cu-import-exports.jsm
***
Bug 1514594: Part 3c - Update ESLint plugin for ChromeUtils.import API changes. r=Standard8
Differential Revision: https://phabricator.services.mozilla.com/D16747
***
Bug 1514594: Part 3d - Remove/fix hundreds of duplicate imports from sync tests. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16748
***
Bug 1514594: Part 3e - Remove no-op ChromeUtils.import() calls. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16749
***
Bug 1514594: Part 3f.1 - Cleanup various test corner cases after mass rewrite. r=Gijs
***
Bug 1514594: Part 3f.2 - Cleanup various non-test corner cases after mass rewrite. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16750
--HG--
extra : rebase_source : 359574ee3064c90f33bf36c2ebe3159a24cc8895
extra : histedit_source : b93c8f42808b1599f9122d7842d2c0b3e656a594%2C64a3a4e3359dc889e2ab2b49461bab9e27fc10a7
186 lines
5.7 KiB
JavaScript
186 lines
5.7 KiB
JavaScript
/* 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 {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm");
|
|
const {getDomain} = ChromeUtils.import("resource://activity-stream/lib/TippyTopProvider.jsm");
|
|
const {RemoteSettings} = ChromeUtils.import("resource://services-settings/remote-settings.js");
|
|
|
|
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
|
"resource://gre/modules/PlacesUtils.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "Services",
|
|
"resource://gre/modules/Services.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "NewTabUtils",
|
|
"resource://gre/modules/NewTabUtils.jsm");
|
|
|
|
const MIN_FAVICON_SIZE = 96;
|
|
|
|
/**
|
|
* Get favicon info (uri and size) for a uri from Places.
|
|
*
|
|
* @param uri {nsIURI} Page to check for favicon data
|
|
* @returns A promise of an object (possibly null) containing the data
|
|
*/
|
|
function getFaviconInfo(uri) {
|
|
// Use 0 to get the biggest width available
|
|
const preferredWidth = 0;
|
|
return new Promise(resolve => PlacesUtils.favicons.getFaviconDataForPage(
|
|
uri,
|
|
// Package up the icon data in an object if we have it; otherwise null
|
|
(iconUri, faviconLength, favicon, mimeType, faviconSize) =>
|
|
resolve(iconUri ? {iconUri, faviconSize} : null),
|
|
preferredWidth));
|
|
}
|
|
|
|
/**
|
|
* Fetches visit paths for a given URL from its most recent visit in Places.
|
|
*
|
|
* Note that this includes the URL itself as well as all the following
|
|
* permenent&temporary redirected URLs if any.
|
|
*
|
|
* @param {String} a URL string
|
|
*
|
|
* @returns {Array} Returns an array containing objects as
|
|
* {int} visit_id: ID of the visit in moz_historyvisits.
|
|
* {String} url: URL of the redirected URL.
|
|
*/
|
|
async function fetchVisitPaths(url) {
|
|
const query = `
|
|
WITH RECURSIVE path(visit_id)
|
|
AS (
|
|
SELECT v.id
|
|
FROM moz_places h
|
|
JOIN moz_historyvisits v
|
|
ON v.place_id = h.id
|
|
WHERE h.url_hash = hash(:url) AND h.url = :url
|
|
AND v.visit_date = h.last_visit_date
|
|
|
|
UNION
|
|
|
|
SELECT id
|
|
FROM moz_historyvisits
|
|
JOIN path
|
|
ON visit_id = from_visit
|
|
WHERE visit_type IN
|
|
(${PlacesUtils.history.TRANSITIONS.REDIRECT_PERMANENT},
|
|
${PlacesUtils.history.TRANSITIONS.REDIRECT_TEMPORARY})
|
|
)
|
|
SELECT visit_id, (
|
|
SELECT (
|
|
SELECT url
|
|
FROM moz_places
|
|
WHERE id = place_id)
|
|
FROM moz_historyvisits
|
|
WHERE id = visit_id) AS url
|
|
FROM path
|
|
`;
|
|
|
|
const visits = await NewTabUtils.activityStreamProvider.executePlacesQuery(query, {
|
|
columns: ["visit_id", "url"],
|
|
params: {url},
|
|
});
|
|
return visits;
|
|
}
|
|
|
|
/**
|
|
* Fetch favicon for a url by following its redirects in Places.
|
|
*
|
|
* This can improve the rich icon coverage for Top Sites since Places only
|
|
* associates the favicon to the final url if the original one gets redirected.
|
|
* Note this is not an urgent request, hence it is dispatched to the main
|
|
* thread idle handler to avoid any possible performance impact.
|
|
*/
|
|
async function fetchIconFromRedirects(url) {
|
|
const visitPaths = await fetchVisitPaths(url);
|
|
if (visitPaths.length > 1) {
|
|
const lastVisit = visitPaths.pop();
|
|
const redirectedUri = Services.io.newURI(lastVisit.url);
|
|
const iconInfo = await getFaviconInfo(redirectedUri);
|
|
if (iconInfo && iconInfo.faviconSize >= MIN_FAVICON_SIZE) {
|
|
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
|
Services.io.newURI(url),
|
|
iconInfo.iconUri,
|
|
false,
|
|
PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
|
null,
|
|
Services.scriptSecurityManager.getSystemPrincipal()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
this.FaviconFeed = class FaviconFeed {
|
|
constructor() {
|
|
this._queryForRedirects = new Set();
|
|
}
|
|
|
|
/**
|
|
* fetchIcon attempts to fetch a rich icon for the given url from two sources.
|
|
* First, it looks up the tippy top feed, if it's still missing, then it queries
|
|
* the places for rich icon with its most recent visit in order to deal with
|
|
* the redirected visit. See Bug 1421428 for more details.
|
|
*/
|
|
async fetchIcon(url) {
|
|
// Avoid initializing and fetching icons if prefs are turned off
|
|
if (!this.shouldFetchIcons) {
|
|
return;
|
|
}
|
|
|
|
const site = await this.getSite(getDomain(url));
|
|
if (!site) {
|
|
if (!this._queryForRedirects.has(url)) {
|
|
this._queryForRedirects.add(url);
|
|
Services.tm.idleDispatchToMainThread(() => fetchIconFromRedirects(url));
|
|
}
|
|
return;
|
|
}
|
|
|
|
let iconUri = Services.io.newURI(site.image_url);
|
|
// The #tippytop is to be able to identify them for telemetry.
|
|
iconUri = iconUri.mutate().setRef("tippytop").finalize();
|
|
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
|
Services.io.newURI(url),
|
|
iconUri,
|
|
false,
|
|
PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
|
null,
|
|
Services.scriptSecurityManager.getSystemPrincipal()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get the site tippy top data from Remote Settings.
|
|
*/
|
|
async getSite(domain) {
|
|
const sites = await this.tippyTop.get({filters: {domain}});
|
|
return sites.length ? sites[0] : null;
|
|
}
|
|
|
|
/**
|
|
* Get the tippy top collection from Remote Settings.
|
|
*/
|
|
get tippyTop() {
|
|
if (!this._tippyTop) {
|
|
this._tippyTop = RemoteSettings("tippytop");
|
|
}
|
|
return this._tippyTop;
|
|
}
|
|
|
|
/**
|
|
* Determine if we should be fetching and saving icons.
|
|
*/
|
|
get shouldFetchIcons() {
|
|
return Services.prefs.getBoolPref("browser.chrome.site_icons");
|
|
}
|
|
|
|
onAction(action) {
|
|
switch (action.type) {
|
|
case at.RICH_ICON_MISSING:
|
|
this.fetchIcon(action.data.url);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
const EXPORTED_SYMBOLS = ["FaviconFeed", "fetchIconFromRedirects"];
|