Bug 849236 - Add a screenshot button to the responsive mode. r=mratcliffe
authorPaul Rouget <paul@mozilla.com>
Tue, 03 Sep 2013 09:15:51 +0200
changeset 145280 0d0feeec23a81e87b1534c9f0492fdaa81c4a551
parent 145279 0169b1c99f312bb1b01e4ad501eaa4b6d42f89ae
child 145281 9cc1839ef1f25741216a529bfa0aed71163a7e7c
push id25205
push useremorley@mozilla.com
push dateTue, 03 Sep 2013 11:14:02 +0000
treeherdermozilla-central@7ff96bd19c1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmratcliffe
bugs849236
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 849236 - Add a screenshot button to the responsive mode. r=mratcliffe
browser/devtools/responsivedesign/responsivedesign.jsm
browser/devtools/responsivedesign/test/browser_responsiveui.js
browser/devtools/responsivedesign/test/browser_responsiveuiaddcustompreset.js
browser/locales/en-US/chrome/browser/devtools/responsiveUI.properties
browser/themes/linux/jar.mn
browser/themes/osx/jar.mn
browser/themes/shared/devtools/responsivedesign.inc.css
browser/themes/shared/devtools/responsiveui-rotate.png
browser/themes/shared/devtools/responsiveui-screenshot.png
browser/themes/windows/jar.mn
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -152,16 +152,17 @@ function ResponsiveUI(aWindow, aTab)
   this.container.setAttribute("responsivemode", "true");
   this.stack.setAttribute("responsivemode", "true");
 
   // Let's bind some callbacks.
   this.bound_presetSelected = this.presetSelected.bind(this);
   this.bound_addPreset = this.addPreset.bind(this);
   this.bound_removePreset = this.removePreset.bind(this);
   this.bound_rotate = this.rotate.bind(this);
+  this.bound_screenshot = () => this.screenshot();
   this.bound_close = this.close.bind(this);
   this.bound_startResizing = this.startResizing.bind(this);
   this.bound_stopResizing = this.stopResizing.bind(this);
   this.bound_onDrag = this.onDrag.bind(this);
   this.bound_onKeypress = this.onKeypress.bind(this);
 
   // Events
   this.tab.addEventListener("TabClose", this);
