summaryrefslogtreecommitdiff
path: root/data/extensions/spyblock@gnu.org/lib/child/dataCollector.js
blob: 09c334ad242ad4593ed159b6e8c00c1843fff17d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-2017 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 {PrivateBrowsingUtils} = Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm", {});

let {port} = require("messaging");
let {Utils} = require("utils");

port.on("collectData", onCollectData);

function onCollectData({outerWindowID, screenshotWidth}, sender)
{
  let window = Services.wm.getOuterWindowWithId(outerWindowID);
  if (window)
  {
    return Task.spawn(function*()
    {
      let data = {};
      data.isPrivate = PrivateBrowsingUtils.isContentWindowPrivate(window);
      data.opener = window.opener ? window.opener.location.href : null;
      data.referrer = window.document.referrer;
      data.frames = yield scanFrames(window);
      data.screenshot = yield createScreenshot(window, screenshotWidth);
      return data;
    });
  }
}

function scanFrames(window)
{
  let frames = [];
  for (let i = 0; i < window.frames.length; i++)
  {
    let frame = window.frames[i];
    frames.push({
      url: frame.location.href,
      frames: scanFrames(frame)
    });
  }
  return frames;
}

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 data = pixelData.data;
  let mapping = [0x00,  0x55,  0xAA,  0xFF];
  for (let i = 0; i < data.length; i++)
  {
    data[i] = mapping[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));
    }
  }

  return pixelData;
}