Bug 1403682 - Add _findBoundingBox function and tests for mozscreenshots cropping; r?jaws
MozReview-Commit-ID: 7kvVsF3Wq3z
--- a/browser/tools/mozscreenshots/browser.ini
+++ b/browser/tools/mozscreenshots/browser.ini
@@ -1,6 +1,7 @@
[DEFAULT]
subsuite = screenshots
support-files =
head.js
[browser_screenshots.js]
+[browser_boundingbox.js]
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/browser_boundingbox.js
@@ -0,0 +1,77 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+add_task(async function() {
+ const scale = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDocShell).QueryInterface(Ci.nsIBaseWindow)
+ .devicePixelsPerDesktopPixel;
+ let rect = TestRunner._findBoundingBox(["#tabbrowser-tabs"]);
+ let element = document.querySelector("#tabbrowser-tabs");
+ let tabBar = element.ownerDocument.getBoxObjectFor(element);
+
+ // Calculate expected values
+ let expectedLeft = scale * (tabBar.screenX - TestRunner.croppingPadding);
+ let expectedTop = scale * (tabBar.screenY - TestRunner.croppingPadding);
+ let expectedRight = scale * (tabBar.width + TestRunner.croppingPadding * 2) + expectedLeft;
+ let expectedBottom = scale * (tabBar.height + TestRunner.croppingPadding * 2) + expectedTop;
+
+ // Calculate browser region
+ let windowLeft = window.screenX * scale;
+ let windowTop = window.screenY * scale;
+ let windowRight = window.outerWidth * scale + windowLeft;
+ let windowBottom = window.outerHeight * scale + windowTop;
+
+ // Adjust values based on browser window
+ expectedLeft = Math.max(expectedLeft, windowLeft);
+ expectedTop = Math.max(expectedTop, windowTop);
+ expectedRight = Math.min(expectedRight, windowRight);
+ expectedBottom = Math.min(expectedBottom, windowBottom);
+ // Check width calculation on simple example
+ is(rect.width, expectedRight - expectedLeft,
+ "Checking _findBoundingBox width calculation");
+ // Check height calculation on simple example
+ is(rect.height, expectedBottom - expectedTop,
+ "Checking _findBoundingBox height caclulation");
+
+ rect = TestRunner._findBoundingBox(["#forward-button", "#TabsToolbar"]);
+ element = document.querySelector("#TabsToolbar");
+ let tabToolbar = element.ownerDocument.getBoxObjectFor(element);
+ element = document.querySelector("#forward-button");
+ let fButton = element.ownerDocument.getBoxObjectFor(element);
+
+ // Calculate expected values
+ expectedLeft = scale * (Math.min(tabToolbar.screenX, fButton.screenX)
+ - TestRunner.croppingPadding);
+ expectedTop = scale * (Math.min(tabToolbar.screenY, fButton.screenY)
+ - TestRunner.croppingPadding);
+ expectedRight = scale * (Math.max(tabToolbar.width + tabToolbar.screenX,
+ fButton.width + fButton.screenX)
+ + TestRunner.croppingPadding);
+ expectedBottom = scale * (Math.max(tabToolbar.height + tabToolbar.screenY,
+ fButton.height + fButton.screenY)
+ + TestRunner.croppingPadding );
+
+ // Adjust values based on browser window
+ expectedLeft = Math.max(expectedLeft, windowLeft);
+ expectedTop = Math.max(expectedTop, windowTop);
+ expectedRight = Math.min(expectedRight, windowRight);
+ expectedBottom = Math.min(expectedBottom, windowBottom);
+
+ // Check width calculation on union
+ is(rect.width, expectedRight - expectedLeft,
+ "Checking _findBoundingBox union width calculation");
+ // Check height calculation on union
+ is(rect.height, expectedBottom - expectedTop,
+ "Checking _findBoundingBox union height calculation");
+
+ rect = TestRunner._findBoundingBox(["#does_not_exist"]);
+ // Check that 'selector not found' returns null
+ is(rect, null, "Checking that selector not found returns null");
+
+ rect = TestRunner._findBoundingBox([]);
+ // Check that no selectors returns null
+ is(rect, null, "Checking that no selectors returns null");
+});
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
@@ -11,16 +11,17 @@ const env = Cc["@mozilla.org/process/env
const APPLY_CONFIG_TIMEOUT_MS = 60 * 1000;
const HOME_PAGE = "chrome://mozscreenshots/content/lib/mozscreenshots.html";
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
+Cu.import("resource://gre/modules/Geometry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserTestUtils",
"resource://testing-common/BrowserTestUtils.jsm");
Cu.import("chrome://mozscreenshots/content/Screenshot.jsm");
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
@@ -36,16 +37,17 @@ XPCOMUtils.defineLazyGetter(this, "log",
});
this.TestRunner = {
combos: null,
completedCombos: 0,
currentComboIndex: 0,
_lastCombo: null,
_libDir: null,
+ croppingPadding: 10,
init(extensionPath) {
log.debug("init");
this._extensionPath = extensionPath;
},
/**
* Load specified sets, execute all combinations of them, and capture screenshots.
@@ -154,16 +156,83 @@ this.TestRunner = {
gBrowser.unpinTab(gBrowser.selectedTab);
gBrowser.selectedBrowser.loadURI("data:text/html;charset=utf-8,<h1>Done!");
browserWindow.restore();
Services.prefs.clearUserPref("toolkit.cosmeticAnimations.enabled");
},
// helpers
+ /**
+ * Calculate the bounding box based on CSS selector from config for cropping
+ *
+ * @param {String[]} selectors - array of CSS selectors for relevant DOM element
+ * @return {Geometry.jsm Rect} Rect holding relevant x, y, width, height with padding
+ **/
+ _findBoundingBox(selectors, windowType) {
+ // No selectors provided
+ if (!selectors.length) {
+ log.info("_findBoundingBox: selectors argument is empty");
+ return null;
+ }
+
+ // Set window type, default "navigator:browser"
+ windowType = windowType || "navigator:browser";
+ let browserWindow = Services.wm.getMostRecentWindow(windowType);
+ // Scale for high-density displays
+ const scale = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDocShell).QueryInterface(Ci.nsIBaseWindow)
+ .devicePixelsPerDesktopPixel;
+
+ let finalRect = undefined;
+ // Grab bounding boxes and find the union
+ for (let selector of selectors) {
+ let element;
+ // Check for function to find anonymous content
+ if (typeof(selector) == "function") {
+ element = selector();
+ } else {
+ element = browserWindow.document.querySelector(selector);
+ }
+
+ // Selector not found
+ if (!element) {
+ log.info("_findBoundingBox: selector not found");
+ return null;
+ }
+
+ // Calculate box region, convert to Rect
+ let box = element.ownerDocument.getBoxObjectFor(element);
+ let newRect = new Rect(box.screenX * scale, box.screenY * scale,
+ box.width * scale, box.height * scale);
+
+ if (!finalRect) {
+ finalRect = newRect;
+ } else {
+ finalRect = finalRect.union(newRect);
+ }
+ }
+
+ // Add fixed padding
+ finalRect = finalRect.inflateFixed(this.croppingPadding * scale);
+
+ let windowLeft = browserWindow.screenX * scale;
+ let windowTop = browserWindow.screenY * scale;
+ let windowWidth = browserWindow.outerWidth * scale;
+ let windowHeight = browserWindow.outerHeight * scale;
+
+ // Clip dimensions to window only
+ finalRect.left = Math.max(finalRect.left, windowLeft);
+ finalRect.top = Math.max(finalRect.top, windowTop);
+ finalRect.right = Math.min(finalRect.right, windowLeft + windowWidth);
+ finalRect.bottom = Math.min(finalRect.bottom, windowTop + windowHeight);
+
+ return finalRect;
+ },
+
async _performCombo(combo) {
let paddedComboIndex = padLeft(this.currentComboIndex + 1, String(this.combos.length).length);
log.info("Combination " + paddedComboIndex + "/" + this.combos.length + ": " +
this._comboName(combo).substring(1));
function changeConfig(config) {
log.debug("calling " + config.name);
let applyPromise = Promise.resolve(config.applyConfig());
--- a/toolkit/modules/Geometry.jsm
+++ b/toolkit/modules/Geometry.jsm
@@ -325,10 +325,22 @@ Rect.prototype = {
let xAdj = (this.width * xscl - this.width) / 2;
let s = (arguments.length > 1) ? yscl : xscl;
let yAdj = (this.height * s - this.height) / 2;
this.left -= xAdj;
this.right += xAdj;
this.top -= yAdj;
this.bottom += yAdj;
return this;
+ },
+
+ /**
+ * Grows or shrinks the rectangle by fixed amount while keeping the center point.
+ * Accepts single fixed amount
+ */
+ inflateFixed: function inflateFixed(fixed) {
+ this.left -= fixed;
+ this.right += fixed;
+ this.top -= fixed;
+ this.bottom += fixed;
+ return this;
}
};