@@ -223,16 +224,17 @@ ResponsiveUI.prototype = {
       this.stopResizing();
 
     // Remove listeners.
     this.mainWindow.document.removeEventListener("keypress", this.bound_onKeypress, false);
     this.menulist.removeEventListener("select", this.bound_presetSelected, true);
     this.tab.removeEventListener("TabClose", this);
     this.tabContainer.removeEventListener("TabSelect", this);
     this.rotatebutton.removeEventListener("command", this.bound_rotate, true);
+    this.screenshotbutton.removeEventListener("command", this.bound_screenshot, true);
     this.closebutton.removeEventListener("command", this.bound_close, true);
     this.addbutton.removeEventListener("command", this.bound_addPreset, true);
     this.removebutton.removeEventListener("command", this.bound_removePreset, true);
 
     // Removed elements.
     this.container.removeChild(this.toolbar);
     this.stack.removeChild(this.resizer);
     this.stack.removeChild(this.resizeBarV);
@@ -295,18 +297,19 @@ ResponsiveUI.prototype = {
    },
 
   /**
    * Build the toolbar and the resizers.
    *
    * <vbox class="browserContainer"> From tabbrowser.xml
    *  <toolbar class="devtools-toolbar devtools-responsiveui-toolbar">
    *    <menulist class="devtools-menulist"/> // presets
-   *    <toolbarbutton tabindex="0" class="devtools-toolbarbutton" label="rotate"/> // rotate
-   *    <toolbarbutton tabindex="0" class="devtools-toolbarbutton devtools-closebutton" tooltiptext="Leave Responsive Design View"/> // close
+   *    <toolbarbutton tabindex="0" class="devtools-toolbarbutton" tooltiptext="rotate"/> // rotate
+   *    <toolbarbutton tabindex="0" class="devtools-toolbarbutton" tooltiptext="screenshot"/> // screenshot
+   *    <toolbarbutton tabindex="0" class="devtools-toolbarbutton" tooltiptext="Leave Responsive Design View"/> // close
    *  </toolbar>
    *  <stack class="browserStack"> From tabbrowser.xml
    *    <browser/>
    *    <box class="devtools-responsiveui-resizehandle" bottom="0" right="0"/>
    *    <box class="devtools-responsiveui-resizebarV" top="0" right="0"/>
    *    <box class="devtools-responsiveui-resizebarH" bottom="0" left="0"/>
    *  </stack>
    * </vbox>
@@ -336,29 +339,36 @@ ResponsiveUI.prototype = {
     this.removebutton.addEventListener("command", this.bound_removePreset, true);
 
     menupopup.appendChild(this.chromeDoc.createElement("menuseparator"));
     menupopup.appendChild(this.addbutton);
     menupopup.appendChild(this.removebutton);
 
     this.rotatebutton = this.chromeDoc.createElement("toolbarbutton");
     this.rotatebutton.setAttribute("tabindex", "0");
-    this.rotatebutton.setAttribute("label", this.strings.GetStringFromName("responsiveUI.rotate"));
-    this.rotatebutton.className = "devtools-toolbarbutton";
+    this.rotatebutton.setAttribute("tooltiptext", this.strings.GetStringFromName("responsiveUI.rotate2"));
+    this.rotatebutton.className = "devtools-toolbarbutton devtools-responsiveui-rotate";
     this.rotatebutton.addEventListener("command", this.bound_rotate, true);
 
+    this.screenshotbutton = this.chromeDoc.createElement("toolbarbutton");
+    this.screenshotbutton.setAttribute("tabindex", "0");
+    this.screenshotbutton.setAttribute("tooltiptext", this.strings.GetStringFromName("responsiveUI.screenshot"));
+    this.screenshotbutton.className = "devtools-toolbarbutton devtools-responsiveui-screenshot";
+    this.screenshotbutton.addEventListener("command", this.bound_screenshot, true);
+
     this.closebutton = this.chromeDoc.createElement("toolbarbutton");
     this.closebutton.setAttribute("tabindex", "0");
-    this.closebutton.className = "devtools-toolbarbutton devtools-closebutton";
+    this.closebutton.className = "devtools-toolbarbutton devtools-responsiveui-close";
     this.closebutton.setAttribute("tooltiptext", this.strings.GetStringFromName("responsiveUI.close"));
     this.closebutton.addEventListener("command", this.bound_close, true);
 
     this.toolbar.appendChild(this.closebutton);
     this.toolbar.appendChild(this.menulist);
     this.toolbar.appendChild(this.rotatebutton);
+    this.toolbar.appendChild(this.screenshotbutton);
 
     // Resizers
     this.resizer = this.chromeDoc.createElement("box");
     this.resizer.className = "devtools-responsiveui-resizehandle";
     this.resizer.setAttribute("right", "0");
     this.resizer.setAttribute("bottom", "0");
     this.resizer.onmousedown = this.bound_startResizing;
 
@@ -564,16 +574,53 @@ ResponsiveUI.prototype = {
       this.saveCustomSize();
     } else {
       this.rotateValue = !this.rotateValue;
       this.saveCurrentPreset();
     }
   },
 
   /**
+   * Take a screenshot of the page.
+   *
+   * @param aFileName name of the screenshot file (used for tests).
+   */
+  screenshot: function RUI_screenshot(aFileName) {
+    let window = this.browser.contentWindow;
+    let document = window.document;
+    let canvas = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+
+    let width = window.innerWidth;
+    let height = window.innerHeight;
+
+    canvas.width = width;
+    canvas.height = height;
+
+    let ctx = canvas.getContext("2d");
+    ctx.drawWindow(window, window.scrollX, window.scrollY, width, height, "#fff");
+
+    let filename = aFileName;
+
+    if (!filename) {
+      let date = new Date();
+      let month = ("0" + (date.getMonth() + 1)).substr(-2, 2);
+      let day = ("0" + (date.getDay() + 1)).substr(-2, 2);
+      let dateString = [date.getFullYear(), month, day].join("-");
+      let timeString = date.toTimeString().replace(/:/g, ".").split(" ")[0];
+      filename = this.strings.formatStringFromName("responsiveUI.screenshotGeneratedFilename", [dateString, timeString], 2);
+    }
+
+    canvas.toBlob(blob => {
+      let chromeWindow = this.chromeDoc.defaultView;
+      let url = chromeWindow.URL.createObjectURL(blob);
+      chromeWindow.saveURL(url, filename + ".png", null, true, true, document.documentURIObject, document);
+    });
+  },
+
+  /**
    * Change the size of the browser.
    *
    * @param aWidth width of the browser.
    * @param aHeight height of the browser.
    */
   setSize: function RUI_setSize(aWidth, aHeight) {
     aWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH);
     aHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_HEIGHT);
--- a/browser/devtools/responsivedesign/test/browser_responsiveui.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveui.js
@@ -148,20 +148,48 @@ function test() {
     is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
 
     // Menus are correctly updated?
     is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "true", "menus checked");
 
     is(content.innerWidth, widthBeforeClose, "width restored.");
     is(content.innerHeight, heightBeforeClose, "height restored.");
 
