Bug 1404078 - notify user when full page is cut off r=kmag
authorIan Bicking <ianb@colorstudy.com>
Thu, 28 Sep 2017 15:18:35 -0500
changeset 426960 933b30269777f718a14d2fc379e563a051b14618
parent 426959 4bf4766d914b027e60d93a60b6befeba9948f624
child 426961 294f332a35538940469b1a2576615ff5ffe1e016
child 427019 706ffd585a89bc9cda2471eedc74139858848add
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewerskmag
bugs1404078
milestone58.0a1
Bug 1404078 - notify user when full page is cut off r=kmag Adds a new captureType, fullPageTruncated Fixes upstream bug: https://github.com/mozilla-services/screenshots/issues/2129 Export of commit: https://github.com/mozilla-services/screenshots/pull/3564/commits/e31c321cbc2c2755440f1c8e9c19792cd1c02976 MozReview-Commit-ID: HB3e5Q24afT
browser/extensions/screenshots/webextension/_locales/en_US/messages.json
browser/extensions/screenshots/webextension/build/buildSettings.js
browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
browser/extensions/screenshots/webextension/build/shot.js
browser/extensions/screenshots/webextension/selector/shooter.js
browser/extensions/screenshots/webextension/selector/ui.js
browser/extensions/screenshots/webextension/selector/uicontrol.js
--- a/browser/extensions/screenshots/webextension/_locales/en_US/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/en_US/messages.json
@@ -35,16 +35,24 @@
   "notificationLinkCopiedDetails": {
     "message": "The link to your shot has been copied to the clipboard. Press $META_KEY$-V to paste.",
     "placeholders": {
       "meta_key": {
         "content": "$1"
       }
     }
   },
