| Index: lib/child/dataCollector.js |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/lib/child/dataCollector.js |
| @@ -0,0 +1,112 @@ |
| +/* |
| + * This file is part of Adblock Plus <https://adblockplus.org/>, |
| + * Copyright (C) 2006-2015 Eyeo GmbH |
| + * |
| + * Adblock Plus is free software: you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License version 3 as |
| + * published by the Free Software Foundation. |
| + * |
| + * Adblock Plus is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| + */ |
| + |
| +/** |
| + * @fileOverview Collects some data for a content window, to be attached to |
| + * issue reports. |
| + */ |
| + |
| +"use strict"; |
| + |
| +let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); |
| +let {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); |
| + |
| +let {Utils} = require("utils"); |
| + |
| +addMessageListener("AdblockPlus:CollectData", onCollectData); |
| +onShutdown.add(() => { |
| + removeMessageListener("AdblockPlus:CollectData", onCollectData); |
| +}); |
| + |
| +function onCollectData(message) |
| +{ |
| + let {outerWindowID, screenshotWidth, responseID} = message.data; |
| + |
| + function success(data) |
| + { |
| + sendAsyncMessage("AdblockPlus:CollectDataResponse", { |
| + responseID, |
| + data |
| + }); |
| + } |
| + |
| + function error(e) |
| + { |
| + Cu.reportError(e); |
| + sendAsyncMessage("AdblockPlus:CollectDataResponse", { |
| + responseID, |
| + data: null |
| + }); |
| + } |
| + |
| + let window = Services.wm.getOuterWindowWithId(outerWindowID); |
| + if (window) |
| + { |
| + Task.spawn(function*() |
| + { |
| + let data = {}; |
| + data.screenshot = yield createScreenshot(window, screenshotWidth); |
| + return data; |
| + }).then(success, error); |
| + } |
| +} |
| + |
| +function* createScreenshot(window, screenshotWidth) |
| +{ |
| + let canvas = window.document.createElement("canvas"); |
| + canvas.width = screenshotWidth; |
| + |
| + let context = canvas.getContext("2d"); |
| + let wndWidth = window.document.documentElement.scrollWidth; |
| + let wndHeight = window.document.documentElement.scrollHeight; |
| + |
| + // Copy scaled screenshot of the webpage, according to the specified width. |
| + |
| + // Gecko doesn't like sizes more than 64k, restrict to 30k to be on the safe side. |
| + // Also, make sure height is at most five times the width to keep image size down. |
| + let copyWidth = Math.min(wndWidth, 30000); |
| + let copyHeight = Math.min(wndHeight, 30000, copyWidth * 5); |
| + let copyX = Math.max(Math.min(window.scrollX - copyWidth / 2, wndWidth - copyWidth), 0); |
| + let copyY = Math.max(Math.min(window.scrollY - copyHeight / 2, wndHeight - copyHeight), 0); |
| + |
| + let scalingFactor = screenshotWidth / copyWidth; |
| + canvas.height = copyHeight * scalingFactor; |
| + |
| + context.save(); |
| + context.scale(scalingFactor, scalingFactor); |
| + context.drawWindow(window, copyX, copyY, copyWidth, copyHeight, "rgb(255,255,255)"); |
| + context.restore(); |
| + |
| + // Reduce colors |
| + let pixelData = context.getImageData(0, 0, canvas.width, canvas.height); |
| + let max = pixelData.width * pixelData.height * 4; |
| + let mapping = [0x00, 0x55, 0xAA, 0xFF]; |
| + for (let i = 0; i < max; i++) |
| + { |
| + pixelData.data[i] = mapping[pixelData.data[i] >> 6]; |
| + |
| + if (i % 5000 == 0) |
| + { |
| + // Take a break every 5000 bytes to prevent browser hangs |
| + yield new Promise((resolve, reject) => Utils.runAsync(resolve)); |
| + } |
| + } |
| + |
| + // Convert the data into an image URL |
| + context.putImageData(pixelData, 0, 0); |
| + return canvas.toDataURL("image/png"); |
| +} |