-    mgr.once("off", function() {executeSoon(finishUp)});
+    mgr.once("off", function() {executeSoon(testScreenshot)});
     EventUtils.synthesizeKey("VK_ESCAPE", {});
   }
 
+  function testScreenshot() {
+    let isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
+    if (isWinXP) {
+      // We have issues testing this on Windows XP.
+      // See https://bugzilla.mozilla.org/show_bug.cgi?id=848760#c17
+      return finishUp();
+    }
+
+    info("screenshot");
+    instance.screenshot("responsiveui");
+    let FileUtils = (Cu.import("resource://gre/modules/FileUtils.jsm", {})).FileUtils;
+
+    // while(1) until we find the file.
+    // no need for a timeout, the test will get killed anyway.
+    info("checking if file exists in 200ms");
+    function checkIfFileExist() {
+      let file = FileUtils.getFile("DfltDwnld", [ "responsiveui.png" ]);
+      if (file.exists()) {
+        ok(true, "Screenshot file exists");
+        file.remove(false);
+        finishUp();
+      } else {
+        setTimeout(checkIfFileExist, 200);
+      }
+    }
+    checkIfFileExist();
+  }
+
   function finishUp() {
 
     // Menus are correctly updated?
     is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "false", "menu unchecked");
 
     delete instance;
     gBrowser.removeCurrentTab();
     finish();
