Bug 1262439 - 4 - Use the new eye-dropper highlighter in the color-picker tooltip; r=bgrins draft
authorPatrick Brosset <pbrosset@mozilla.com>
Thu, 09 Jun 2016 11:26:04 +0200
changeset 385010 45b7a7117d12c56563b3445cc7f9326cdc99a81f
parent 385009 4763dcb72f8472d40ebc7d7d711f6cce68d496e2
child 385011 686966a8d27f6edfaae4d02355f91bbe6d4b0e12
push id22388
push userpbrosset@mozilla.com
push dateThu, 07 Jul 2016 13:03:20 +0000
reviewersbgrins
bugs1262439
milestone50.0a1
Bug 1262439 - 4 - Use the new eye-dropper highlighter in the color-picker tooltip; r=bgrins The color-picker tooltip now uses the new eye-dropper highlighter, by using the pickColorFromPage inspector method instead of the XUL-based eye-dropper tool. Telemetry hasn't yet been re-implemented in the new eye-dropper highlighter so the telemetry-related test code has been removed for now. This will be added again in a later commit. MozReview-Commit-ID: enSzSKHac4
devtools/client/inspector/rules/test/browser_rules_eyedropper.js
devtools/client/inspector/shared/style-inspector-overlays.js
devtools/client/shared/widgets/Tooltip.js
--- a/devtools/client/inspector/rules/test/browser_rules_eyedropper.js
+++ b/devtools/client/inspector/rules/test/browser_rules_eyedropper.js
@@ -1,24 +1,15 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
-
 "use strict";
 
