mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1576911 - Make ThumbnailsChild a JSWindowActorChild instead of ActorChild r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D45957 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
6e2cb1503d
commit
64dd6427d1
@ -43,9 +43,9 @@ var tabPreviews = {
|
||||
let browser = aTab.linkedBrowser;
|
||||
let uri = browser.currentURI.spec;
|
||||
let canvas = PageThumbs.createCanvas(window);
|
||||
PageThumbs.shouldStoreThumbnail(browser, aDoStore => {
|
||||
PageThumbs.shouldStoreThumbnail(browser).then(aDoStore => {
|
||||
if (aDoStore && aShouldCache) {
|
||||
PageThumbs.captureAndStore(browser, function() {
|
||||
PageThumbs.captureAndStore(browser).then(function() {
|
||||
let img = new Image();
|
||||
img.src = PageThumbs.getThumbnailURL(uri);
|
||||
aTab.__thumbnail = img;
|
||||
@ -53,12 +53,14 @@ var tabPreviews = {
|
||||
canvas.getContext("2d").drawImage(img, 0, 0);
|
||||
});
|
||||
} else {
|
||||
PageThumbs.captureToCanvas(browser, canvas, () => {
|
||||
if (aShouldCache) {
|
||||
aTab.__thumbnail = canvas;
|
||||
aTab.__thumbnail_lastURI = uri;
|
||||
}
|
||||
});
|
||||
PageThumbs.captureToCanvas(browser, canvas)
|
||||
.then(() => {
|
||||
if (aShouldCache) {
|
||||
aTab.__thumbnail = canvas;
|
||||
aTab.__thumbnail_lastURI = uri;
|
||||
}
|
||||
})
|
||||
.catch(e => Cu.reportError(e));
|
||||
}
|
||||
});
|
||||
return canvas;
|
||||
|
@ -314,7 +314,9 @@ var StarUI = {
|
||||
}
|
||||
|
||||
let canvas = PageThumbs.createCanvas(window);
|
||||
PageThumbs.captureToCanvas(gBrowser.selectedBrowser, canvas);
|
||||
PageThumbs.captureToCanvas(gBrowser.selectedBrowser, canvas).catch(e =>
|
||||
Cu.reportError(e)
|
||||
);
|
||||
document.mozSetImageElement("editBookmarkPanelImageCanvas", canvas);
|
||||
},
|
||||
|
||||
|
@ -132,11 +132,9 @@ var gBrowserThumbnails = {
|
||||
if (!aBrowser.currentURI || !topSites.includes(aBrowser.currentURI.spec)) {
|
||||
return;
|
||||
}
|
||||
this._shouldCapture(aBrowser, function(aResult) {
|
||||
if (aResult) {
|
||||
PageThumbs.captureAndStoreIfStale(aBrowser);
|
||||
}
|
||||
});
|
||||
if (await this._shouldCapture(aBrowser)) {
|
||||
await PageThumbs.captureAndStoreIfStale(aBrowser);
|
||||
}
|
||||
},
|
||||
|
||||
_delayedCapture: function Thumbnails_delayedCapture(aBrowser) {
|
||||
@ -163,16 +161,15 @@ var gBrowserThumbnails = {
|
||||
this._timeouts.set(aBrowser, { isTimeout: true, id: timeoutId });
|
||||
},
|
||||
|
||||
_shouldCapture: function Thumbnails_shouldCapture(aBrowser, aCallback) {
|
||||
_shouldCapture: async function Thumbnails_shouldCapture(aBrowser) {
|
||||
// Capture only if it's the currently selected tab and not an about: page.
|
||||
if (
|
||||
aBrowser != gBrowser.selectedBrowser ||
|
||||
gBrowser.currentURI.schemeIs("about")
|
||||
) {
|
||||
aCallback(false);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
PageThumbs.shouldStoreThumbnail(aBrowser, aCallback);
|
||||
return PageThumbs.shouldStoreThumbnail(aBrowser);
|
||||
},
|
||||
|
||||
_cancelDelayedCapture: function Thumbnails_cancelDelayedCapture(aBrowser) {
|
||||
|
@ -470,11 +470,15 @@
|
||||
}
|
||||
// PageThumb is async with e10s but that's fine
|
||||
// since we can update the image during the dnd.
|
||||
PageThumbs.captureToCanvas(browser, canvas, captureListener);
|
||||
PageThumbs.captureToCanvas(browser, canvas)
|
||||
.then(captureListener)
|
||||
.catch(e => Cu.reportError(e));
|
||||
} else {
|
||||
// For the non e10s case we can just use PageThumbs
|
||||
// sync, so let's use the canvas for setDragImage.
|
||||
PageThumbs.captureToCanvas(browser, canvas);
|
||||
PageThumbs.captureToCanvas(browser, canvas).catch(e =>
|
||||
Cu.reportError(e)
|
||||
);
|
||||
dragImageOffset = dragImageOffset * scale;
|
||||
}
|
||||
dt.setDragImage(toDrag, dragImageOffset, dragImageOffset);
|
||||
|
@ -235,19 +235,16 @@ PreviewController.prototype = {
|
||||
* Capture a new thumbnail image for this preview. Called by the controller
|
||||
* in response to a request for a new thumbnail image.
|
||||
*/
|
||||
updateCanvasPreview(aFullScale, aCallback) {
|
||||
updateCanvasPreview(aFullScale) {
|
||||
// Update our cached browser dims so that delayed resize
|
||||
// events don't trigger another invalidation if this tab becomes active.
|
||||
this.cacheBrowserDims();
|
||||
PageThumbs.captureToCanvas(
|
||||
this.linkedBrowser,
|
||||
this.canvasPreview,
|
||||
aCallback,
|
||||
{ fullScale: aFullScale }
|
||||
);
|
||||
AeroPeek.resetCacheTimer();
|
||||
return PageThumbs.captureToCanvas(this.linkedBrowser, this.canvasPreview, {
|
||||
fullScale: aFullScale,
|
||||
}).catch(e => Cu.reportError(e));
|
||||
// If we're updating the canvas, then we're in the middle of a peek so
|
||||
// don't discard the cache of previews.
|
||||
AeroPeek.resetCacheTimer();
|
||||
},
|
||||
|
||||
updateTitleAndTooltip() {
|
||||
@ -288,7 +285,7 @@ PreviewController.prototype = {
|
||||
requestPreview(aTaskbarCallback) {
|
||||
// Grab a high res content preview
|
||||
this.resetCanvasPreview();
|
||||
this.updateCanvasPreview(true, aPreviewCanvas => {
|
||||
this.updateCanvasPreview(true).then(aPreviewCanvas => {
|
||||
let winWidth = this.win.width;
|
||||
let winHeight = this.win.height;
|
||||
|
||||
@ -340,7 +337,7 @@ PreviewController.prototype = {
|
||||
*/
|
||||
requestThumbnail(aTaskbarCallback, aRequestedWidth, aRequestedHeight) {
|
||||
this.resizeCanvasPreview(aRequestedWidth, aRequestedHeight);
|
||||
this.updateCanvasPreview(false, aThumbnailCanvas => {
|
||||
this.updateCanvasPreview(false).then(aThumbnailCanvas => {
|
||||
aTaskbarCallback.done(aThumbnailCanvas, false);
|
||||
});
|
||||
},
|
||||
|
@ -5,10 +5,6 @@
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["ThumbnailsChild"];
|
||||
|
||||
const { ActorChild } = ChromeUtils.import(
|
||||
"resource://gre/modules/ActorChild.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
@ -17,65 +13,39 @@ ChromeUtils.defineModuleGetter(
|
||||
"resource://gre/modules/PageThumbUtils.jsm"
|
||||
);
|
||||
|
||||
class ThumbnailsChild extends ActorChild {
|
||||
class ThumbnailsChild extends JSWindowActorChild {
|
||||
receiveMessage(message) {
|
||||
if (message.name == "Browser:Thumbnail:Request") {
|
||||
/**
|
||||
* Remote thumbnail request handler for PageThumbs thumbnails.
|
||||
*/
|
||||
let snapshot;
|
||||
let args = message.data.additionalArgs;
|
||||
let fullScale = args ? args.fullScale : false;
|
||||
if (fullScale) {
|
||||
snapshot = PageThumbUtils.createSnapshotThumbnail(
|
||||
this.content,
|
||||
null,
|
||||
args
|
||||
);
|
||||
} else {
|
||||
let snapshotWidth = message.data.canvasWidth;
|
||||
let snapshotHeight = message.data.canvasHeight;
|
||||
snapshot = PageThumbUtils.createCanvas(
|
||||
this.content,
|
||||
snapshotWidth,
|
||||
snapshotHeight
|
||||
);
|
||||
PageThumbUtils.createSnapshotThumbnail(this.content, snapshot, args);
|
||||
switch (message.name) {
|
||||
case "Browser:Thumbnail:ContentSize": {
|
||||
return PageThumbUtils.getContentSize(this.contentWindow);
|
||||
}
|
||||
|
||||
snapshot.toBlob(aBlob => {
|
||||
this.mm.sendAsyncMessage("Browser:Thumbnail:Response", {
|
||||
thumbnail: aBlob,
|
||||
id: message.data.id,
|
||||
});
|
||||
});
|
||||
} else if (message.name == "Browser:Thumbnail:CheckState") {
|
||||
/**
|
||||
* Remote isSafeForCapture request handler for PageThumbs.
|
||||
*/
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
let result = PageThumbUtils.shouldStoreContentThumbnail(
|
||||
this.content,
|
||||
this.mm.docShell
|
||||
case "Browser:Thumbnail:CheckState": {
|
||||
/**
|
||||
* Remote isSafeForCapture request handler for PageThumbs.
|
||||
*/
|
||||
return new Promise(resolve =>
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
let result = PageThumbUtils.shouldStoreContentThumbnail(
|
||||
this.contentWindow,
|
||||
this.browsingContext.docShell
|
||||
);
|
||||
resolve(result);
|
||||
})
|
||||
);
|
||||
this.mm.sendAsyncMessage("Browser:Thumbnail:CheckState:Response", {
|
||||
result,
|
||||
});
|
||||
});
|
||||
} else if (message.name == "Browser:Thumbnail:GetOriginalURL") {
|
||||
/**
|
||||
* Remote GetOriginalURL request handler for PageThumbs.
|
||||
*/
|
||||
let channel = this.mm.docShell.currentDocumentChannel;
|
||||
let channelError = PageThumbUtils.isChannelErrorResponse(channel);
|
||||
let originalURL;
|
||||
try {
|
||||
originalURL = channel.originalURI.spec;
|
||||
} catch (ex) {}
|
||||
this.mm.sendAsyncMessage("Browser:Thumbnail:GetOriginalURL:Response", {
|
||||
channelError,
|
||||
originalURL,
|
||||
});
|
||||
}
|
||||
case "Browser:Thumbnail:GetOriginalURL": {
|
||||
/**
|
||||
* Remote GetOriginalURL request handler for PageThumbs.
|
||||
*/
|
||||
let channel = this.browsingContext.docShell.currentDocumentChannel;
|
||||
let channelError = PageThumbUtils.isChannelErrorResponse(channel);
|
||||
let originalURL;
|
||||
try {
|
||||
originalURL = channel.originalURI.spec;
|
||||
} catch (ex) {}
|
||||
return { channelError, originalURL };
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ const LATEST_STORAGE_VERSION = 3;
|
||||
const EXPIRATION_MIN_CHUNK_SIZE = 50;
|
||||
const EXPIRATION_INTERVAL_SECS = 3600;
|
||||
|
||||
var gRemoteThumbId = 0;
|
||||
|
||||
// If a request for a thumbnail comes in and we find one that is "stale"
|
||||
// (or don't find one at all) we automatically queue a request to generate a
|
||||
// new one.
|
||||
@ -175,11 +173,13 @@ var PageThumbs = {
|
||||
|
||||
return new Promise(resolve => {
|
||||
let canvas = this.createCanvas(aBrowser.ownerGlobal);
|
||||
this.captureToCanvas(aBrowser, canvas, () => {
|
||||
canvas.toBlob(blob => {
|
||||
resolve(blob, this.contentType);
|
||||
});
|
||||
});
|
||||
this.captureToCanvas(aBrowser, canvas)
|
||||
.then(() => {
|
||||
canvas.toBlob(blob => {
|
||||
resolve(blob, this.contentType);
|
||||
});
|
||||
})
|
||||
.catch(e => Cu.reportError(e));
|
||||
});
|
||||
},
|
||||
|
||||
@ -192,23 +192,19 @@ var PageThumbs = {
|
||||
* @param aCanvas The canvas to draw to. The thumbnail will be scaled to match
|
||||
* the dimensions of this canvas. If callers pass a 0x0 canvas, the canvas
|
||||
* will be resized to default thumbnail dimensions just prior to painting.
|
||||
* @param aCallback (optional) A callback invoked once the thumbnail has been
|
||||
* rendered to aCanvas.
|
||||
* @param aArgs (optional) Additional named parameters:
|
||||
* fullScale - request that a non-downscaled image be returned.
|
||||
*/
|
||||
captureToCanvas(aBrowser, aCanvas, aCallback, aArgs) {
|
||||
async captureToCanvas(aBrowser, aCanvas, aArgs) {
|
||||
let telemetryCaptureTime = new Date();
|
||||
let args = {
|
||||
fullScale: aArgs ? aArgs.fullScale : false,
|
||||
};
|
||||
this._captureToCanvas(aBrowser, aCanvas, args, aCanvas => {
|
||||
return this._captureToCanvas(aBrowser, aCanvas, args).then(() => {
|
||||
Services.telemetry
|
||||
.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS")
|
||||
.add(new Date() - telemetryCaptureTime);
|
||||
if (aCallback) {
|
||||
aCallback(aCanvas);
|
||||
}
|
||||
return aCanvas;
|
||||
});
|
||||
},
|
||||
|
||||
@ -220,69 +216,52 @@ var PageThumbs = {
|
||||
* content being displayed.
|
||||
*
|
||||
* @param aBrowser The target browser
|
||||
* @param aCallback(aResult) A callback invoked once security checks have
|
||||
* completed. aResult is a boolean indicating the combined result of the
|
||||
* security checks performed.
|
||||
*/
|
||||
shouldStoreThumbnail(aBrowser, aCallback) {
|
||||
async shouldStoreThumbnail(aBrowser) {
|
||||
// Don't capture in private browsing mode.
|
||||
if (PrivateBrowsingUtils.isBrowserPrivate(aBrowser)) {
|
||||
aCallback(false);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (aBrowser.isRemoteBrowser) {
|
||||
let mm = aBrowser.messageManager;
|
||||
let resultFunc = function(aMsg) {
|
||||
mm.removeMessageListener(
|
||||
"Browser:Thumbnail:CheckState:Response",
|
||||
resultFunc
|
||||
if (aBrowser.browsingContext.currentWindowGlobal) {
|
||||
let thumbnailsActor = aBrowser.browsingContext.currentWindowGlobal.getActor(
|
||||
"Thumbnails"
|
||||
);
|
||||
aCallback(aMsg.data.result);
|
||||
};
|
||||
mm.addMessageListener(
|
||||
"Browser:Thumbnail:CheckState:Response",
|
||||
resultFunc
|
||||
);
|
||||
try {
|
||||
mm.sendAsyncMessage("Browser:Thumbnail:CheckState");
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
// If the message manager is not able send our message, taking a content
|
||||
// screenshot is also not going to work: return false.
|
||||
resultFunc({ data: { result: false } });
|
||||
return thumbnailsActor
|
||||
.sendQuery("Browser:Thumbnail:CheckState")
|
||||
.catch(err => {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
aCallback(
|
||||
PageThumbUtils.shouldStoreContentThumbnail(
|
||||
aBrowser.contentDocument,
|
||||
aBrowser.docShell
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return PageThumbUtils.shouldStoreContentThumbnail(
|
||||
aBrowser.contentDocument,
|
||||
aBrowser.docShell
|
||||
);
|
||||
},
|
||||
|
||||
// The background thumbnail service captures to canvas but doesn't want to
|
||||
// participate in this service's telemetry, which is why this method exists.
|
||||
_captureToCanvas(aBrowser, aCanvas, aArgs, aCallback) {
|
||||
async _captureToCanvas(aBrowser, aCanvas, aArgs) {
|
||||
if (aBrowser.isRemoteBrowser) {
|
||||
(async () => {
|
||||
let data = await this._captureRemoteThumbnail(
|
||||
aBrowser,
|
||||
aCanvas.width,
|
||||
aCanvas.height,
|
||||
aArgs
|
||||
);
|
||||
let canvas = data.thumbnail;
|
||||
let ctx = canvas.getContext("2d");
|
||||
let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
aCanvas.width = canvas.width;
|
||||
aCanvas.height = canvas.height;
|
||||
let thumbnail = await this._captureRemoteThumbnail(
|
||||
aBrowser,
|
||||
aCanvas.width,
|
||||
aCanvas.height,
|
||||
aArgs
|
||||
);
|
||||
|
||||
// 'thumbnail' can be null if the browser has navigated away after starting
|
||||
// the thumbnail request, so we check it here.
|
||||
if (thumbnail) {
|
||||
let ctx = thumbnail.getContext("2d");
|
||||
let imgData = ctx.getImageData(0, 0, thumbnail.width, thumbnail.height);
|
||||
aCanvas.width = thumbnail.width;
|
||||
aCanvas.height = thumbnail.height;
|
||||
aCanvas.getContext("2d").putImageData(imgData, 0, 0);
|
||||
if (aCallback) {
|
||||
aCallback(aCanvas);
|
||||
}
|
||||
})();
|
||||
return;
|
||||
}
|
||||
return aCanvas;
|
||||
}
|
||||
// The content is a local page, grab a thumbnail sync.
|
||||
PageThumbUtils.createSnapshotThumbnail(
|
||||
@ -290,10 +269,7 @@ var PageThumbs = {
|
||||
aCanvas,
|
||||
aArgs
|
||||
);
|
||||
|
||||
if (aCallback) {
|
||||
aCallback(aCanvas);
|
||||
}
|
||||
return aCanvas;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -306,65 +282,48 @@ var PageThumbs = {
|
||||
* fullScale - request that a non-downscaled image be returned.
|
||||
* @return a promise
|
||||
*/
|
||||
_captureRemoteThumbnail(aBrowser, aWidth, aHeight, aArgs) {
|
||||
return new Promise(resolve => {
|
||||
// The index we send with the request so we can identify the
|
||||
// correct response.
|
||||
let index = gRemoteThumbId++;
|
||||
|
||||
// Thumbnail request response handler
|
||||
let mm = aBrowser.messageManager;
|
||||
|
||||
// Browser:Thumbnail:Response handler
|
||||
let thumbFunc = function(aMsg) {
|
||||
// Ignore events unrelated to our request
|
||||
if (aMsg.data.id != index) {
|
||||
return;
|
||||
}
|
||||
|
||||
mm.removeMessageListener("Browser:Thumbnail:Response", thumbFunc);
|
||||
let imageBlob = aMsg.data.thumbnail;
|
||||
let doc = aBrowser.parentElement.ownerDocument;
|
||||
let reader = new FileReader();
|
||||
reader.addEventListener("loadend", function() {
|
||||
let image = doc.createElementNS(PageThumbUtils.HTML_NAMESPACE, "img");
|
||||
image.onload = function() {
|
||||
let thumbnail = doc.createElementNS(
|
||||
PageThumbUtils.HTML_NAMESPACE,
|
||||
"canvas"
|
||||
);
|
||||
thumbnail.width = image.naturalWidth;
|
||||
thumbnail.height = image.naturalHeight;
|
||||
let ctx = thumbnail.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
resolve({
|
||||
thumbnail,
|
||||
});
|
||||
};
|
||||
image.src = reader.result;
|
||||
});
|
||||
// xxx wish there was a way to skip this encoding step
|
||||
reader.readAsDataURL(imageBlob);
|
||||
};
|
||||
|
||||
// Send a thumbnail request
|
||||
mm.addMessageListener("Browser:Thumbnail:Response", thumbFunc);
|
||||
mm.sendAsyncMessage("Browser:Thumbnail:Request", {
|
||||
canvasWidth: aWidth,
|
||||
canvasHeight: aHeight,
|
||||
background: PageThumbUtils.THUMBNAIL_BG_COLOR,
|
||||
id: index,
|
||||
additionalArgs: aArgs,
|
||||
});
|
||||
});
|
||||
async _captureRemoteThumbnail(aBrowser, aWidth, aHeight, aArgs) {
|
||||
if (!aBrowser.browsingContext) {
|
||||
return null;
|
||||
}
|
||||
let thumbnailsActor = aBrowser.browsingContext.currentWindowGlobal.getActor(
|
||||
"Thumbnails"
|
||||
);
|
||||
let [contentWidth, contentHeight] = await thumbnailsActor.sendQuery(
|
||||
"Browser:Thumbnail:ContentSize"
|
||||
);
|
||||
let fullScale = aArgs ? aArgs.fullScale : false;
|
||||
let scale = fullScale
|
||||
? 1
|
||||
: Math.min(Math.max(aWidth / contentWidth, aHeight / contentHeight), 1);
|
||||
let image = await aBrowser.drawSnapshot(
|
||||
0,
|
||||
0,
|
||||
contentWidth,
|
||||
contentHeight,
|
||||
scale,
|
||||
PageThumbUtils.THUMBNAIL_BG_COLOR
|
||||
);
|
||||
if (aBrowser.parentElement) {
|
||||
let doc = aBrowser.parentElement.ownerDocument;
|
||||
let thumbnail = doc.createElementNS(
|
||||
PageThumbUtils.HTML_NAMESPACE,
|
||||
"canvas"
|
||||
);
|
||||
thumbnail.width = aWidth;
|
||||
thumbnail.height = aHeight;
|
||||
let ctx = thumbnail.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
return thumbnail;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Captures a thumbnail for the given browser and stores it to the cache.
|
||||
* @param aBrowser The browser to capture a thumbnail for.
|
||||
* @param aCallback The function to be called when finished (optional).
|
||||
*/
|
||||
captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
|
||||
captureAndStore: async function PageThumbs_captureAndStore(aBrowser) {
|
||||
if (!this._prefEnabled()) {
|
||||
return;
|
||||
}
|
||||
@ -373,41 +332,30 @@ var PageThumbs = {
|
||||
let originalURL;
|
||||
let channelError = false;
|
||||
|
||||
(async () => {
|
||||
if (!aBrowser.isRemoteBrowser) {
|
||||
let channel = aBrowser.docShell.currentDocumentChannel;
|
||||
originalURL = channel.originalURI.spec;
|
||||
// see if this was an error response.
|
||||
channelError = PageThumbUtils.isChannelErrorResponse(channel);
|
||||
} else {
|
||||
let resp = await new Promise(resolve => {
|
||||
let mm = aBrowser.messageManager;
|
||||
let respName = "Browser:Thumbnail:GetOriginalURL:Response";
|
||||
mm.addMessageListener(respName, function onResp(msg) {
|
||||
mm.removeMessageListener(respName, onResp);
|
||||
resolve(msg.data);
|
||||
});
|
||||
mm.sendAsyncMessage("Browser:Thumbnail:GetOriginalURL");
|
||||
});
|
||||
originalURL = resp.originalURL || url;
|
||||
channelError = resp.channelError;
|
||||
}
|
||||
if (!aBrowser.isRemoteBrowser) {
|
||||
let channel = aBrowser.docShell.currentDocumentChannel;
|
||||
originalURL = channel.originalURI.spec;
|
||||
// see if this was an error response.
|
||||
channelError = PageThumbUtils.isChannelErrorResponse(channel);
|
||||
} else {
|
||||
let thumbnailsActor = aBrowser.browsingContext.currentWindowGlobal.getActor(
|
||||
"Thumbnails"
|
||||
);
|
||||
let resp = await thumbnailsActor.sendQuery(
|
||||
"Browser:Thumbnail:GetOriginalURL"
|
||||
);
|
||||
|
||||
let isSuccess = true;
|
||||
try {
|
||||
let blob = await this.captureToBlob(aBrowser);
|
||||
let buffer = await TaskUtils.readBlob(blob);
|
||||
await this._store(originalURL, url, buffer, channelError);
|
||||
} catch (ex) {
|
||||
Cu.reportError(
|
||||
"Exception thrown during thumbnail capture: '" + ex + "'"
|
||||
);
|
||||
isSuccess = false;
|
||||
}
|
||||
if (aCallback) {
|
||||
aCallback(isSuccess);
|
||||
}
|
||||
})();
|
||||
originalURL = resp.originalURL || url;
|
||||
channelError = resp.channelError;
|
||||
}
|
||||
|
||||
try {
|
||||
let blob = await this.captureToBlob(aBrowser);
|
||||
let buffer = await TaskUtils.readBlob(blob);
|
||||
await this._store(originalURL, url, buffer, channelError);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Exception thrown during thumbnail capture: '" + ex + "'");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -417,33 +365,30 @@ var PageThumbs = {
|
||||
* such notifications if they want to be notified of an updated thumbnail.
|
||||
*
|
||||
* @param aBrowser The content window of this browser will be captured.
|
||||
* @param aCallback The function to be called when finished (optional).
|
||||
*/
|
||||
captureAndStoreIfStale: function PageThumbs_captureAndStoreIfStale(
|
||||
aBrowser,
|
||||
aCallback
|
||||
captureAndStoreIfStale: async function PageThumbs_captureAndStoreIfStale(
|
||||
aBrowser
|
||||
) {
|
||||
if (!aBrowser.currentURI) {
|
||||
return false;
|
||||
}
|
||||
let url = aBrowser.currentURI.spec;
|
||||
PageThumbsStorage.isFileRecentForURL(url).then(
|
||||
recent => {
|
||||
if (
|
||||
!recent &&
|
||||
// Careful, the call to PageThumbsStorage is async, so the browser may
|
||||
// have navigated away from the URL or even closed.
|
||||
aBrowser.currentURI &&
|
||||
aBrowser.currentURI.spec == url
|
||||
) {
|
||||
this.captureAndStore(aBrowser, aCallback);
|
||||
} else if (aCallback) {
|
||||
aCallback(true);
|
||||
}
|
||||
},
|
||||
err => {
|
||||
if (aCallback) {
|
||||
aCallback(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
let recent;
|
||||
try {
|
||||
recent = await PageThumbsStorage.isFileRecentForURL(url);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
!recent &&
|
||||
// Careful, the call to PageThumbsStorage is async, so the browser may
|
||||
// have navigated away from the URL or even closed.
|
||||
aBrowser.currentURI &&
|
||||
aBrowser.currentURI.spec == url
|
||||
) {
|
||||
await this.captureAndStore(aBrowser);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -456,42 +401,35 @@ var PageThumbs = {
|
||||
* @param aData An ArrayBuffer containing the image data.
|
||||
* @param aNoOverwrite If true and files for the URLs already exist, the files
|
||||
* will not be overwritten.
|
||||
* @return {Promise}
|
||||
*/
|
||||
_store: function PageThumbs__store(
|
||||
_store: async function PageThumbs__store(
|
||||
aOriginalURL,
|
||||
aFinalURL,
|
||||
aData,
|
||||
aNoOverwrite
|
||||
) {
|
||||
return (async function() {
|
||||
let telemetryStoreTime = new Date();
|
||||
await PageThumbsStorage.writeData(aFinalURL, aData, aNoOverwrite);
|
||||
Services.telemetry
|
||||
.getHistogramById("FX_THUMBNAILS_STORE_TIME_MS")
|
||||
.add(new Date() - telemetryStoreTime);
|
||||
let telemetryStoreTime = new Date();
|
||||
await PageThumbsStorage.writeData(aFinalURL, aData, aNoOverwrite);
|
||||
Services.telemetry
|
||||
.getHistogramById("FX_THUMBNAILS_STORE_TIME_MS")
|
||||
.add(new Date() - telemetryStoreTime);
|
||||
|
||||
Services.obs.notifyObservers(null, "page-thumbnail:create", aFinalURL);
|
||||
// We've been redirected. Create a copy of the current thumbnail for
|
||||
// the redirect source. We need to do this because:
|
||||
//
|
||||
// 1) Users can drag any kind of links onto the newtab page. If those
|
||||
// links redirect to a different URL then we want to be able to
|
||||
// provide thumbnails for both of them.
|
||||
//
|
||||
// 2) The newtab page should actually display redirect targets, only.
|
||||
// Because of bug 559175 this information can get lost when using
|
||||
// Sync and therefore also redirect sources appear on the newtab
|
||||
// page. We also want thumbnails for those.
|
||||
if (aFinalURL != aOriginalURL) {
|
||||
await PageThumbsStorage.copy(aFinalURL, aOriginalURL, aNoOverwrite);
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"page-thumbnail:create",
|
||||
aOriginalURL
|
||||
);
|
||||
}
|
||||
})();
|
||||
Services.obs.notifyObservers(null, "page-thumbnail:create", aFinalURL);
|
||||
// We've been redirected. Create a copy of the current thumbnail for
|
||||
// the redirect source. We need to do this because:
|
||||
//
|
||||
// 1) Users can drag any kind of links onto the newtab page. If those
|
||||
// links redirect to a different URL then we want to be able to
|
||||
// provide thumbnails for both of them.
|
||||
//
|
||||
// 2) The newtab page should actually display redirect targets, only.
|
||||
// Because of bug 559175 this information can get lost when using
|
||||
// Sync and therefore also redirect sources appear on the newtab
|
||||
// page. We also want thumbnails for those.
|
||||
if (aFinalURL != aOriginalURL) {
|
||||
await PageThumbsStorage.copy(aFinalURL, aOriginalURL, aNoOverwrite);
|
||||
Services.obs.notifyObservers(null, "page-thumbnail:create", aOriginalURL);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -12,7 +12,7 @@ function* runTests() {
|
||||
yield BrowserTestUtils.waitForContentEvent(browser, "DOMContentLoaded");
|
||||
|
||||
yield new Promise(resolve => {
|
||||
PageThumbs.shouldStoreThumbnail(browser, aResult => {
|
||||
PageThumbs.shouldStoreThumbnail(browser).then(aResult => {
|
||||
ok(!aResult, "we're not going to capture an error page");
|
||||
resolve();
|
||||
});
|
||||
|
@ -64,13 +64,12 @@ function testCombination(combi, url, aCombinations, aResult) {
|
||||
let tab = (gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, url));
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
BrowserTestUtils.browserLoaded(browser).then(() => {
|
||||
BrowserTestUtils.browserLoaded(browser).then(async () => {
|
||||
let msg = JSON.stringify(combi) + " == " + aResult;
|
||||
PageThumbs.shouldStoreThumbnail(browser, aIsSafeSite => {
|
||||
is(aIsSafeSite, aResult, msg);
|
||||
gBrowser.removeTab(tab);
|
||||
// Continue with the next combination.
|
||||
checkCombinations(aCombinations, aResult);
|
||||
});
|
||||
let aIsSafeSite = await PageThumbs.shouldStoreThumbnail(browser);
|
||||
is(aIsSafeSite, aResult, msg);
|
||||
gBrowser.removeTab(tab);
|
||||
// Continue with the next combination.
|
||||
checkCombinations(aCombinations, aResult);
|
||||
});
|
||||
}
|
||||
|
@ -64,12 +64,12 @@ function* simpleCaptureTest() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
// Capture the screenshot.
|
||||
PageThumbs.captureAndStore(browser, function() {
|
||||
PageThumbs.captureAndStore(browser).then(function() {
|
||||
// We've got a capture so should have seen the observer.
|
||||
is(numNotifications, 1, "got notification of item being created.");
|
||||
// The capture is now "fresh" - so requesting the URL should not cause
|
||||
// a new capture.
|
||||
PageThumbs.captureAndStoreIfStale(browser, function() {
|
||||
PageThumbs.captureAndStoreIfStale(browser).then(function() {
|
||||
is(
|
||||
numNotifications,
|
||||
1,
|
||||
@ -105,7 +105,9 @@ function* capIfStaleErrorResponseUpdateTest() {
|
||||
// As we set the thumbnail very stale, allowing 1 second of "slop" here
|
||||
// works around this while still keeping the test valid.
|
||||
let now = Date.now() - 1000;
|
||||
PageThumbs.captureAndStoreIfStale(gBrowser.selectedBrowser, () => {
|
||||
PageThumbs.captureAndStoreIfStale(gBrowser.selectedBrowser).then(() => {
|
||||
PageThumbsStorageService.getFilePathForURL(URL);
|
||||
|
||||
ok(getThumbnailModifiedTime(URL) < now, "modified time should be < now");
|
||||
retrieveImageDataForURL(URL, function([r, g, b]) {
|
||||
is("" + [r, g, b], "" + [0, 255, 0], "thumbnail is still green");
|
||||
@ -136,7 +138,7 @@ function* capIfStaleGoodResponseUpdateTest() {
|
||||
// As we set the thumbnail very stale, allowing 1 second of "slop" here
|
||||
// works around this while still keeping the test valid.
|
||||
let now = Date.now() - 1000;
|
||||
PageThumbs.captureAndStoreIfStale(browser, () => {
|
||||
PageThumbs.captureAndStoreIfStale(browser).then(() => {
|
||||
ok(getThumbnailModifiedTime(URL) >= now, "modified time should be >= now");
|
||||
// the captureAndStoreIfStale request saw a 200 response with the red body,
|
||||
// so we expect to see the red version here.
|
||||
|
@ -157,18 +157,17 @@ function whenLoaded(aElement, aCallback = next) {
|
||||
* @param aBlue The blue component's intensity.
|
||||
* @param aMessage The info message to print when comparing the pixel color.
|
||||
*/
|
||||
function captureAndCheckColor(aRed, aGreen, aBlue, aMessage) {
|
||||
async function captureAndCheckColor(aRed, aGreen, aBlue, aMessage) {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
// We'll get oranges if the expiration filter removes the file during the
|
||||
// test.
|
||||
dontExpireThumbnailURLs([browser.currentURI.spec]);
|
||||
|
||||
// Capture the screenshot.
|
||||
PageThumbs.captureAndStore(browser, function() {
|
||||
retrieveImageDataForURL(browser.currentURI.spec, function([r, g, b]) {
|
||||
is("" + [r, g, b], "" + [aRed, aGreen, aBlue], aMessage);
|
||||
next();
|
||||
});
|
||||
await PageThumbs.captureAndStore(browser);
|
||||
retrieveImageDataForURL(browser.currentURI.spec, function([r, g, b]) {
|
||||
is("" + [r, g, b], "" + [aRed, aGreen, aBlue], aMessage);
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -685,7 +685,10 @@
|
||||
}
|
||||
|
||||
get browsingContext() {
|
||||
return this.frameLoader.browsingContext;
|
||||
if (this.frameLoader) {
|
||||
return this.frameLoader.browsingContext;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Note that this overrides webNavigation on XULFrameElement, and duplicates the return value for the non-remote case
|
||||
@ -2086,11 +2089,17 @@
|
||||
);
|
||||
}
|
||||
|
||||
drawSnapshot(x, y, w, h, scale, backgroundColor) {
|
||||
if (!this.frameLoader) {
|
||||
throw Components.Exception("No frame loader.", Cr.NS_ERROR_FAILURE);
|
||||
async drawSnapshot(x, y, w, h, scale, backgroundColor) {
|
||||
let rect = new DOMRect(x, y, w, h);
|
||||
try {
|
||||
return this.browsingContext.currentWindowGlobal.drawSnapshot(
|
||||
rect,
|
||||
scale,
|
||||
backgroundColor
|
||||
);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return this.frameLoader.drawSnapshot(x, y, w, h, scale, backgroundColor);
|
||||
}
|
||||
|
||||
dropLinks(aLinks, aTriggeringPrincipal) {
|
||||
|
@ -381,6 +381,12 @@ let ACTORS = {
|
||||
allFrames: true,
|
||||
},
|
||||
|
||||
Thumbnails: {
|
||||
child: {
|
||||
moduleURI: "resource://gre/actors/ThumbnailsChild.jsm",
|
||||
},
|
||||
},
|
||||
|
||||
Zoom: {
|
||||
parent: {
|
||||
moduleURI: "resource://gre/actors/ZoomParent.jsm",
|
||||
@ -478,17 +484,6 @@ let LEGACY_ACTORS = {
|
||||
},
|
||||
},
|
||||
|
||||
Thumbnails: {
|
||||
child: {
|
||||
module: "resource://gre/actors/ThumbnailsChild.jsm",
|
||||
messages: [
|
||||
"Browser:Thumbnail:Request",
|
||||
"Browser:Thumbnail:CheckState",
|
||||
"Browser:Thumbnail:GetOriginalURL",
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
UnselectedTabHover: {
|
||||
child: {
|
||||
module: "resource://gre/actors/UnselectedTabHoverChild.jsm",
|
||||
|
Loading…
Reference in New Issue
Block a user