mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1764275
- Add faviconDataUrl and imagePageUrl to Snapshot Groups. r=daleharvey
Add faviconDataUrl and imagePageUrl to each Snapshot Group so the companion can directly use these instead of a polyfill for faviconImage and url. Also change favicon service APIs to respect mDefaultIconURIPreferredSize instead of always returning the largest icon. This allows to use those APIs more easily from jsm modules without having to pass around window handles. Differential Revision: https://phabricator.services.mozilla.com/D143462
This commit is contained in:
parent
4e7c111145
commit
59338c231d
@ -49,6 +49,10 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
||||
* This title should only be used if `title` is not present.
|
||||
* @property {string} imageUrl
|
||||
* The image url to use for the group.
|
||||
* @property {string} faviconDataUrl
|
||||
* The data url to use for the favicon, null if not available.
|
||||
* @property {string} imagePageUrl
|
||||
* The url of the snapshot used to get the image and favicon urls.
|
||||
* @property {number} lastAccessed
|
||||
* The last access time of the most recently accessed snapshot.
|
||||
* Stored as the number of milliseconds since the epoch.
|
||||
@ -372,7 +376,7 @@ const SnapshotGroups = new (class SnapshotGroups {
|
||||
params
|
||||
);
|
||||
|
||||
return rows.map(row => this.#translateSnapshotGroupRow(row));
|
||||
return Promise.all(rows.map(row => this.#translateSnapshotGroupRow(row)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -499,7 +503,7 @@ const SnapshotGroups = new (class SnapshotGroups {
|
||||
* The database row to translate.
|
||||
* @returns {SnapshotGroup}
|
||||
*/
|
||||
#translateSnapshotGroupRow(row) {
|
||||
async #translateSnapshotGroupRow(row) {
|
||||
// Group image selection should be done in this order:
|
||||
// 1. Oldest view in group featured image
|
||||
// 2. Second Oldest View in group featured image
|
||||
@ -512,7 +516,7 @@ const SnapshotGroups = new (class SnapshotGroups {
|
||||
// available.
|
||||
// The query returns featured1|featured2|url1|url2
|
||||
let imageUrls = row.getResultByName("image_urls")?.split("|");
|
||||
let imageUrl = null;
|
||||
let imageUrl, faviconDataUrl, imagePageUrl;
|
||||
if (imageUrls) {
|
||||
imageUrl = imageUrls[0] || imageUrls[1];
|
||||
if (!imageUrl && imageUrls[2]) {
|
||||
@ -524,11 +528,41 @@ const SnapshotGroups = new (class SnapshotGroups {
|
||||
imageUrl = PageThumbs.getThumbnailURL(imageUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// The favicon is for the same page we return a preview image for.
|
||||
imagePageUrl =
|
||||
imageUrls[2] && !imageUrls[0] && imageUrls[1]
|
||||
? imageUrls[3]
|
||||
: imageUrls[2];
|
||||
if (imagePageUrl) {
|
||||
faviconDataUrl = await new Promise(resolve => {
|
||||
PlacesUtils.favicons.getFaviconDataForPage(
|
||||
Services.io.newURI(imagePageUrl),
|
||||
(uri, dataLength, data, mimeType) => {
|
||||
if (dataLength) {
|
||||
// NOTE: honestly this is awkward and inefficient. We build a string
|
||||
// with String.fromCharCode and then btoa that. It's a Uint8Array
|
||||
// under the hood, and we should probably just expose something in
|
||||
// ChromeUtils to Base64 encode a Uint8Array directly, but this is
|
||||
// fine for now.
|
||||
let b64 = btoa(
|
||||
data.reduce((d, byte) => d + String.fromCharCode(byte), "")
|
||||
);
|
||||
resolve(`data:${mimeType};base64,${b64}`);
|
||||
return;
|
||||
}
|
||||
resolve(undefined);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let snapshotGroup = {
|
||||
id: row.getResultByName("id"),
|
||||
faviconDataUrl,
|
||||
imageUrl,
|
||||
imagePageUrl,
|
||||
title: row.getResultByName("title") || "",
|
||||
hidden: row.getResultByName("hidden") == 1,
|
||||
builder: row.getResultByName("builder"),
|
||||
|
@ -5,6 +5,10 @@
|
||||
* Tests for snapshot groups addition, update, and removal.
|
||||
*/
|
||||
|
||||
const FAVICON_DATAURL1 =
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==";
|
||||
const FAVICON_DATAURL2 =
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVBBBBCklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==";
|
||||
const TEST_URL1 = "https://example.com/";
|
||||
const TEST_IMAGE_URL1 = "https://example.com/preview1.png";
|
||||
const TEST_URL2 = "https://example.com/12345";
|
||||
@ -21,6 +25,26 @@ async function delete_all_groups() {
|
||||
}
|
||||
}
|
||||
|
||||
async function setIcon(pageUrl, iconUrl, dataUrl) {
|
||||
PlacesUtils.favicons.replaceFaviconDataFromDataURL(
|
||||
Services.io.newURI(iconUrl),
|
||||
dataUrl,
|
||||
(Date.now() + 8640000) * 1000,
|
||||
Services.scriptSecurityManager.getSystemPrincipal()
|
||||
);
|
||||
|
||||
await new Promise(resolve => {
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
Services.io.newURI(pageUrl),
|
||||
Services.io.newURI(iconUrl),
|
||||
false,
|
||||
PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
resolve,
|
||||
Services.scriptSecurityManager.getSystemPrincipal()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds interactions and snapshots for the supplied data.
|
||||
*
|
||||
@ -83,6 +107,10 @@ add_task(async function test_add_and_query() {
|
||||
data.map(d => d.url)
|
||||
);
|
||||
|
||||
info("add a favicon for both urls");
|
||||
await setIcon(TEST_URL1, TEST_URL1 + "favicon.ico", FAVICON_DATAURL1);
|
||||
await setIcon(TEST_URL2, TEST_URL2 + "/favicon.ico", FAVICON_DATAURL2);
|
||||
|
||||
let groups = await SnapshotGroups.query({ skipMinimum: true });
|
||||
Assert.equal(groups.length, 1, "Should return 1 SnapshotGroup");
|
||||
assertSnapshotGroup(groups[0], {
|
||||
@ -93,6 +121,7 @@ add_task(async function test_add_and_query() {
|
||||
snapshotCount: data.length,
|
||||
lastAccessed: now - 10000,
|
||||
imageUrl: getPageThumbURL(TEST_URL1),
|
||||
imagePageUrl: TEST_URL1,
|
||||
});
|
||||
|
||||
info("add a featured image for second oldest snapshot");
|
||||
@ -110,6 +139,8 @@ add_task(async function test_add_and_query() {
|
||||
snapshotCount: data.length,
|
||||
lastAccessed: now - 10000,
|
||||
imageUrl: previewImageURL,
|
||||
faviconDataUrl: FAVICON_DATAURL2,
|
||||
imagePageUrl: TEST_URL2,
|
||||
});
|
||||
|
||||
info("add a featured image for the oldest snapshot");
|
||||
@ -127,6 +158,8 @@ add_task(async function test_add_and_query() {
|
||||
snapshotCount: data.length,
|
||||
lastAccessed: now - 10000,
|
||||
imageUrl: previewImageURL,
|
||||
faviconDataUrl: FAVICON_DATAURL1,
|
||||
imagePageUrl: TEST_URL1,
|
||||
});
|
||||
});
|
||||
|
||||
@ -543,6 +576,7 @@ add_task(async function test_snapshot_image_with_hidden() {
|
||||
// The images were set on TEST_URL1/TEST_URL2 in an earlier test.
|
||||
assertSnapshotGroup(groups[0], {
|
||||
imageUrl: TEST_IMAGE_URL1,
|
||||
imagePageUrl: TEST_URL1,
|
||||
});
|
||||
|
||||
await SnapshotGroups.setUrlHidden(groups[0].id, TEST_URL1, true);
|
||||
@ -551,6 +585,7 @@ add_task(async function test_snapshot_image_with_hidden() {
|
||||
info("Should use the oldest non-hidden image");
|
||||
assertSnapshotGroup(groups[0], {
|
||||
imageUrl: TEST_IMAGE_URL2,
|
||||
imagePageUrl: TEST_URL2,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -537,6 +537,10 @@ nsFaviconService::GetFaviconURLForPage(nsIURI* aPageURI,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG(aPageURI);
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
// Use the default value, may be UINT16_MAX if a default is not set.
|
||||
if (aPreferredWidth == 0) {
|
||||
aPreferredWidth = mDefaultIconURIPreferredSize;
|
||||
}
|
||||
|
||||
nsAutoCString pageSpec;
|
||||
nsresult rv = aPageURI->GetSpec(pageSpec);
|
||||
@ -562,6 +566,10 @@ nsFaviconService::GetFaviconDataForPage(nsIURI* aPageURI,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG(aPageURI);
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
// Use the default value, may be UINT16_MAX if a default is not set.
|
||||
if (aPreferredWidth == 0) {
|
||||
aPreferredWidth = mDefaultIconURIPreferredSize;
|
||||
}
|
||||
|
||||
nsAutoCString pageSpec;
|
||||
nsresult rv = aPageURI->GetSpec(pageSpec);
|
||||
@ -772,6 +780,7 @@ nsFaviconService::SetDefaultIconURIPreferredSize(uint16_t aDefaultSize) {
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFaviconService::PreferredSizeFromURI(nsIURI* aURI, uint16_t* _size) {
|
||||
NS_ENSURE_ARG(aURI);
|
||||
*_size = mDefaultIconURIPreferredSize;
|
||||
nsAutoCString ref;
|
||||
// Check for a ref first.
|
||||
|
@ -221,7 +221,8 @@ interface nsIFaviconService : nsISupports
|
||||
* aMimeType will be an empty string, regardless of whether a favicon
|
||||
* was found.
|
||||
* @param [optional] aPreferredWidth
|
||||
* The preferred icon width, 0 for the biggest available.
|
||||
* The preferred icon width, skip or pass 0 for the default value,
|
||||
* set through setDefaultIconURIPreferredSize.
|
||||
*
|
||||
* @note If a favicon specific to this page cannot be found, this will try to
|
||||
* fallback to the /favicon.ico for the root domain.
|
||||
@ -248,7 +249,8 @@ interface nsIFaviconService : nsISupports
|
||||
* URI, aDataLen will be 0, aData will be an empty array, and aMimeType
|
||||
* will be an empty string.
|
||||
* @param [optional] aPreferredWidth
|
||||
* The preferred icon width, 0 for the biggest available.
|
||||
* The preferred icon width, skip or pass 0 for the default value,
|
||||
* set through setDefaultIconURIPreferredSize.
|
||||
* @note If a favicon specific to this page cannot be found, this will try to
|
||||
* fallback to the /favicon.ico for the root domain.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user