+  "imageCroppedWarning": {
+    "message": "This image has been cropped to $PIXELS$px.",
+    "placeholders": {
+      "pixels": {
+        "content": "$1"
+      }
+    }
+  },
   "requestErrorTitle": {
     "message": "Out of order."
   },
   "requestErrorDetails": {
     "message": "Sorry! We couldn’t save your shot. Please try again later."
   },
   "connectionErrorTitle": {
     "message": "We can’t connect to your screenshots."
--- a/browser/extensions/screenshots/webextension/build/buildSettings.js
+++ b/browser/extensions/screenshots/webextension/build/buildSettings.js
@@ -1,9 +1,11 @@
 window.buildSettings = {
   defaultSentryDsn: "https://904ccdd4866247c092ae8fc1a4764a63:940d44bdc71d4daea133c19080ccd38d@sentry.prod.mozaws.net/224",
   logLevel: "" || "warn",
   captureText: ("" === "true"),
   uploadBinary: ("" === "true"),
-  pngToJpegCutoff: parseInt("" || 2500000, 10)
+  pngToJpegCutoff: parseInt("" || 2500000, 10),
+  maxImageHeight: parseInt("" || 5000, 10),
+  maxImageWidth: parseInt("" || 5000, 10)
 };
 null;
 
--- a/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
+++ b/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
@@ -537,16 +537,28 @@ window.inlineSelectionCss = `
   color: #fff;
   font-family: -apple-system, BlinkMacSystemFont, "segoe ui", "helvetica neue", helvetica, ubuntu, roboto, noto, arial, sans-serif;
   font-size: 24px;
   line-height: 32px;
   text-align: center;
   padding-top: 20px;
   width: 400px; }
 
+#imageCroppedWarning {
+  position: absolute;
+  background: rgba(0, 0, 0, 0.8);
+  bottom: 0;
+  color: #fff;
+  font-family: -apple-system, BlinkMacSystemFont, "segoe ui", "helvetica neue", helvetica, ubuntu, roboto, noto, arial, sans-serif;
+  font-size: 12px;
+  padding: 10px;
+  text-align: center;
+  width: 100%;
+  z-index: 2; }
+
 .myshots-all-buttons-container {
   display: flex;
   flex-direction: row-reverse;
   background: #f5f5f5;
   border-radius: 2px;
   box-sizing: border-box;
   height: 80px;
   padding: 8px;
--- a/browser/extensions/screenshots/webextension/build/shot.js
+++ b/browser/extensions/screenshots/webextension/build/shot.js
@@ -702,17 +702,24 @@ class _Clip {
   }
   set image(image) {
     if (!image) {
       this._image = undefined;
       return;
     }
     assert(checkObject(image, ["url"], ["dimensions", "text", "location", "captureType", "type"]), "Bad attrs for Clip Image:", Object.keys(image));
     assert(isValidClipImageUrl(image.url), "Bad Clip image URL:", image.url);
-    assert(image.captureType == "madeSelection" || image.captureType == "selection" || image.captureType == "visible" || image.captureType == "auto" || image.captureType == "fullPage" || !image.captureType, "Bad image.captureType:", image.captureType);
+    assert(
+      image.captureType == "madeSelection" ||
+      image.captureType == "selection" ||
+      image.captureType == "visible" ||
+      image.captureType == "auto" ||
+      image.captureType == "fullPage" ||
+      image.captureType == "fullPageTruncated" ||
+      !image.captureType, "Bad image.captureType:", image.captureType);
     assert(typeof image.text == "string" || !image.text, "Bad Clip image text:", image.text);
     if (image.dimensions) {
       assert(typeof image.dimensions.x == "number" && typeof image.dimensions.y == "number", "Bad Clip image dimensions:", image.dimensions);
     }
     if (image.type) {
       assert(image.type == "png" || image.type == "jpeg", "Unexpected image type:", image.type);
     }
     assert(image.location &&
--- a/browser/extensions/screenshots/webextension/selector/shooter.js
+++ b/browser/extensions/screenshots/webextension/selector/shooter.js
@@ -42,24 +42,26 @@ this.shooter = (function() { // eslint-d
   let screenshotPage = exports.screenshotPage = function(selectedPos, captureType) {
     if (!supportsDrawWindow) {
       return null;
     }
     let height = selectedPos.bottom - selectedPos.top;
     let width = selectedPos.right - selectedPos.left;
     let canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
     let ctx = canvas.getContext('2d');
-    if (captureType == 'fullPage') {
+    let expand = window.devicePixelRatio !== 1;
+    if (captureType == 'fullPage' || captureType == 'fullPageTruncated') {
+      expand = false;
       canvas.width = width;
       canvas.height = height;
     } else {
       canvas.width = width * window.devicePixelRatio;
       canvas.height = height * window.devicePixelRatio;
     }
-    if (window.devicePixelRatio !== 1 && captureType != 'fullPage') {
+    if (expand) {
       ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
     }
     ui.iframe.hide();
     try {
       ctx.drawWindow(window, selectedPos.left, selectedPos.top, width, height, "#fff");
     } finally {
       ui.iframe.unhide();
     }
--- a/browser/extensions/screenshots/webextension/selector/ui.js
+++ b/browser/extensions/screenshots/webextension/selector/ui.js
@@ -1,9 +1,9 @@
-/* globals log, util, catcher, inlineSelectionCss, callBackground, assertIsTrusted, assertIsBlankDocument */
+/* globals log, util, catcher, inlineSelectionCss, callBackground, assertIsTrusted, assertIsBlankDocument, buildSettings */
 
 "use strict";
 
 this.ui = (function() { // eslint-disable-line no-unused-vars
   let exports = {};
   const SAVE_BUTTON_HEIGHT = 50;
 
   const { watchFunction } = catcher;
@@ -702,20 +702,26 @@ this.ui = (function() { // eslint-disabl
     },
     remove() {
       util.removeNode(this.el);
       this.el = this.xEl = this.yEl = null;
     }
   };
 
   exports.Preview = {
-    display(dataUrl) {
+    display(dataUrl, showCropWarning) {
       let img = makeEl("IMG");
       img.src = dataUrl;
       iframe.document().querySelector(".preview-image").appendChild(img);
+      if (showCropWarning) {
+        let imageCroppedEl = makeEl("DIV");
+        imageCroppedEl.id = "imageCroppedWarning";
+        imageCroppedEl.textContent = browser.i18n.getMessage("imageCroppedWarning", buildSettings.maxImageHeight);
+        iframe.document().querySelector(".preview-overlay").appendChild(imageCroppedEl);
+      }
     }
   };
 
   /** Removes every UI this module creates */
   exports.remove = function() {
     for (let name in exports) {
       if (name.startsWith("iframe")) {
         continue;
--- a/browser/extensions/screenshots/webextension/selector/uicontrol.js
+++ b/browser/extensions/screenshots/webextension/selector/uicontrol.js
@@ -1,10 +1,10 @@
 /* globals log, catcher, util, ui, slides */
-/* globals shooter, callBackground, selectorLoader, assertIsTrusted */
+/* globals shooter, callBackground, selectorLoader, assertIsTrusted, buildSettings */
 
 "use strict";
 
 this.uicontrol = (function() {
   let exports = {};
 
   /** ********************************************************
    * selection
@@ -40,18 +40,18 @@ this.uicontrol = (function() {
   resizeDirection (string: top, topLeft, etc, during resizing)
   resizeStartPos (x/y position where resizing started)
   mouseupNoAutoselect (true if a mouseup in draggingReady should not trigger autoselect)
 
   */
 
   const { watchFunction, watchPromise } = catcher;
 
-  const MAX_PAGE_HEIGHT = 5000;
-  const MAX_PAGE_WIDTH = 5000;
+  const MAX_PAGE_HEIGHT = buildSettings.maxImageHeight;
+  const MAX_PAGE_WIDTH = buildSettings.maxImageWidth;
   // An autoselection smaller than these will be ignored entirely:
   const MIN_DETECT_ABSOLUTE_HEIGHT = 10;
   const MIN_DETECT_ABSOLUTE_WIDTH = 30;
   // An autoselection smaller than these will not be preferred:
   const MIN_DETECT_HEIGHT = 30;
   const MIN_DETECT_WIDTH = 100;
   // An autoselection bigger than either of these will be ignored:
   const MAX_DETECT_HEIGHT = Math.max(window.innerHeight + 100, 700);
@@ -155,32 +155,38 @@ this.uicontrol = (function() {
       selectedPos = new Selection(
         window.scrollX, window.scrollY,
         window.scrollX + window.innerWidth, window.scrollY + window.innerHeight);
       captureType = 'visible';
       setState("previewing");
     },
     onClickFullPage: () => {
       sendEvent("capture-full-page", "selection-button");
+      captureType = "fullPage";
       let width = Math.max(
         document.body.clientWidth,
         document.documentElement.clientWidth,
         document.body.scrollWidth,
         document.documentElement.scrollWidth);
+      if (width > MAX_PAGE_WIDTH) {
+        captureType = "fullPageTruncated";
+      }
       width = Math.min(width, MAX_PAGE_WIDTH);
       let height = Math.max(
         document.body.clientHeight,
         document.documentElement.clientHeight,
         document.body.scrollHeight,
         document.documentElement.scrollHeight);
+      if (height > MAX_PAGE_HEIGHT) {
+        captureType = "fullPageTruncated";
+      }
       height = Math.min(height, MAX_PAGE_HEIGHT);
       selectedPos = new Selection(
         0, 0,
         width, height);
-      captureType = 'fullPage';
       setState("previewing");
     },
     onSavePreview: () => {
       sendEvent(`save-${captureType.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()}`, "save-preview-button");
       shooter.takeShot(captureType, selectedPos, dataUrl);
     },
     onDownloadPreview: () => {
       sendEvent(`download-${captureType.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()}`, "download-preview-button");
@@ -363,17 +369,17 @@ this.uicontrol = (function() {
    */
 
   let dataUrl;
 
   stateHandlers.previewing = {
     start() {
       dataUrl = shooter.screenshotPage(selectedPos, captureType);
       ui.iframe.usePreview();
-      ui.Preview.display(dataUrl);
+      ui.Preview.display(dataUrl, captureType == "fullPageTruncated");
     }
   };
 
   stateHandlers.onboarding = {
     start() {
       if (typeof slides == "undefined") {
         throw new Error("Attempted to set state to onboarding without loading slides");
       }