1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/places/ColorAnalyzer.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,90 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +const Ci = Components.interfaces; 1.11 +const Cc = Components.classes; 1.12 +const Cu = Components.utils; 1.13 + 1.14 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.15 + 1.16 +const XHTML_NS = "http://www.w3.org/1999/xhtml"; 1.17 +const MAXIMUM_PIXELS = Math.pow(144, 2); 1.18 + 1.19 +function ColorAnalyzer() { 1.20 + // a queue of callbacks for each job we give to the worker 1.21 + this.callbacks = []; 1.22 + 1.23 + this.hiddenWindowDoc = Cc["@mozilla.org/appshell/appShellService;1"]. 1.24 + getService(Ci.nsIAppShellService). 1.25 + hiddenDOMWindow.document; 1.26 + 1.27 + this.worker = new ChromeWorker("resource://gre/modules/ColorAnalyzer_worker.js"); 1.28 + this.worker.onmessage = this.onWorkerMessage.bind(this); 1.29 + this.worker.onerror = this.onWorkerError.bind(this); 1.30 +} 1.31 + 1.32 +ColorAnalyzer.prototype = { 1.33 + findRepresentativeColor: function ColorAnalyzer_frc(imageURI, callback) { 1.34 + function cleanup() { 1.35 + image.removeEventListener("load", loadListener); 1.36 + image.removeEventListener("error", errorListener); 1.37 + } 1.38 + let image = this.hiddenWindowDoc.createElementNS(XHTML_NS, "img"); 1.39 + let loadListener = this.onImageLoad.bind(this, image, callback, cleanup); 1.40 + let errorListener = this.onImageError.bind(this, image, callback, cleanup); 1.41 + image.addEventListener("load", loadListener); 1.42 + image.addEventListener("error", errorListener); 1.43 + image.src = imageURI.spec; 1.44 + }, 1.45 + 1.46 + onImageLoad: function ColorAnalyzer_onImageLoad(image, callback, cleanup) { 1.47 + if (image.naturalWidth * image.naturalHeight > MAXIMUM_PIXELS) { 1.48 + // this will probably take too long to process - fail 1.49 + callback.onComplete(false); 1.50 + } else { 1.51 + let canvas = this.hiddenWindowDoc.createElementNS(XHTML_NS, "canvas"); 1.52 + canvas.width = image.naturalWidth; 1.53 + canvas.height = image.naturalHeight; 1.54 + let ctx = canvas.getContext("2d"); 1.55 + ctx.drawImage(image, 0, 0); 1.56 + this.startJob(ctx.getImageData(0, 0, canvas.width, canvas.height), 1.57 + callback); 1.58 + } 1.59 + cleanup(); 1.60 + }, 1.61 + 1.62 + onImageError: function ColorAnalyzer_onImageError(image, callback, cleanup) { 1.63 + Cu.reportError("ColorAnalyzer: image at " + image.src + " didn't load"); 1.64 + callback.onComplete(false); 1.65 + cleanup(); 1.66 + }, 1.67 + 1.68 + startJob: function ColorAnalyzer_startJob(imageData, callback) { 1.69 + this.callbacks.push(callback); 1.70 + this.worker.postMessage({ imageData: imageData, maxColors: 1 }); 1.71 + }, 1.72 + 1.73 + onWorkerMessage: function ColorAnalyzer_onWorkerMessage(event) { 1.74 + // colors can be empty on failure 1.75 + if (event.data.colors.length < 1) { 1.76 + this.callbacks.shift().onComplete(false); 1.77 + } else { 1.78 + this.callbacks.shift().onComplete(true, event.data.colors[0]); 1.79 + } 1.80 + }, 1.81 + 1.82 + onWorkerError: function ColorAnalyzer_onWorkerError(error) { 1.83 + // this shouldn't happen, but just in case 1.84 + error.preventDefault(); 1.85 + Cu.reportError("ColorAnalyzer worker: " + error.message); 1.86 + this.callbacks.shift().onComplete(false); 1.87 + }, 1.88 + 1.89 + classID: Components.ID("{d056186c-28a0-494e-aacc-9e433772b143}"), 1.90 + QueryInterface: XPCOMUtils.generateQI([Ci.mozIColorAnalyzer]) 1.91 +}; 1.92 + 1.93 +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ColorAnalyzer]);