-// So we can test collecting telemetry on the eyedropper
-var oldCanRecord = Services.telemetry.canRecordExtended;
-Services.telemetry.canRecordExtended = true;
-registerCleanupFunction(function () {
-  Services.telemetry.canRecordExtended = oldCanRecord;
-});
-const EXPECTED_TELEMETRY = {
-  "DEVTOOLS_PICKER_EYEDROPPER_OPENED_COUNT": 2,
-  "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG": 1
-};
+// Test opening the eyedropper from the color picker. Pressing escape to close it, and
+// clicking the page to select a color.
 
 const TEST_URI = `
   <style type="text/css">
     body {
       background-color: white;
       padding: 0px
     }
 
@@ -38,152 +29,89 @@ const TEST_URI = `
   <body><div id="div1"></div><div id="div2"></div></body>
 `;
 
 // #f09
 const ORIGINAL_COLOR = "rgb(255, 0, 153)";
 // #ff5
 const EXPECTED_COLOR = "rgb(255, 255, 85)";
 
-// Test opening the eyedropper from the color picker. Pressing escape
-// to close it, and clicking the page to select a color.
-
 add_task(function* () {
-  // clear telemetry so we can get accurate counts
-  clearTelemetry();
-
+  info("Add the test tab, open the rule-view and select the test node");
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
-  let {inspector, view} = yield openRuleView();
+  let {testActor, inspector, view} = yield openRuleView();
   yield selectNode("#div2", inspector);
 
+  info("Get the background-color property from the rule-view");
   let property = getRuleViewProperty(view, "#div2", "background-color");
   let swatch = property.valueSpan.querySelector(".ruleview-colorswatch");
   ok(swatch, "Color swatch is displayed for the bg-color property");
 
-  let dropper = yield openEyedropper(view, swatch);
+  info("Open the eyedropper from the colorpicker tooltip");
+  yield openEyedropper(view, swatch);
 
   let tooltip = view.tooltips.colorPicker.tooltip;
-  ok(tooltip.isHidden(),
-     "color picker tooltip is closed after opening eyedropper");
+  ok(tooltip.isHidden(), "color picker tooltip is closed after opening eyedropper");
 
-  yield testESC(swatch, dropper);
+  info("Test that pressing escape dismisses the eyedropper");
+  yield testESC(swatch, inspector, testActor);
 
-  dropper = yield openEyedropper(view, swatch);
-
-  ok(dropper, "dropper opened");
+  info("Open the eyedropper again");
+  yield openEyedropper(view, swatch);
 
-  yield testSelect(view, swatch, dropper);
-
-  checkTelemetry();
+  info("Test that a color can be selected with the eyedropper");
+  yield testSelect(view, swatch, inspector, testActor);
 });
 
-function testESC(swatch, dropper) {
-  let deferred = defer();
-
-  dropper.once("destroy", () => {
-    let color = swatch.style.backgroundColor;
-    is(color, ORIGINAL_COLOR, "swatch didn't change after pressing ESC");
+function* testESC(swatch, inspector, testActor) {
+  info("Press escape");
+  let onCanceled = new Promise(resolve => {
+    inspector.inspector.once("color-pick-canceled", resolve);
+  });
+  yield testActor.synthesizeKey({key: "VK_ESCAPE", options: {}});
+  yield onCanceled;
 
-    deferred.resolve();
-  });
-
-  inspectPage(dropper, false).then(pressESC);
-
-  return deferred.promise;
+  let color = swatch.style.backgroundColor;
+  is(color, ORIGINAL_COLOR, "swatch didn't change after pressing ESC");
 }
 
-function* testSelect(view, swatch, dropper) {
-  let onDestroyed = dropper.once("destroy");
-  // the change to the content is done async after rule view change
+function* testSelect(view, swatch, inspector, testActor) {
+  info("Click at x:10px y:10px");
+  let onPicked = new Promise(resolve => {
+    inspector.inspector.once("color-picked", resolve);
+  });
+  // The change to the content is done async after rule view change
   let onRuleViewChanged = view.once("ruleview-changed");
 
-  inspectPage(dropper);
+  yield testActor.synthesizeMouse({selector: "html", x: 10, y: 10,
+                                   options: {type: "mousemove"}});
+  yield testActor.synthesizeMouse({selector: "html", x: 10, y: 10,
+                                   options: {type: "mousedown"}});
+  yield testActor.synthesizeMouse({selector: "html", x: 10, y: 10,
+                                   options: {type: "mouseup"}});
 
-  yield onDestroyed;
+  yield onPicked;
   yield onRuleViewChanged;
 
   let color = swatch.style.backgroundColor;
   is(color, EXPECTED_COLOR, "swatch changed colors");
 
   is((yield getComputedStyleProperty("div", null, "background-color")),
      EXPECTED_COLOR,
      "div's color set to body color after dropper");
 }
 
-function clearTelemetry() {
-  for (let histogramId in EXPECTED_TELEMETRY) {
-    let histogram = Services.telemetry.getHistogramById(histogramId);
-    histogram.clear();
-  }
-}
-
-function checkTelemetry() {
-  for (let histogramId in EXPECTED_TELEMETRY) {
-    let expected = EXPECTED_TELEMETRY[histogramId];
-    let histogram = Services.telemetry.getHistogramById(histogramId);
-    let snapshot = histogram.snapshot();
-
-    is(snapshot.sum, expected,
-      "eyedropper telemetry value correct for " + histogramId);
-  }
-}
-
-/* Helpers */
-
-function openEyedropper(view, swatch) {
-  let deferred = defer();
-
+function* openEyedropper(view, swatch) {
   let tooltip = view.tooltips.colorPicker.tooltip;
 
-  tooltip.once("shown", () => {
-    let tooltipDoc = tooltip.content.contentDocument;
-    let dropperButton = tooltipDoc.querySelector("#eyedropper-button");
-
-    tooltip.once("eyedropper-opened", (event, dropper) => {
-      deferred.resolve(dropper);
-    });
-    dropperButton.click();
-  });
-
+  info("Click on the swatch");
+  let onShown = tooltip.once("shown");
   swatch.click();
-  return deferred.promise;
-}
-
-function inspectPage(dropper, click = true) {
-  let target = document.documentElement;
-  let win = window;
-
-  // get location of the content, offset from browser window
-  let box = gBrowser.selectedBrowser.getBoundingClientRect();
-  let x = box.left + 1;
-  let y = box.top + 1;
-
-  return dropperStarted(dropper).then(() => {
-    EventUtils.synthesizeMouse(target, x, y, { type: "mousemove" }, win);
+  yield onShown;
 
-    return dropperLoaded(dropper).then(() => {
-      EventUtils.synthesizeMouse(target, x + 10, y + 10,
-        { type: "mousemove" }, win);
-
-      if (click) {
-        EventUtils.synthesizeMouse(target, x + 10, y + 10, {}, win);
-      }
-    });
-  });
-}
+  let tooltipDoc = tooltip.content.contentDocument;
+  let dropperButton = tooltipDoc.querySelector("#eyedropper-button");
 
-function dropperStarted(dropper) {
-  if (dropper.isStarted) {
-    return promise.resolve();
-  }
-  return dropper.once("started");
+  info("Click on the eyedropper icon");
+  let onOpened = tooltip.once("eyedropper-opened");
+  dropperButton.click();
+  yield onOpened;
 }
-
-function dropperLoaded(dropper) {
-  if (dropper.loaded) {
-    return promise.resolve();
-  }
-  return dropper.once("load");
-}
-
-function pressESC() {
-  EventUtils.synthesizeKey("VK_ESCAPE", { });
-}
--- a/devtools/client/inspector/shared/style-inspector-overlays.js
+++ b/devtools/client/inspector/shared/style-inspector-overlays.js
@@ -285,17 +285,17 @@ TooltipsOverlay.prototype = {
     this.previewTooltip.startTogglingOnHover(this.view.element,
       this._onPreviewTooltipTargetHover.bind(this));
 
     // MDN CSS help tooltip
     this.cssDocs = new CssDocsTooltip(panelDoc);
 
     if (this.isRuleView) {
       // Color picker tooltip
-      this.colorPicker = new SwatchColorPickerTooltip(panelDoc);
+      this.colorPicker = new SwatchColorPickerTooltip(panelDoc, this.view.inspector);
       // Cubic bezier tooltip
       this.cubicBezier = new SwatchCubicBezierTooltip(panelDoc);
       // Filter editor tooltip
       this.filterEditor = new SwatchFilterTooltip(panelDoc);
     }
 
     this._isStarted = true;
   },
--- a/devtools/client/shared/widgets/Tooltip.js
+++ b/devtools/client/shared/widgets/Tooltip.js
@@ -10,17 +10,16 @@ const {Spectrum} = require("devtools/cli
 const {CubicBezierWidget} =
       require("devtools/client/shared/widgets/CubicBezierWidget");
 const {MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
 const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
 const {TooltipToggle} = require("devtools/client/shared/widgets/tooltip/TooltipToggle");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {colorUtils} = require("devtools/shared/css-color");
 const Heritage = require("sdk/core/heritage");
-const {Eyedropper} = require("devtools/client/eyedropper/eyedropper");
 const {gDevTools} = require("devtools/client/framework/devtools");
 const Services = require("Services");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 
 loader.lazyRequireGetter(this, "beautify", "devtools/shared/jsbeautify/beautify");
 loader.lazyRequireGetter(this, "setNamedTimeout", "devtools/client/shared/widgets/view-helpers", true);
 loader.lazyRequireGetter(this, "clearNamedTimeout", "devtools/client/shared/widgets/view-helpers", true);
 loader.lazyRequireGetter(this, "setNamedTimeout", "devtools/client/shared/widgets/view-helpers", true);
@@ -853,19 +852,21 @@ SwatchBasedEditorTooltip.prototype = {
  * The swatch color picker tooltip class is a specific class meant to be used
  * along with output-parser's generated color swatches.
  * It extends the parent SwatchBasedEditorTooltip class.
  * It just wraps a standard Tooltip and sets its content with an instance of a
  * color picker.
  *
  * @param {XULDocument} doc
  */
-function SwatchColorPickerTooltip(doc) {
+function SwatchColorPickerTooltip(doc, inspector) {
   SwatchBasedEditorTooltip.call(this, doc);
 
+  this.inspector = inspector;
+
   // Creating a spectrum instance. this.spectrum will always be a promise that
   // resolves to the spectrum instance
   this.spectrum = this.tooltip.setColorPickerContent([0, 0, 0, 1]);
   this._onSpectrumColorChange = this._onSpectrumColorChange.bind(this);
   this._openEyeDropper = this._openEyeDropper.bind(this);
 }
 
 module.exports.SwatchColorPickerTooltip = SwatchColorPickerTooltip;
@@ -887,19 +888,26 @@ Heritage.extend(SwatchBasedEditorTooltip
       this.spectrum.then(spectrum => {
         spectrum.off("changed", this._onSpectrumColorChange);
         spectrum.rgb = this._colorToRgba(color);
         spectrum.on("changed", this._onSpectrumColorChange);
         spectrum.updateUI();
       });
     }
 
-    let tooltipDoc = this.tooltip.content.contentDocument;
-    let eyeButton = tooltipDoc.querySelector("#eyedropper-button");
-    eyeButton.addEventListener("click", this._openEyeDropper);
+    let {target} = this.inspector.toolbox;
+    target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
+      let tooltipDoc = this.tooltip.content.contentDocument;
+      let eyeButton = tooltipDoc.querySelector("#eyedropper-button");
+      if (value) {
+        eyeButton.addEventListener("click", this._openEyeDropper);
+      } else {
+        eyeButton.style.display = "none";
+      }
+    }, e => console.error(e));
   },
 
   _onSpectrumColorChange: function (event, rgba, cssColor) {
     this._selectColor(cssColor);
   },
 
   _selectColor: function (color) {
     if (this.activeSwatch) {
@@ -912,65 +920,52 @@ Heritage.extend(SwatchBasedEditorTooltip
 
       if (this.eyedropperOpen) {
         this.commit();
       }
     }
   },
 
   _openEyeDropper: function () {
-    let chromeWindow = this.tooltip.doc.defaultView.top;
-    let windowType = chromeWindow.document.documentElement
-                     .getAttribute("windowtype");
-    let toolboxWindow;
-    if (windowType != gDevTools.chromeWindowType) {
-      // this means the toolbox is in a seperate window. We need to make
-      // sure we'll be inspecting the browser window instead
-      toolboxWindow = chromeWindow;
-      chromeWindow = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
-      chromeWindow.focus();
-    }
-    let dropper = new Eyedropper(chromeWindow, { copyOnSelect: false,
-                                                 context: "picker" });
+    let {inspector, toolbox} = this.inspector;
+    inspector.pickColorFromPage({copyOnSelect: false}).catch(e => console.error(e));
 
-    dropper.once("select", (event, color) => {
-      if (toolboxWindow) {
-        toolboxWindow.focus();
-      }
+    inspector.once("color-picked", color => {
+      toolbox.win.focus();
       this._selectColor(color);
     });
 
-    dropper.once("destroy", () => {
+    inspector.once("color-pick-canceled", () => {
       this.eyedropperOpen = false;
       this.activeSwatch = null;
     });
 
-    dropper.open();
     this.eyedropperOpen = true;
 
     // close the colorpicker tooltip so that only the eyedropper is open.
     this.hide();
 
-    this.tooltip.emit("eyedropper-opened", dropper);
+    this.tooltip.emit("eyedropper-opened");
   },
 
   _colorToRgba: function (color) {
     color = new colorUtils.CssColor(color);
     let rgba = color._getRGBATuple();
     return [rgba.r, rgba.g, rgba.b, rgba.a];
   },
 
   _toDefaultType: function (color) {
     let colorObj = new colorUtils.CssColor(color);
     colorObj.setAuthoredUnitFromColor(this._originalColor);
     return colorObj.toString();
   },
 
   destroy: function () {
     SwatchBasedEditorTooltip.prototype.destroy.call(this);
+    this.inspector = null;
     this.currentSwatchColor = null;
     this.spectrum.then(spectrum => {
       spectrum.off("changed", this._onSpectrumColorChange);
       spectrum.destroy();
     });
   }
 });