--- a/browser/devtools/responsivedesign/test/browser_responsiveuiaddcustompreset.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveuiaddcustompreset.js
@@ -80,17 +80,17 @@ function test() {
     mgr.once("off", restart);
 
     // Force document reflow to avoid intermittent failures.
     info("document height " + document.height);
 
     // We're still in the loop of initializing the responsive mode.
     // Let's wait next loop to stop it.
     executeSoon(function() {
-      EventUtils.synthesizeKey("VK_ESCAPE", {});
+      instance.close();
     });
   }
 
   function restart() {
     info("Restarting Responsive Mode");
     mgr.once("on", function() {
       let container = gBrowser.getBrowserContainer();
       is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
@@ -130,17 +130,17 @@ function test() {
     deletedPresetB = instance.menulist.selectedItem.getAttribute("label");
     instance.removebutton.doCommand();
 
     info("waiting for responsive mode to turn off");
     mgr.once("off", restartAgain);
 
     // We're still in the loop of initializing the responsive mode.
     // Let's wait next loop to stop it.
-    executeSoon(() => EventUtils.synthesizeKey("VK_ESCAPE", {}));
+    executeSoon(() => instance.close());
   }
 
   function restartAgain() {
     info("waiting for responsive mode to turn on");
     mgr.once("on", () => {
       instance = gBrowser.selectedTab.__responsiveUI;
       testCustomPresetsNotInListAnymore();
     });
--- a/browser/locales/en-US/chrome/browser/devtools/responsiveUI.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/responsiveUI.properties
@@ -7,18 +7,26 @@
 #
 # The correct localization of this file might be to keep it in
 # English, or another language commonly spoken among web developers.
 # You want to make that choice consistent across the developer tools.
 # A good criteria is the language in which you'd find the best
 # documentation on web development on the web.
 
 
-# LOCALIZATION NOTE  (responsiveUI.rotate): label of the rotate button.
-responsiveUI.rotate=rotate
+# LOCALIZATION NOTE  (responsiveUI.rotate2): tooltip of the rotate button.
+responsiveUI.rotate2=Rotate
+
+# LOCALIZATION NOTE  (responsiveUI.screenshot): tooltip of the screenshot button.
+responsiveUI.screenshot=Screenshot
+
+# LOCALIZATION NOTE (responsiveUI.screenshotGeneratedFilename): The auto generated filename.
+# The first argument (%1$S) is the date string in yyyy-mm-dd format and the second
+# argument (%2$S) is the time string in HH.MM.SS format.
+responsiveUI.screenshotGeneratedFilename=Screen Shot %1$S at %2$S
 
 # LOCALIZATION NOTE  (responsiveUI.addPreset): label of the add preset button.
 responsiveUI.addPreset=Add Preset
 
 # LOCALIZATION NOTE  (responsiveUI.removePreset): label of the remove preset button.
 responsiveUI.removePreset=Remove Preset
 
 # LOCALIZATION NOTE  (responsiveUI.customResolution): label of the first item
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -217,16 +217,18 @@ browser.jar:
   skin/classic/browser/devtools/tool-network.png          (devtools/tool-network.png)
   skin/classic/browser/devtools/close.png                 (devtools/close.png)
   skin/classic/browser/devtools/vview-delete.png          (devtools/vview-delete.png)
   skin/classic/browser/devtools/vview-edit.png            (devtools/vview-edit.png)
   skin/classic/browser/devtools/undock.png                (devtools/undock.png)
   skin/classic/browser/devtools/font-inspector.css        (devtools/font-inspector.css)
   skin/classic/browser/devtools/computedview.css          (devtools/computedview.css)
   skin/classic/browser/devtools/arrow-e.png               (devtools/arrow-e.png)
+  skin/classic/browser/devtools/responsiveui-rotate.png   (../shared/devtools/responsiveui-rotate.png)
+  skin/classic/browser/devtools/responsiveui-screenshot.png (../shared/devtools/responsiveui-screenshot.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-16-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-24-throbber.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-128.png
   skin/classic/browser/sync-desktopIcon.png
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -307,16 +307,18 @@ browser.jar:
   skin/classic/browser/devtools/tool-network.png            (devtools/tool-network.png)
   skin/classic/browser/devtools/close.png                   (devtools/close.png)
   skin/classic/browser/devtools/vview-delete.png            (devtools/vview-delete.png)
   skin/classic/browser/devtools/vview-edit.png              (devtools/vview-edit.png)
   skin/classic/browser/devtools/undock.png                  (devtools/undock.png)
   skin/classic/browser/devtools/font-inspector.css          (devtools/font-inspector.css)
   skin/classic/browser/devtools/computedview.css            (devtools/computedview.css)
   skin/classic/browser/devtools/arrow-e.png                 (devtools/arrow-e.png)
+  skin/classic/browser/devtools/responsiveui-rotate.png     (../shared/devtools/responsiveui-rotate.png)
+  skin/classic/browser/devtools/responsiveui-screenshot.png (../shared/devtools/responsiveui-screenshot.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-128.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-mobileIcon.png
--- a/browser/themes/shared/devtools/responsivedesign.inc.css
+++ b/browser/themes/shared/devtools/responsivedesign.inc.css
@@ -29,16 +29,28 @@
   border-radius: 0;
 }
 
 .devtools-responsiveui-toolbar:-moz-locale-dir(ltr) > *:first-child,
 .devtools-responsiveui-toolbar:-moz-locale-dir(rtl) > *:last-child {
   margin-left: 0;
 }
 
+.devtools-responsiveui-close {
+  list-style-image: url("chrome://browser/skin/devtools/close.png");
+}
+
+.devtools-responsiveui-rotate {
+  list-style-image: url("chrome://browser/skin/devtools/responsiveui-rotate.png");
+}
+
+.devtools-responsiveui-screenshot {
+  list-style-image: url("chrome://browser/skin/devtools/responsiveui-screenshot.png");
+}
+
 .devtools-responsiveui-resizebarV {
   width: 7px;
   height: 24px;
   cursor: ew-resize;
   transform: translate(12px, -12px);
   background-image: url("chrome://browser/skin/devtools/responsive-vertical-resizer.png");
 }
 
new file mode 100644
index 0000000000000000000000000000000000000000..1e30f708697532e260694d36d6d0ae50cd491ef7
GIT binary patch
literal 498
zc$@+90S*3%P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0005GNkl<Zc-p0t
z-z!657{?FWq{(JTIew??ViZ%BD4YvRlI3n!EJ-9xp@_KJo!oFCGMW;N+3c6iR%4o9
ze*n1@`5A6^G2ge|qqR0QE<WdZ-{*P0-}9d5oWn#Sk$=I6r0icv2U#S>7K9)h$bkwp
z(kQ2SAr&jV{=foad9+vz6aym@)BZrv`TF)A3WvkjB$7SJqh1RdR*j}z9RC{YmLG9;
zK}Cbb=CGh}1unoj2+?>!^7~f%!P>@_8S6_@gRYZ5c9qTHKA?i&FNC6dpwke899{qL
z3=*dxK)8Q+^q-uCyf?RZKC({)Z&2y-_{iOTPtPx2ZBM^RC}l^14(PeIuAPt1uVYe=
zg*V_ZC^rV?Zc=NOgc7z{AYls;^I_1sxU@nB<^e~s@CNPJIL(&BJqS7=&ZKWdxxBKz
zNt+$<;0@F-uWy#|skv1cC}5C6=3=$G47Aaj2=sFdE-K8xI5s(Jz`6`#l9PZs&`swt
z76&aTCCw$hgZd$(X?tFT1YmFq0muNkATI$jkj7wGVwhCn>*_-+NcO*A$TP!4S}d<A
os;=i`NgL23r-C#X36eGV23z8q2k?OIX#fBK07*qoM6N<$g5THRF8}}l
new file mode 100644
index 0000000000000000000000000000000000000000..82e6c3f3c5446fb17b430f688a33fbd28042120f
GIT binary patch
literal 528
zc$@(c0`L8aP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0005kNkl<Zc-p0r
z-Ahw(9LA6A3?i6DZ5JMhE~L7VSPhElg`!@_rYR^aBt&r1kTQty4Kpx9(cOBptdQ+O
zjMR2v^JNvGQb_d&6y3F#NcV#CLNC_y!1=}Z!XW741J8NB&-1`JM=KVK|Al5PGb9#Z
z2To7}YKf^`pd46bM~M=%e8$(=<KHh7cCh|Ma(H<3X=rr(0Wt>A*--;FP<f@QzWJil
zee1<y^c4!*$MJFJ^C~iZ%(BBS2QGd6_I(|J4<=jS{a@HrId<6PKqHJdAg=h4NUjI&
z_Agv;x~B*=J(*#LT@JM3A*M(q)2}NkuLkupqvMou{>DkiIUhB>WGcNPv+SyYsG{%w
za0G?+(MOZhg@c0_K4^@Z9&a)$2VN>JyX!_yoIcx<%jcJsm(Asu;9ciUX63-VqN>g_
z0IwyL{`tqFrgyETaX@C}Kv*&S@No!U)6MSQU?Q1{5Ndc{-egt|JXieM-HYHq5AmHr
zfKa=t8wPokSvAmvhgrc>1jAz!!I^qb+dV=}k2jfRSHrq{E&eXFyO)tX$z*fSz#O5b
zCo`)XZ$s>AdZ|$k;ROM32iyj|zz@0zH9g*#VU`_sHA|_X0~@dd$3J2>JNj>ErW>=K
S?OJXC0000<MNUMnLSTZ!nD#FK
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -244,16 +244,18 @@ browser.jar:
         skin/classic/browser/devtools/tool-network.png              (devtools/tool-network.png)
         skin/classic/browser/devtools/close.png                     (devtools/close.png)
         skin/classic/browser/devtools/vview-delete.png              (devtools/vview-delete.png)
         skin/classic/browser/devtools/vview-edit.png                (devtools/vview-edit.png)
         skin/classic/browser/devtools/undock.png                    (devtools/undock.png)
         skin/classic/browser/devtools/font-inspector.css            (devtools/font-inspector.css)
         skin/classic/browser/devtools/computedview.css              (devtools/computedview.css)
         skin/classic/browser/devtools/arrow-e.png                   (devtools/arrow-e.png)
+        skin/classic/browser/devtools/responsiveui-rotate.png       (../shared/devtools/responsiveui-rotate.png)
+        skin/classic/browser/devtools/responsiveui-screenshot.png   (../shared/devtools/responsiveui-screenshot.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/sync-throbber.png
         skin/classic/browser/sync-16.png
         skin/classic/browser/sync-32.png
         skin/classic/browser/sync-128.png
         skin/classic/browser/sync-bg.png
         skin/classic/browser/sync-desktopIcon.png
         skin/classic/browser/sync-mobileIcon.png
@@ -503,16 +505,18 @@ browser.jar:
         skin/classic/aero/browser/devtools/tool-network.png          (devtools/tool-network.png)
         skin/classic/aero/browser/devtools/close.png                 (devtools/close.png)
         skin/classic/aero/browser/devtools/vview-delete.png          (devtools/vview-delete.png)
         skin/classic/aero/browser/devtools/vview-edit.png            (devtools/vview-edit.png)
         skin/classic/aero/browser/devtools/undock.png                (devtools/undock.png)
         skin/classic/aero/browser/devtools/font-inspector.css        (devtools/font-inspector.css)
         skin/classic/aero/browser/devtools/computedview.css          (devtools/computedview.css)
         skin/classic/aero/browser/devtools/arrow-e.png               (devtools/arrow-e.png)
+        skin/classic/aero/browser/devtools/responsiveui-rotate.png   (../shared/devtools/responsiveui-rotate.png)
+        skin/classic/aero/browser/devtools/responsiveui-screenshot.png (../shared/devtools/responsiveui-screenshot.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/sync-throbber.png
         skin/classic/aero/browser/sync-16.png
         skin/classic/aero/browser/sync-32.png
         skin/classic/aero/browser/sync-128.png
         skin/classic/aero/browser/sync-bg.png
         skin/classic/aero/browser/sync-desktopIcon.png
         skin/classic/aero/browser/sync-mobileIcon.png