Bug 1432256 - Fix color picker not detecting focused styling; r?gl. draft
authorErica Wrighty <ewright@mozilla.com>
Tue, 13 Feb 2018 11:37:55 -0500
changeset 754583 955882afceeea851dc4d6e1fa23816110bea6649
parent 753931 d1b78b3cafc7185b05cd7701f721712f412e671e
push id98931
push userbmo:ewright@mozilla.com
push dateTue, 13 Feb 2018 20:50:44 +0000
reviewersgl
bugs1432256
milestone60.0a1
Bug 1432256 - Fix color picker not detecting focused styling; r?gl. MozReview-Commit-ID: KonwPaKNlZf
devtools/server/actors/highlighters/eye-dropper.js
--- a/devtools/server/actors/highlighters/eye-dropper.js
+++ b/devtools/server/actors/highlighters/eye-dropper.js
@@ -130,16 +130,20 @@ EyeDropper.prototype = {
       return false;
     }
 
     this.options = options;
 
     // Get the page's current zoom level.
     this.pageZoom = getCurrentZoom(this.win);
 
+    // Focus the content so the keyboard can be used, and so that any focused
+    // elements are drawn as such.
+    this.win.focus();
+
     // Take a screenshot of the viewport. This needs to be done first otherwise the
     // eyedropper UI will appear in the screenshot itself (since the UI is injected as
     // native anonymous content in the page).
     // Once the screenshot is ready, the magnified area will be drawn.
     this.prepareImageCapture();
 
     // Start listening for user events.
     let {pageListenerTarget} = this.highlighterEnv;
@@ -156,19 +160,16 @@ EyeDropper.prototype = {
     this.ctx = this.getElement("canvas").getCanvasContext();
     this.ctx.imageSmoothingEnabled = false;
 
     this.magnifiedArea = {width: MAGNIFIER_WIDTH, height: MAGNIFIER_HEIGHT,
                           x: DEFAULT_START_POS_X, y: DEFAULT_START_POS_Y};
 
     this.moveTo(DEFAULT_START_POS_X, DEFAULT_START_POS_Y);
 
-    // Focus the content so the keyboard can be used.
-    this.win.focus();
-
     return true;
   },
 
   /**
    * Hide the eye-dropper highlighter.
    */
   hide() {
     if (this.highlighterEnv.isXUL) {
@@ -190,30 +191,31 @@ EyeDropper.prototype = {
     this.getElement("root").setAttribute("hidden", "true");
     this.getElement("root").removeAttribute("drawn");
 
     this.emit("hidden");
   },
 
   prepareImageCapture() {
     // Get the image data from the content window.
-    let imageData = getWindowAsImageData(this.win);
+    getWindowAsImageData(this.win)
+      .then(imageData => this.win.createImageBitmap(imageData))
 
-    // We need to transform imageData to something drawWindow will consume. An ImageBitmap
-    // works well. We could have used an Image, but doing so results in errors if the page
-    // defines CSP headers.
-    this.win.createImageBitmap(imageData).then(image => {
-      this.pageImage = image;
-      // We likely haven't drawn anything yet (no mousemove events yet), so start now.
-      this.draw();
+      // We need to transform imageData to something drawWindow will consume. An
+      // ImageBitmap works well. We could have used an Image, but doing so results
+      // in errors if the page defines CSP headers.
+      .then(image => {
+        this.pageImage = image;
+        // We likely haven't drawn anything yet (no mousemove events yet), so start now.
+        this.draw();
 
-      // Set an attribute on the root element to be able to run tests after the first draw
-      // was done.
-      this.getElement("root").setAttribute("drawn", "true");
-    });
+        // Set an attribute on the root element to be able to run tests after the
+        // first draw was done.
+        this.getElement("root").setAttribute("drawn", "true");
+      });
   },
 
   /**
    * Get the number of cells (blown-up pixels) per direction in the grid.
    */
   get cellsWide() {
     // Canvas will render whole "pixels" (cells) only, and an even number at that. Round
     // up to the nearest even number of pixels.
@@ -468,33 +470,37 @@ EyeDropper.prototype = {
   }
 };
 
 exports.EyeDropper = EyeDropper;
 
 /**
  * Draw the visible portion of the window on a canvas and get the resulting ImageData.
  * @param {Window} win
- * @return {ImageData} The image data for the window.
+ * @return {Promise} Resolves with the ImageData (after a run of the event loop to
+ * allow the window to draw the focus effects on a focused element).
  */
 function getWindowAsImageData(win) {
   let canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
   let scale = getCurrentZoom(win);
   let width = win.innerWidth;
   let height = win.innerHeight;
   canvas.width = width * scale;
   canvas.height = height * scale;
   canvas.mozOpaque = true;
 
   let ctx = canvas.getContext("2d");
+  ctx.scale(scale, scale);
 
-  ctx.scale(scale, scale);
-  ctx.drawWindow(win, win.scrollX, win.scrollY, width, height, "#fff");
-
-  return ctx.getImageData(0, 0, canvas.width, canvas.height);
+  return new Promise(resolve => {
+    setTimeout(() => {
+      ctx.drawWindow(win, win.scrollX, win.scrollY, width, height, "#fff");
+      resolve(ctx.getImageData(0, 0, canvas.width, canvas.height));
+    }, 0);
+  });
 }
 
 /**
  * Get a formatted CSS color string from a color value.
  * @param {array} rgb Rgb values of a color to format.
  * @param {string} format Format of string. One of "hex", "rgb", "hsl", "name".
  * @return {string} Formatted color value, e.g. "#FFF" or "hsl(20, 10%, 10%)".
  */