зеркало из https://github.com/mozilla/gecko-dev.git
Bug 497543 - Part 1 - JavaScript Module; r=dietrich
This commit is contained in:
Родитель
55aff2dc60
Коммит
5831fad834
|
@ -52,6 +52,7 @@ EXTRA_JS_MODULES = \
|
||||||
openLocationLastURL.jsm \
|
openLocationLastURL.jsm \
|
||||||
NetworkPrioritizer.jsm \
|
NetworkPrioritizer.jsm \
|
||||||
offlineAppCache.jsm \
|
offlineAppCache.jsm \
|
||||||
|
PageThumbs.jsm \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
/* 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";
|
||||||
|
|
||||||
|
let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsCache"];
|
||||||
|
|
||||||
|
const Cu = Components.utils;
|
||||||
|
const Cc = Components.classes;
|
||||||
|
const Ci = Components.interfaces;
|
||||||
|
|
||||||
|
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default width for page thumbnails.
|
||||||
|
*
|
||||||
|
* Hint: This is the default value because the 'New Tab Page' is the only
|
||||||
|
* client for now.
|
||||||
|
*/
|
||||||
|
const THUMBNAIL_WIDTH = 201;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default height for page thumbnails.
|
||||||
|
*
|
||||||
|
* Hint: This is the default value because the 'New Tab Page' is the only
|
||||||
|
* client for now.
|
||||||
|
*/
|
||||||
|
const THUMBNAIL_HEIGHT = 127;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default background color for page thumbnails.
|
||||||
|
*/
|
||||||
|
const THUMBNAIL_BG_COLOR = "#fff";
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||||
|
"resource://gre/modules/NetUtil.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||||
|
"resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton providing functionality for capturing web page thumbnails and for
|
||||||
|
* accessing them if already cached.
|
||||||
|
*/
|
||||||
|
let PageThumbs = {
|
||||||
|
/**
|
||||||
|
* The scheme to use for thumbnail urls.
|
||||||
|
*/
|
||||||
|
get scheme() "moz-page-thumb",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The static host to use for thumbnail urls.
|
||||||
|
*/
|
||||||
|
get staticHost() "thumbnail",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The thumbnails' image type.
|
||||||
|
*/
|
||||||
|
get contentType() "image/png",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the thumbnail image's url for a given web page's url.
|
||||||
|
* @param aUrl The web page's url that is depicted in the thumbnail.
|
||||||
|
* @return The thumbnail image's url.
|
||||||
|
*/
|
||||||
|
getThumbnailURL: function PageThumbs_getThumbnailURL(aUrl) {
|
||||||
|
return this.scheme + "://" + this.staticHost +
|
||||||
|
"?url=" + encodeURIComponent(aUrl);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a canvas containing a thumbnail depicting the given window.
|
||||||
|
* @param aWindow The DOM window to capture a thumbnail from.
|
||||||
|
* @return The newly created canvas containing the image data.
|
||||||
|
*/
|
||||||
|
capture: function PageThumbs_capture(aWindow) {
|
||||||
|
let [sx, sy, sw, sh, scale] = this._determineCropRectangle(aWindow);
|
||||||
|
|
||||||
|
let canvas = this._createCanvas();
|
||||||
|
let ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
// Scale the canvas accordingly.
|
||||||
|
ctx.scale(scale, scale);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Draw the window contents to the canvas.
|
||||||
|
ctx.drawWindow(aWindow, sx, sy, sw, sh, THUMBNAIL_BG_COLOR,
|
||||||
|
ctx.DRAWWINDOW_DO_NOT_FLUSH);
|
||||||
|
} catch (e) {
|
||||||
|
// We couldn't draw to the canvas for some reason.
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the image data contained in the given canvas to the underlying
|
||||||
|
* storage.
|
||||||
|
* @param aKey The key to use for the storage.
|
||||||
|
* @param aCanvas The canvas containing the thumbnail's image data.
|
||||||
|
* @param aCallback The function to be called when the canvas data has been
|
||||||
|
* stored (optional).
|
||||||
|
*/
|
||||||
|
store: function PageThumbs_store(aKey, aCanvas, aCallback) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
function finish(aSuccessful) {
|
||||||
|
if (aCallback)
|
||||||
|
aCallback(aSuccessful);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a writeable cache entry.
|
||||||
|
PageThumbsCache.getWriteEntry(aKey, function (aEntry) {
|
||||||
|
if (!aEntry) {
|
||||||
|
finish(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract image data from the canvas.
|
||||||
|
self._readImageData(aCanvas, function (aData) {
|
||||||
|
let outputStream = aEntry.openOutputStream(0);
|
||||||
|
|
||||||
|
// Write the image data to the cache entry.
|
||||||
|
NetUtil.asyncCopy(aData, outputStream, function (aResult) {
|
||||||
|
let success = Components.isSuccessCode(aResult);
|
||||||
|
if (success)
|
||||||
|
aEntry.markValid();
|
||||||
|
|
||||||
|
aEntry.close();
|
||||||
|
finish(success);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the image data from a given canvas and passes it to the callback.
|
||||||
|
* @param aCanvas The canvas to read the image data from.
|
||||||
|
* @param aCallback The function that the image data is passed to.
|
||||||
|
*/
|
||||||
|
_readImageData: function PageThumbs_readImageData(aCanvas, aCallback) {
|
||||||
|
let dataUri = aCanvas.toDataURL(PageThumbs.contentType, "");
|
||||||
|
let uri = Services.io.newURI(dataUri, "UTF8", null);
|
||||||
|
|
||||||
|
NetUtil.asyncFetch(uri, function (aData, aResult) {
|
||||||
|
if (Components.isSuccessCode(aResult) && aData && aData.available())
|
||||||
|
aCallback(aData);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the crop rectangle for a given content window.
|
||||||
|
* @param aWindow The content window.
|
||||||
|
* @return An array containing x, y, width, heigh and the scale of the crop
|
||||||
|
* rectangle.
|
||||||
|
*/
|
||||||
|
_determineCropRectangle: function PageThumbs_determineCropRectangle(aWindow) {
|
||||||
|
let sx = 0;
|
||||||
|
let sy = 0;
|
||||||
|
let sw = aWindow.innerWidth;
|
||||||
|
let sh = aWindow.innerHeight;
|
||||||
|
|
||||||
|
let scale = Math.max(THUMBNAIL_WIDTH / sw, THUMBNAIL_HEIGHT / sh);
|
||||||
|
let scaledWidth = sw * scale;
|
||||||
|
let scaledHeight = sh * scale;
|
||||||
|
|
||||||
|
if (scaledHeight > THUMBNAIL_HEIGHT) {
|
||||||
|
sy = Math.floor(Math.abs((scaledHeight - THUMBNAIL_HEIGHT) / 2) / scale);
|
||||||
|
sh -= 2 * sy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scaledWidth > THUMBNAIL_WIDTH) {
|
||||||
|
sx = Math.floor(Math.abs((scaledWidth - THUMBNAIL_WIDTH) / 2) / scale);
|
||||||
|
sw -= 2 * sx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [sx, sy, sw, sh, scale];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new hidden canvas element.
|
||||||
|
* @return The newly created canvas.
|
||||||
|
*/
|
||||||
|
_createCanvas: function PageThumbs_createCanvas() {
|
||||||
|
let doc = Services.appShell.hiddenDOMWindow.document;
|
||||||
|
let canvas = doc.createElementNS(HTML_NAMESPACE, "canvas");
|
||||||
|
canvas.mozOpaque = true;
|
||||||
|
canvas.width = THUMBNAIL_WIDTH;
|
||||||
|
canvas.height = THUMBNAIL_HEIGHT;
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton handling the storage of page thumbnails.
|
||||||
|
*/
|
||||||
|
let PageThumbsCache = {
|
||||||
|
/**
|
||||||
|
* Calls the given callback with a cache entry opened for reading.
|
||||||
|
* @param aKey The key identifying the desired cache entry.
|
||||||
|
* @param aCallback The callback that is called when the cache entry is ready.
|
||||||
|
*/
|
||||||
|
getReadEntry: function Cache_getReadEntry(aKey, aCallback) {
|
||||||
|
// Try to open the desired cache entry.
|
||||||
|
this._openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, aCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the given callback with a cache entry opened for writing.
|
||||||
|
* @param aKey The key identifying the desired cache entry.
|
||||||
|
* @param aCallback The callback that is called when the cache entry is ready.
|
||||||
|
*/
|
||||||
|
getWriteEntry: function Cache_getWriteEntry(aKey, aCallback) {
|
||||||
|
// Try to open the desired cache entry.
|
||||||
|
this._openCacheEntry(aKey, Ci.nsICache.ACCESS_WRITE, aCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the cache entry identified by the given key.
|
||||||
|
* @param aKey The key identifying the desired cache entry.
|
||||||
|
* @param aAccess The desired access mode (see nsICache.ACCESS_* constants).
|
||||||
|
* @param aCallback The function to be called when the cache entry was opened.
|
||||||
|
*/
|
||||||
|
_openCacheEntry: function Cache_openCacheEntry(aKey, aAccess, aCallback) {
|
||||||
|
function onCacheEntryAvailable(aEntry, aAccessGranted, aStatus) {
|
||||||
|
let validAccess = aAccess == aAccessGranted;
|
||||||
|
let validStatus = Components.isSuccessCode(aStatus);
|
||||||
|
|
||||||
|
// Check if a valid entry was passed and if the
|
||||||
|
// access we requested was actually granted.
|
||||||
|
if (aEntry && !(validAccess && validStatus)) {
|
||||||
|
aEntry.close();
|
||||||
|
aEntry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
aCallback(aEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
let listener = this._createCacheListener(onCacheEntryAvailable);
|
||||||
|
this._cacheSession.asyncOpenCacheEntry(aKey, aAccess, listener);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a cache listener implementing the nsICacheListener interface.
|
||||||
|
* @param aCallback The callback to be called when the cache entry is available.
|
||||||
|
* @return The new cache listener.
|
||||||
|
*/
|
||||||
|
_createCacheListener: function Cache_createCacheListener(aCallback) {
|
||||||
|
return {
|
||||||
|
onCacheEntryAvailable: aCallback,
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a lazy getter for the cache session.
|
||||||
|
*/
|
||||||
|
XPCOMUtils.defineLazyGetter(PageThumbsCache, "_cacheSession", function () {
|
||||||
|
return Services.cache.createSession(PageThumbs.scheme,
|
||||||
|
Ci.nsICache.STORE_ON_DISK, true);
|
||||||
|
});
|
|
@ -63,6 +63,8 @@ XPCOMUtils.defineLazyGetter(Services, "dirsvc", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
let initTable = [
|
let initTable = [
|
||||||
|
["appShell", "@mozilla.org/appshell/appShellService;1", "nsIAppShellService"],
|
||||||
|
["cache", "@mozilla.org/network/cache-service;1", "nsICacheService"],
|
||||||
["console", "@mozilla.org/consoleservice;1", "nsIConsoleService"],
|
["console", "@mozilla.org/consoleservice;1", "nsIConsoleService"],
|
||||||
["contentPrefs", "@mozilla.org/content-pref/service;1", "nsIContentPrefService"],
|
["contentPrefs", "@mozilla.org/content-pref/service;1", "nsIContentPrefService"],
|
||||||
["cookies", "@mozilla.org/cookiemanager;1", "nsICookieManager2"],
|
["cookies", "@mozilla.org/cookiemanager;1", "nsICookieManager2"],
|
||||||
|
|
Загрузка…
Ссылка в новой задаче