mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 1096804 - Add support to PageThumbs for requesting non-downsampled content screenshots. r=dao
This commit is contained in:
parent
3e43959d68
commit
0f68cf1319
@ -296,11 +296,14 @@ PreviewController.prototype = {
|
||||
ctx.drawWindow(this.win.win, 0, 0, winWidth, winHeight, "rgba(0,0,0,0)");
|
||||
|
||||
// Draw the content are into the composite canvas at the right location.
|
||||
ctx.drawImage(aPreviewCanvas, this.browserDims.x, this.browserDims.y, aPreviewCanvas.width, aPreviewCanvas.height);
|
||||
ctx.drawImage(aPreviewCanvas, this.browserDims.x, this.browserDims.y,
|
||||
aPreviewCanvas.width, aPreviewCanvas.height);
|
||||
ctx.restore();
|
||||
|
||||
// Deliver the resulting composite canvas to Windows
|
||||
this.win.tabbrowser.previewTab(this.tab, function () { aTaskbarCallback.done(composite, false); });
|
||||
this.win.tabbrowser.previewTab(this.tab, function () {
|
||||
aTaskbarCallback.done(composite, false);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@ -379,7 +382,7 @@ function TabWindow(win) {
|
||||
this.win.addEventListener(this.winEvents[i], this, false);
|
||||
|
||||
this.tabbrowser.addTabsProgressListener(this);
|
||||
|
||||
|
||||
AeroPeek.windows.push(this);
|
||||
let tabs = this.tabbrowser.tabs;
|
||||
for (let i = 0; i < tabs.length; i++)
|
||||
|
@ -139,50 +139,55 @@ this.PageThumbUtils = {
|
||||
* jagged pixels to represent text.
|
||||
*
|
||||
* @params aWindow - the window to create a snapshot of.
|
||||
* @params aDestCanvas (optional) a destination canvas to draw the final snapshot to.
|
||||
* @params aDestCanvas destination canvas to draw the final
|
||||
* snapshot to. Can be null.
|
||||
* @param aArgs (optional) Additional named parameters:
|
||||
* fullScale - request that a non-downscaled image be returned.
|
||||
* @return Canvas with a scaled thumbnail of the window.
|
||||
*/
|
||||
createSnapshotThumbnail: function(aWindow, aDestCanvas = null) {
|
||||
createSnapshotThumbnail: function(aWindow, aDestCanvas, aArgs) {
|
||||
if (Cu.isCrossProcessWrapper(aWindow)) {
|
||||
throw new Error('Do not pass cpows here.');
|
||||
}
|
||||
|
||||
let fullScale = aArgs ? aArgs.fullScale : false;
|
||||
let [contentWidth, contentHeight] = this.getContentSize(aWindow);
|
||||
let [thumbnailWidth, thumbnailHeight] = aDestCanvas ?
|
||||
[aDestCanvas.width, aDestCanvas.height] :
|
||||
this.getThumbnailSize(aWindow);
|
||||
|
||||
// If the caller wants a fullscale image, set the desired thumbnail dims
|
||||
// to the dims of content and (if provided) size the incoming canvas to
|
||||
// support our results.
|
||||
if (fullScale) {
|
||||
thumbnailWidth = contentWidth;
|
||||
thumbnailHeight = contentHeight;
|
||||
if (aDestCanvas) {
|
||||
aDestCanvas.width = contentWidth;
|
||||
aDestCanvas.height = contentHeight;
|
||||
}
|
||||
}
|
||||
|
||||
let intermediateWidth = thumbnailWidth * 2;
|
||||
let intermediateHeight = thumbnailHeight * 2;
|
||||
let skipDownscale = false;
|
||||
let snapshotCanvas = undefined;
|
||||
|
||||
// Our intermediate thumbnail is bigger than content,
|
||||
// which can happen on hiDPI devices like a retina macbook pro.
|
||||
// In those cases, just render at the final size.
|
||||
if ((intermediateWidth >= contentWidth) ||
|
||||
(intermediateHeight >= contentHeight)) {
|
||||
// If the intermediate thumbnail is larger than content dims (hiDPI
|
||||
// devices can experience this) or a full preview is requested render
|
||||
// at the final thumbnail size.
|
||||
if ((intermediateWidth >= contentWidth ||
|
||||
intermediateHeight >= contentHeight) || fullScale) {
|
||||
intermediateWidth = thumbnailWidth;
|
||||
intermediateHeight = thumbnailHeight;
|
||||
skipDownscale = true;
|
||||
snapshotCanvas = aDestCanvas;
|
||||
}
|
||||
|
||||
// If we've been given a large preallocated canvas, so
|
||||
// just render once into the destination canvas.
|
||||
if (aDestCanvas &&
|
||||
((aDestCanvas.width >= intermediateWidth) ||
|
||||
(aDestCanvas.height >= intermediateHeight))) {
|
||||
intermediateWidth = aDestCanvas.width;
|
||||
intermediateHeight = aDestCanvas.height;
|
||||
skipDownscale = true;
|
||||
snapshotCanvas = aDestCanvas;
|
||||
}
|
||||
// Create an intermediate surface
|
||||
let snapshotCanvas = this.createCanvas(aWindow, intermediateWidth,
|
||||
intermediateHeight);
|
||||
|
||||
if (!snapshotCanvas) {
|
||||
snapshotCanvas = this.createCanvas(aWindow, intermediateWidth, intermediateHeight);
|
||||
}
|
||||
|
||||
// This is step 1.
|
||||
// Step 1: capture the image at the intermediate dims. For thumbnails
|
||||
// this is twice the thumbnail size, for fullScale images this is at
|
||||
// content dims.
|
||||
// Also by default, canvas does not draw the scrollbars, so no need to
|
||||
// remove the scrollbar sizes.
|
||||
let scale = Math.min(Math.max(intermediateWidth / contentWidth,
|
||||
@ -195,18 +200,21 @@ this.PageThumbUtils = {
|
||||
PageThumbUtils.THUMBNAIL_BG_COLOR,
|
||||
snapshotCtx.DRAWWINDOW_DO_NOT_FLUSH);
|
||||
snapshotCtx.restore();
|
||||
if (skipDownscale) {
|
||||
return snapshotCanvas;
|
||||
}
|
||||
|
||||
// Part 2: Assumes that the snapshot is 2x the thumbnail size
|
||||
let finalCanvas = aDestCanvas || this.createCanvas(aWindow, thumbnailWidth, thumbnailHeight);
|
||||
// Part 2: Downscale from our intermediate dims to the final thumbnail
|
||||
// dims and copy the result to aDestCanvas. If the caller didn't
|
||||
// provide a target canvas, create a new canvas and return it.
|
||||
let finalCanvas = aDestCanvas ||
|
||||
this.createCanvas(aWindow, thumbnailWidth, thumbnailHeight);
|
||||
|
||||
let finalCtx = finalCanvas.getContext("2d");
|
||||
finalCtx.save();
|
||||
finalCtx.scale(0.5, 0.5);
|
||||
if (!skipDownscale) {
|
||||
finalCtx.scale(0.5, 0.5);
|
||||
}
|
||||
finalCtx.drawImage(snapshotCanvas, 0, 0);
|
||||
finalCtx.restore();
|
||||
|
||||
return finalCanvas;
|
||||
},
|
||||
|
||||
|
@ -207,13 +207,20 @@ this.PageThumbs = {
|
||||
* canvas asynchronously. Pass aCallback to receive an async callback after
|
||||
* canvas painting has completed.
|
||||
* @param aBrowser The browser to capture a thumbnail from.
|
||||
* @param aCanvas The canvas to draw to.
|
||||
* @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.
|
||||
* rendered to aCanvas.
|
||||
* @param aArgs (optional) Additional named parameters:
|
||||
* fullScale - request that a non-downscaled image be returned.
|
||||
*/
|
||||
captureToCanvas: function PageThumbs_captureToCanvas(aBrowser, aCanvas, aCallback) {
|
||||
captureToCanvas: function (aBrowser, aCanvas, aCallback, aArgs) {
|
||||
let telemetryCaptureTime = new Date();
|
||||
this._captureToCanvas(aBrowser, aCanvas, function () {
|
||||
let args = {
|
||||
fullScale: aArgs ? aArgs.fullScale : false
|
||||
};
|
||||
this._captureToCanvas(aBrowser, aCanvas, args, (aCanvas) => {
|
||||
Services.telemetry
|
||||
.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS")
|
||||
.add(new Date() - telemetryCaptureTime);
|
||||
@ -257,14 +264,17 @@ this.PageThumbs = {
|
||||
|
||||
// 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: function (aBrowser, aCanvas, aCallback) {
|
||||
_captureToCanvas: function (aBrowser, aCanvas, aArgs, aCallback) {
|
||||
if (aBrowser.isRemoteBrowser) {
|
||||
Task.spawn(function* () {
|
||||
let data =
|
||||
yield this._captureRemoteThumbnail(aBrowser, aCanvas);
|
||||
yield 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;
|
||||
aCanvas.getContext("2d").putImageData(imgData, 0, 0);
|
||||
if (aCallback) {
|
||||
aCallback(aCanvas);
|
||||
@ -272,8 +282,10 @@ this.PageThumbs = {
|
||||
}.bind(this));
|
||||
return;
|
||||
}
|
||||
|
||||
aCanvas = PageThumbUtils.createSnapshotThumbnail(aBrowser.contentWindow, aCanvas);
|
||||
// The content is a local page, grab a thumbnail sync.
|
||||
PageThumbUtils.createSnapshotThumbnail(aBrowser.contentWindow,
|
||||
aCanvas,
|
||||
aArgs);
|
||||
|
||||
if (aCallback) {
|
||||
aCallback(aCanvas);
|
||||
@ -284,10 +296,13 @@ this.PageThumbs = {
|
||||
* Asynchrnously render an appropriately scaled thumbnail to canvas.
|
||||
*
|
||||
* @param aBrowser The browser to capture a thumbnail from.
|
||||
* @param aCanvas The canvas to draw to.
|
||||
* @param aWidth The desired canvas width.
|
||||
* @param aHeight The desired canvas height.
|
||||
* @param aArgs (optional) Additional named parameters:
|
||||
* fullScale - request that a non-downscaled image be returned.
|
||||
* @return a promise
|
||||
*/
|
||||
_captureRemoteThumbnail: function (aBrowser, aCanvas) {
|
||||
_captureRemoteThumbnail: function (aBrowser, aWidth, aHeight, aArgs) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
// The index we send with the request so we can identify the
|
||||
@ -329,10 +344,11 @@ this.PageThumbs = {
|
||||
// Send a thumbnail request
|
||||
mm.addMessageListener("Browser:Thumbnail:Response", thumbFunc);
|
||||
mm.sendAsyncMessage("Browser:Thumbnail:Request", {
|
||||
canvasWidth: aCanvas.width,
|
||||
canvasHeight: aCanvas.height,
|
||||
canvasWidth: aWidth,
|
||||
canvasHeight: aHeight,
|
||||
background: PageThumbUtils.THUMBNAIL_BG_COLOR,
|
||||
id: index
|
||||
id: index,
|
||||
additionalArgs: aArgs
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
|
@ -133,7 +133,7 @@ const backgroundPageThumbsContent = {
|
||||
|
||||
let canvasDrawDate = new Date();
|
||||
|
||||
let finalCanvas = PageThumbUtils.createSnapshotThumbnail(content);
|
||||
let finalCanvas = PageThumbUtils.createSnapshotThumbnail(content, null);
|
||||
capture.canvasDrawTime = new Date() - canvasDrawDate;
|
||||
|
||||
finalCanvas.toBlob(blob => {
|
||||
|
@ -467,10 +467,18 @@ addMessageListener("UpdateCharacterSet", function (aMessage) {
|
||||
* Remote thumbnail request handler for PageThumbs thumbnails.
|
||||
*/
|
||||
addMessageListener("Browser:Thumbnail:Request", function (aMessage) {
|
||||
let snapshotWidth = aMessage.data.canvasWidth;
|
||||
let snapshotHeight = aMessage.data.canvasHeight;
|
||||
let canvas = PageThumbUtils.createCanvas(content, snapshotWidth, snapshotHeight);
|
||||
let snapshot = PageThumbUtils.createSnapshotThumbnail(content, canvas);
|
||||
let snapshot;
|
||||
let args = aMessage.data.additionalArgs;
|
||||
let fullScale = args ? args.fullScale : false;
|
||||
if (fullScale) {
|
||||
snapshot = PageThumbUtils.createSnapshotThumbnail(content, null, args);
|
||||
} else {
|
||||
let snapshotWidth = aMessage.data.canvasWidth;
|
||||
let snapshotHeight = aMessage.data.canvasHeight;
|
||||
snapshot =
|
||||
PageThumbUtils.createCanvas(content, snapshotWidth, snapshotHeight);
|
||||
PageThumbUtils.createSnapshotThumbnail(content, snapshot, args);
|
||||
}
|
||||
|
||||
snapshot.toBlob(function (aBlob) {
|
||||
sendAsyncMessage("Browser:Thumbnail:Response", {
|
||||
|
Loading…
Reference in New Issue
Block a user