Bug 1320939 - Lazy load all tooltip widgets until each is really used. r=jdescottes
authorAlexandre Poirot <poirot.alex@gmail.com>
Tue, 31 Jan 2017 15:31:37 +0100
changeset 403285 35a4c18b0b75614e9af385da5911f6314c32d830
parent 403284 c44d096d361a7bb520569e0a5e005fc5e093dcea
child 403286 dc4b3400913c177a0117da15e722be7bd17c94c3
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1320939
milestone55.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 1320939 - Lazy load all tooltip widgets until each is really used. r=jdescottes MozReview-Commit-ID: 9P93GocdLm8
devtools/client/inspector/computed/computed.js
devtools/client/inspector/rules/rules.js
devtools/client/inspector/rules/test/browser_rules_authored_color.js
devtools/client/inspector/rules/test/browser_rules_colorUnit.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-appears-on-swatch-click.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-edit-gradient.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-hides-on-tooltip.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-multiple-changes.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js
devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js
devtools/client/inspector/rules/test/browser_rules_css-docs-tooltip_closes-on-escape.js
devtools/client/inspector/rules/test/browser_rules_cubicbezier-appears-on-swatch-click.js
devtools/client/inspector/rules/test/browser_rules_cubicbezier-commit-on-ENTER.js
devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js
devtools/client/inspector/rules/test/browser_rules_edit-value-after-name_03.js
devtools/client/inspector/rules/test/browser_rules_eyedropper.js
devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js
devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js
devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js
devtools/client/inspector/rules/test/browser_rules_user-agent-styles-uneditable.js
devtools/client/inspector/rules/test/head.js
devtools/client/inspector/rules/views/text-property-editor.js
devtools/client/inspector/shared/style-inspector-menu.js
devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-color_02.js
devtools/client/inspector/shared/test/browser_styleinspector_tooltip-background-image.js
devtools/client/inspector/shared/test/browser_styleinspector_tooltip-closes-on-new-selection.js
devtools/client/inspector/shared/test/browser_styleinspector_tooltip-longhand-fontfamily.js
devtools/client/inspector/shared/test/browser_styleinspector_tooltip-multiple-background-images.js
devtools/client/inspector/shared/test/browser_styleinspector_tooltip-shorthand-fontfamily.js
devtools/client/inspector/shared/test/browser_styleinspector_tooltip-size.js
devtools/client/inspector/shared/tooltips-overlay.js
devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-xul.js
devtools/client/shared/widgets/tooltip/CssDocsTooltip.js
devtools/client/shared/widgets/tooltip/HTMLTooltip.js
devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
--- a/devtools/client/inspector/computed/computed.js
+++ b/devtools/client/inspector/computed/computed.js
@@ -218,17 +218,16 @@ function CssComputedView(inspector, docu
 
   this.createBoxModelView();
   this.createStyleViews();
 
   this._contextmenu = new StyleInspectorMenu(this, { isRuleView: false });
 
   // Add the tooltips and highlightersoverlay
   this.tooltips = new TooltipsOverlay(this);
-  this.tooltips.addToView();
 
   this.highlighters.addToView(this);
 }
 
 /**
  * Lookup a l10n string in the shared styleinspector string bundle.
  *
  * @param {String} name
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -176,17 +176,16 @@ function CssRuleView(inspector, document
   });
 
   this._showEmpty();
 
   this._contextmenu = new StyleInspectorMenu(this, { isRuleView: true });
 
   // Add the tooltips and highlighters to the view
   this.tooltips = new TooltipsOverlay(this);
-  this.tooltips.addToView();
 
   this.highlighters.addToView(this);
 
   this.classListPreviewer = new ClassListPreviewer(this.inspector, this.classPanel);
 
   EventEmitter.decorate(this);
 }
 
--- a/devtools/client/inspector/rules/test/browser_rules_authored_color.js
+++ b/devtools/client/inspector/rules/test/browser_rules_authored_color.js
@@ -28,22 +28,22 @@ add_task(function* () {
     html += `<div id="${id}" style="color: ${color}">Styled Node</div>`;
   }
 
   let tab = yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(html));
 
   let {inspector, view} = yield openRuleView();
 
   for (let color of colors) {
-    let cPicker = view.tooltips.colorPicker;
     let selector = "#" + color.id;
     yield selectNode(selector, inspector);
 
     let swatch = getRuleViewProperty(view, "element", "color").valueSpan
         .querySelector(".ruleview-colorswatch");
+    let cPicker = view.tooltips.getTooltip("colorPicker");
     let onColorPickerReady = cPicker.once("ready");
     swatch.click();
     yield onColorPickerReady;
 
     yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
       selector,
       name: "color",
       value: "rgb(0, 255, 0)"
--- a/devtools/client/inspector/rules/test/browser_rules_colorUnit.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorUnit.js
@@ -34,17 +34,17 @@ add_task(function* () {
 
     let target = TargetFactory.forTab(tab);
     yield gDevTools.closeToolbox(target);
     gBrowser.removeCurrentTab();
   }
 });
 
 function* basicTest(view, name, result) {
-  let cPicker = view.tooltips.colorPicker;
+  let cPicker = view.tooltips.getTooltip("colorPicker");
   let swatch = getRuleViewProperty(view, "#testid", "color").valueSpan
       .querySelector(".ruleview-colorswatch");
   let onColorPickerReady = cPicker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
     selector: "#testid",
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js
@@ -22,24 +22,24 @@ add_task(function* () {
   let {view} = yield openRuleView();
   let value = getRuleViewProperty(view, "body", "background").valueSpan;
   let swatch = value.querySelectorAll(".ruleview-colorswatch")[0];
   let url = value.querySelector(".theme-link");
   yield testImageTooltipAfterColorChange(swatch, url, view);
 });
 
 function* testImageTooltipAfterColorChange(swatch, url, ruleView) {
+  let previewTooltip = ruleView.tooltips.getTooltip("previewTooltip");
   info("First, verify that the image preview tooltip works");
-  let anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip,
-                                          url);
+  let anchor = yield isHoverTooltipTarget(previewTooltip, url);
   ok(anchor, "The image preview tooltip is shown on the url span");
   is(anchor, url, "The anchor returned by the showOnHover callback is correct");
 
   info("Open the color picker tooltip and change the color");
-  let picker = ruleView.tooltips.colorPicker;
+  let picker = ruleView.tooltips.getTooltip("colorPicker");
   let onColorPickerReady = picker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   yield simulateColorPickerChange(ruleView, picker, [0, 0, 0, 1], {
     selector: "body",
     name: "background-image",
     value: 'url("chrome://global/skin/icons/warning-64.png"), linear-gradient(rgb(0, 0, 0), rgb(255, 0, 102) 400px)'
@@ -52,12 +52,12 @@ function* testImageTooltipAfterColorChan
   yield onHidden;
   yield onModifications;
 
   info("Verify again that the image preview tooltip works");
   // After a color change, the property is re-populated, we need to get the new
   // dom node
   url = getRuleViewProperty(ruleView, "body", "background").valueSpan
     .querySelector(".theme-link");
-  anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip, url);
+  anchor = yield isHoverTooltipTarget(previewTooltip, url);
   ok(anchor, "The image preview tooltip is shown on the url span");
   is(anchor, url, "The anchor returned by the showOnHover callback is correct");
 }
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js
@@ -26,17 +26,17 @@ add_task(function* () {
   yield testColorChangeIsntRevertedWhenOtherTooltipIsShown(view);
 });
 
 function* testColorChangeIsntRevertedWhenOtherTooltipIsShown(ruleView) {
   let swatch = getRuleViewProperty(ruleView, "body", "background").valueSpan
     .querySelector(".ruleview-colorswatch");
 
   info("Open the color picker tooltip and change the color");
-  let picker = ruleView.tooltips.colorPicker;
+  let picker = ruleView.tooltips.getTooltip("colorPicker");
   let onColorPickerReady = picker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   yield simulateColorPickerChange(ruleView, picker, [0, 0, 0, 1], {
     selector: "body",
     name: "background-color",
     value: "rgb(0, 0, 0)"
@@ -48,19 +48,20 @@ function* testColorChangeIsntRevertedWhe
   let onHidden = picker.tooltip.once("hidden");
   focusAndSendKey(spectrum.element.ownerDocument.defaultView, "RETURN");
   yield onHidden;
   yield onModifications;
 
   info("Open the image preview tooltip");
   let value = getRuleViewProperty(ruleView, "body", "background").valueSpan;
   let url = value.querySelector(".theme-link");
-  let onShown = ruleView.tooltips.previewTooltip.once("shown");
-  let anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip, url);
-  ruleView.tooltips.previewTooltip.show(anchor);
+  let previewTooltip = ruleView.tooltips.getTooltip("previewTooltip");
+  let onShown = previewTooltip.once("shown");
+  let anchor = yield isHoverTooltipTarget(previewTooltip, url);
+  previewTooltip.show(anchor);
   yield onShown;
 
   info("Image tooltip is shown, verify that the swatch is still correct");
   swatch = value.querySelector(".ruleview-colorswatch");
   is(swatch.style.backgroundColor, "black",
     "The swatch's color is correct");
   is(swatch.nextSibling.textContent, "black", "The color name is correct");
 }
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-appears-on-swatch-click.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-appears-on-swatch-click.js
@@ -28,17 +28,17 @@ add_task(function* () {
     info("Testing that the colorpicker appears on swatch click");
     let value = getRuleViewProperty(view, "body", property).valueSpan;
     let swatch = value.querySelector(".ruleview-colorswatch");
     yield testColorPickerAppearsOnColorSwatchClick(view, swatch);
   }
 });
 
 function* testColorPickerAppearsOnColorSwatchClick(view, swatch) {
-  let cPicker = view.tooltips.colorPicker;
+  let cPicker = view.tooltips.getTooltip("colorPicker");
   ok(cPicker, "The rule-view has the expected colorPicker property");
 
   let cPickerPanel = cPicker.tooltip.panel;
   ok(cPickerPanel, "The XUL panel for the color picker exists");
 
   let onColorPickerReady = cPicker.once("ready");
   swatch.click();
   yield onColorPickerReady;
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js
@@ -21,17 +21,17 @@ add_task(function* () {
   let {view} = yield openRuleView();
 
   let swatch = getRuleViewProperty(view, "body", "border").valueSpan
     .querySelector(".ruleview-colorswatch");
   yield testPressingEnterCommitsChanges(swatch, view);
 });
 
 function* testPressingEnterCommitsChanges(swatch, ruleView) {
-  let cPicker = ruleView.tooltips.colorPicker;
+  let cPicker = ruleView.tooltips.getTooltip("colorPicker");
 
   let onColorPickerReady = cPicker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   yield simulateColorPickerChange(ruleView, cPicker, [0, 255, 0, .5], {
     selector: "body",
     name: "border-left-color",
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-edit-gradient.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-edit-gradient.js
@@ -47,17 +47,17 @@ function testColorParsing(view) {
 
 function* testPickingNewColor(view) {
   // Grab the first color swatch and color in the gradient
   let ruleEl = getRuleViewProperty(view, "body", "background-image");
   let swatchEl = ruleEl.valueSpan.querySelector(".ruleview-colorswatch");
   let colorEl = ruleEl.valueSpan.querySelector(".ruleview-color");
 
   info("Get the color picker tooltip and clicking on the swatch to show it");
-  let cPicker = view.tooltips.colorPicker;
+  let cPicker = view.tooltips.getTooltip("colorPicker");
   let onColorPickerReady = cPicker.once("ready");
   swatchEl.click();
   yield onColorPickerReady;
 
   let change = {
     selector: "body",
     name: "background-image",
     value: "linear-gradient(to left, rgb(1, 1, 1) 25%, " +
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-hides-on-tooltip.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-hides-on-tooltip.js
@@ -23,24 +23,24 @@ add_task(function* () {
   let {view} = yield openRuleView();
 
   let swatch = getRuleViewProperty(view, "body", "color").valueSpan
     .querySelector(".ruleview-colorswatch");
 
   let bgImageSpan = getRuleViewProperty(view, "body", "background-image").valueSpan;
   let uriSpan = bgImageSpan.querySelector(".theme-link");
 
-  let colorPicker = view.tooltips.colorPicker;
+  let colorPicker = view.tooltips.getTooltip("colorPicker");
   info("Showing the color picker tooltip by clicking on the color swatch");
   let onColorPickerReady = colorPicker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   info("Now showing the image preview tooltip to hide the color picker");
   let onHidden = colorPicker.tooltip.once("hidden");
   // Hiding the color picker refreshes the value.
   let onRuleViewChanged = view.once("ruleview-changed");
-  yield assertHoverTooltipOn(view.tooltips.previewTooltip, uriSpan);
+  yield assertHoverTooltipOn(view.tooltips.getTooltip("previewTooltip"), uriSpan);
   yield onHidden;
   yield onRuleViewChanged;
 
   ok(true, "The color picker closed when the image preview tooltip appeared");
 });
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-multiple-changes.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-multiple-changes.js
@@ -37,17 +37,17 @@ add_task(function* () {
 function* testSimpleMultipleColorChanges(inspector, ruleView) {
   yield selectNode("p", inspector);
 
   info("Getting the <p> tag's color property");
   let swatch = getRuleViewProperty(ruleView, "p", "color").valueSpan
     .querySelector(".ruleview-colorswatch");
 
   info("Opening the color picker");
-  let picker = ruleView.tooltips.colorPicker;
+  let picker = ruleView.tooltips.getTooltip("colorPicker");
   let onColorPickerReady = picker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   info("Changing the color several times");
   let colors = [
     {rgba: [0, 0, 0, 1], computed: "rgb(0, 0, 0)"},
     {rgba: [100, 100, 100, 1], computed: "rgb(100, 100, 100)"},
@@ -65,17 +65,17 @@ function* testSimpleMultipleColorChanges
 function* testComplexMultipleColorChanges(inspector, ruleView) {
   yield selectNode("body", inspector);
 
   info("Getting the <body> tag's color property");
   let swatch = getRuleViewProperty(ruleView, "body", "background").valueSpan
     .querySelector(".ruleview-colorswatch");
 
   info("Opening the color picker");
-  let picker = ruleView.tooltips.colorPicker;
+  let picker = ruleView.tooltips.getTooltip("colorPicker");
   let onColorPickerReady = picker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   info("Changing the color several times");
   let colors = [
     {rgba: [0, 0, 0, 1], computed: "rgb(0, 0, 0)"},
     {rgba: [100, 100, 100, 1], computed: "rgb(100, 100, 100)"},
@@ -96,17 +96,17 @@ function* testComplexMultipleColorChange
 function* testOverriddenMultipleColorChanges(inspector, ruleView) {
   yield selectNode("p", inspector);
 
   info("Getting the <body> tag's color property");
   let swatch = getRuleViewProperty(ruleView, "body", "color").valueSpan
     .querySelector(".ruleview-colorswatch");
 
   info("Opening the color picker");
-  let picker = ruleView.tooltips.colorPicker;
+  let picker = ruleView.tooltips.getTooltip("colorPicker");
   let onColorPickerReady = picker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   info("Changing the color several times");
   let colors = [
     {rgba: [0, 0, 0, 1], computed: "rgb(0, 0, 0)"},
     {rgba: [100, 100, 100, 1], computed: "rgb(100, 100, 100)"},
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js
@@ -46,17 +46,17 @@ add_task(function* () {
   EventUtils.synthesizeMouse(spectrum.dragger, 10, 10, {
     // -1 = no buttons are pressed down
     button: -1,
     type: "mousemove",
   }, spectrum.dragger.ownerDocument.defaultView);
 });
 
 function* openColorPickerForSwatch(swatch, view) {
-  let cPicker = view.tooltips.colorPicker;
+  let cPicker = view.tooltips.getTooltip("colorPicker");
   ok(cPicker, "The rule-view has the expected colorPicker property");
 
   let cPickerPanel = cPicker.tooltip.panel;
   ok(cPickerPanel, "The XUL panel for the color picker exists");
 
   let onColorPickerReady = cPicker.once("ready");
   swatch.click();
   yield onColorPickerReady;
--- a/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js
@@ -42,17 +42,17 @@ add_task(function* () {
   info("Setting the popupNode for the MDN docs tooltip");
 
   let {nameSpan} = getRuleViewProperty(view, "element", PROPERTYNAME);
 
   let allMenuItems = openStyleContextMenuAndGetAllItems(view, nameSpan.firstChild);
   let menuitemShowMdnDocs = allMenuItems.find(item => item.label ===
     STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.showMdnDocs"));
 
-  let cssDocs = view.tooltips.cssDocs;
+  let cssDocs = view.tooltips.getTooltip("cssDocs");
 
   info("Showing the MDN docs tooltip");
   let onShown = cssDocs.tooltip.once("shown");
   menuitemShowMdnDocs.click();
   yield onShown;
   ok(true, "The MDN docs tooltip was shown");
 
   info("Quick check that the tooltip contents are set");
--- a/devtools/client/inspector/rules/test/browser_rules_css-docs-tooltip_closes-on-escape.js
+++ b/devtools/client/inspector/rules/test/browser_rules_css-docs-tooltip_closes-on-escape.js
@@ -33,19 +33,20 @@ add_task(function* () {
   yield selectNode("div", inspector);
 
   setBaseCssDocsUrl(URL_ROOT);
 
   info("Retrieve a valid anchor for the CssDocs tooltip");
   let {nameSpan} = getRuleViewProperty(view, "element", PROPERTYNAME);
 
   info("Showing the MDN docs tooltip");
-  let onShown = view.tooltips.cssDocs.tooltip.once("shown");
-  view.tooltips.cssDocs.show(nameSpan, PROPERTYNAME);
+  let cssDocs = view.tooltips.getTooltip("cssDocs");
+  let onShown = cssDocs.tooltip.once("shown");
+  cssDocs.show(nameSpan, PROPERTYNAME);
   yield onShown;
   ok(true, "The MDN docs tooltip was shown");
 
   info("Simulate pressing the 'Escape' key");
-  let onHidden = view.tooltips.cssDocs.tooltip.once("hidden");
+  let onHidden = cssDocs.tooltip.once("hidden");
   EventUtils.sendKey("escape");
   yield onHidden;
   ok(true, "The MDN docs tooltip was hidden on pressing 'escape'");
 });
--- a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-appears-on-swatch-click.js
+++ b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-appears-on-swatch-click.js
@@ -48,17 +48,17 @@ add_task(function* () {
     info("Testing that the cubic-bezier appears on cubicswatch click");
     yield testAppears(view, swatch);
   }
 });
 
 function* testAppears(view, swatch) {
   ok(swatch, "The cubic-swatch exists");
 
-  let bezier = view.tooltips.cubicBezier;
+  let bezier = view.tooltips.getTooltip("cubicBezier");
   ok(bezier, "The rule-view has the expected cubicBezier property");
 
   let bezierPanel = bezier.tooltip.panel;
   ok(bezierPanel, "The XUL panel for the cubic-bezier tooltip exists");
 
   let onBezierWidgetReady = bezier.once("ready");
   swatch.click();
   yield onBezierWidgetReady;
--- a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-commit-on-ENTER.js
+++ b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-commit-on-ENTER.js
@@ -22,17 +22,17 @@ add_task(function* () {
   info("Getting the bezier swatch element");
   let swatch = getRuleViewProperty(view, "body", "transition").valueSpan
     .querySelector(".ruleview-bezierswatch");
 
   yield testPressingEnterCommitsChanges(swatch, view);
 });
 
 function* testPressingEnterCommitsChanges(swatch, ruleView) {
-  let bezierTooltip = ruleView.tooltips.cubicBezier;
+  let bezierTooltip = ruleView.tooltips.getTooltip("cubicBezier");
 
   info("Showing the tooltip");
   let onBezierWidgetReady = bezierTooltip.once("ready");
   swatch.click();
   yield onBezierWidgetReady;
 
   let widget = yield bezierTooltip.widget;
   info("Simulating a change of curve in the widget");
--- a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js
+++ b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js
@@ -85,16 +85,16 @@ function* getRulePropertyValue(name) {
     name: name
   });
   return propValue;
 }
 
 function* escapeTooltip(view) {
   info("Pressing ESCAPE to close the tooltip");
 
-  let bezierTooltip = view.tooltips.cubicBezier;
+  let bezierTooltip = view.tooltips.getTooltip("cubicBezier");
   let widget = yield bezierTooltip.widget;
   let onHidden = bezierTooltip.tooltip.once("hidden");
   let onModifications = view.once("ruleview-changed");
   focusAndSendKey(widget.parent.ownerDocument.defaultView, "ESCAPE");
   yield onHidden;
   yield onModifications;
 }
--- a/devtools/client/inspector/rules/test/browser_rules_edit-value-after-name_03.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-value-after-name_03.js
@@ -28,17 +28,17 @@ add_task(function* () {
 
   info("Test click on color swatch while editing property name");
 
   yield selectNode("#testid", inspector);
   let ruleEditor = getRuleViewRuleEditor(view, 1);
   let propEditor = ruleEditor.rule.textProps[1].editor;
   let swatchSpan = propEditor.valueSpan.querySelectorAll(
     ".ruleview-colorswatch")[3];
-  let colorPicker = view.tooltips.colorPicker;
+  let colorPicker = view.tooltips.getTooltip("colorPicker");
 
   info("Focus the background name span");
   yield focusEditableField(view, propEditor.nameSpan);
   let editor = inplaceEditor(propEditor.doc.activeElement);
 
   info("Modify the background property to background-image to trigger the " +
     "property-value-updated event");
   editor.input.value = "background-image";
--- a/devtools/client/inspector/rules/test/browser_rules_eyedropper.js
+++ b/devtools/client/inspector/rules/test/browser_rules_eyedropper.js
@@ -43,17 +43,17 @@ add_task(function* () {
   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");
 
   info("Open the eyedropper from the colorpicker tooltip");
   yield openEyedropper(view, swatch);
 
-  let tooltip = view.tooltips.colorPicker.tooltip;
+  let tooltip = view.tooltips.getTooltip("colorPicker").tooltip;
   ok(!tooltip.isVisible(), "color picker tooltip is closed after opening eyedropper");
 
   info("Test that pressing escape dismisses the eyedropper");
   yield testESC(swatch, inspector, testActor);
 
   info("Open the eyedropper again");
   yield openEyedropper(view, swatch);
 
@@ -102,20 +102,20 @@ function* testSelect(view, swatch, inspe
   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* openEyedropper(view, swatch) {
-  let tooltip = view.tooltips.colorPicker.tooltip;
+  let tooltip = view.tooltips.getTooltip("colorPicker").tooltip;
 
   info("Click on the swatch");
-  let onColorPickerReady = view.tooltips.colorPicker.once("ready");
+  let onColorPickerReady = view.tooltips.getTooltip("colorPicker").once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   let dropperButton = tooltip.doc.querySelector("#eyedropper-button");
 
   info("Click on the eyedropper icon");
   let onOpened = tooltip.once("eyedropper-opened");
   dropperButton.click();
--- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js
+++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js
@@ -11,17 +11,17 @@ add_task(function* () {
   yield addTab(TEST_URL);
 
   let {view} = yield openRuleView();
 
   info("Getting the filter swatch element");
   let swatch = getRuleViewProperty(view, "body", "filter").valueSpan
     .querySelector(".ruleview-filterswatch");
 
-  let filterTooltip = view.tooltips.filterEditor;
+  let filterTooltip = view.tooltips.getTooltip("filterEditor");
   // Clicking on a cssfilter swatch sets the current filter value in the tooltip
   // which, in turn, makes the FilterWidget emit an "updated" event that causes
   // the rule-view to refresh. So we must wait for the ruleview-changed event.
   let onRuleViewChanged = view.once("ruleview-changed");
   swatch.click();
   yield onRuleViewChanged;
 
   ok(true, "The shown event was emitted after clicking on swatch");
--- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js
+++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js
@@ -19,17 +19,17 @@ add_task(function* () {
   // Clicking on a cssfilter swatch sets the current filter value in the tooltip
   // which, in turn, makes the FilterWidget emit an "updated" event that causes
   // the rule-view to refresh. So we must wait for the ruleview-changed event.
   let onRuleViewChanged = view.once("ruleview-changed");
   swatch.click();
   yield onRuleViewChanged;
 
   info("Get the cssfilter widget instance");
-  let filterTooltip = view.tooltips.filterEditor;
+  let filterTooltip = view.tooltips.getTooltip("filterEditor");
   let widget = filterTooltip.widget;
 
   info("Set a new value in the cssfilter widget");
   onRuleViewChanged = view.once("ruleview-changed");
   widget.setCssValue("blur(2px)");
   yield waitForComputedStyleProperty("body", null, "filter", "blur(2px)");
   yield onRuleViewChanged;
   ok(true, "Changes previewed on the element");
--- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js
+++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js
@@ -97,22 +97,22 @@ function* clickOnFilterSwatch(swatch, vi
   let onRuleViewChanged = view.once("ruleview-changed");
   swatch.click();
   yield onRuleViewChanged;
 }
 
 function* setValueInFilterWidget(value, view) {
   info("Setting the CSS filter value in the tooltip");
 
-  let filterTooltip = view.tooltips.filterEditor;
+  let filterTooltip = view.tooltips.getTooltip("filterEditor");
   let onRuleViewChanged = view.once("ruleview-changed");
   filterTooltip.widget.setCssValue(value);
   yield onRuleViewChanged;
 }
 
 function* pressEscapeToCloseTooltip(view) {
   info("Pressing ESCAPE to close the tooltip");
 
-  let filterTooltip = view.tooltips.filterEditor;
+  let filterTooltip = view.tooltips.getTooltip("filterEditor");
   let onRuleViewChanged = view.once("ruleview-changed");
   EventUtils.sendKey("ESCAPE", filterTooltip.widget.styleWindow);
   yield onRuleViewChanged;
 }
--- a/devtools/client/inspector/rules/test/browser_rules_user-agent-styles-uneditable.js
+++ b/devtools/client/inspector/rules/test/browser_rules_user-agent-styles-uneditable.js
@@ -46,13 +46,13 @@ function* userAgentStylesUneditable(insp
       "nameSpan is not editable");
     ok(!firstProp.editor.valueSpan._editable,
       "valueSpan is not editable");
     ok(!rule.editor.closeBrace._editable, "closeBrace is not editable");
 
     let colorswatch = rule.editor.element
       .querySelector(".ruleview-colorswatch");
     if (colorswatch) {
-      ok(!view.tooltips.colorPicker.swatches.has(colorswatch),
+      ok(!view.tooltips.getTooltip("colorPicker").swatches.has(colorswatch),
         "The swatch is not editable");
     }
   }
 }
--- a/devtools/client/inspector/rules/test/head.js
+++ b/devtools/client/inspector/rules/test/head.js
@@ -170,17 +170,17 @@ var simulateColorPickerChange = Task.asy
  *          - {String} value The expected style value
  * The style will be checked like so: getComputedStyle(element)[name] === value
  */
 var openColorPickerAndSelectColor = Task.async(function* (view, ruleIndex,
     propIndex, newRgba, expectedChange) {
   let ruleEditor = getRuleViewRuleEditor(view, ruleIndex);
   let propEditor = ruleEditor.rule.textProps[propIndex].editor;
   let swatch = propEditor.valueSpan.querySelector(".ruleview-colorswatch");
-  let cPicker = view.tooltips.colorPicker;
+  let cPicker = view.tooltips.getTooltip("colorPicker");
 
   info("Opening the colorpicker by clicking the color swatch");
   let onColorPickerReady = cPicker.once("ready");
   swatch.click();
   yield onColorPickerReady;
 
   yield simulateColorPickerChange(view, cPicker, newRgba, expectedChange);
 
@@ -208,17 +208,17 @@ var openColorPickerAndSelectColor = Task
  *          - {String} value The expected style value
  * The style will be checked like so: getComputedStyle(element)[name] === value
  */
 var openCubicBezierAndChangeCoords = Task.async(function* (view, ruleIndex,
     propIndex, coords, expectedChange) {
   let ruleEditor = getRuleViewRuleEditor(view, ruleIndex);
   let propEditor = ruleEditor.rule.textProps[propIndex].editor;
   let swatch = propEditor.valueSpan.querySelector(".ruleview-bezierswatch");
-  let bezierTooltip = view.tooltips.cubicBezier;
+  let bezierTooltip = view.tooltips.getTooltip("cubicBezier");
 
   info("Opening the cubicBezier by clicking the swatch");
   let onBezierWidgetReady = bezierTooltip.once("ready");
   swatch.click();
   yield onBezierWidgetReady;
 
   let widget = yield bezierTooltip.widget;
 
--- a/devtools/client/inspector/rules/views/text-property-editor.js
+++ b/devtools/client/inspector/rules/views/text-property-editor.js
@@ -370,17 +370,17 @@ TextPropertyEditor.prototype = {
 
     // Attach the color picker tooltip to the color swatches
     this._colorSwatchSpans =
       this.valueSpan.querySelectorAll("." + COLOR_SWATCH_CLASS);
     if (this.ruleEditor.isEditable) {
       for (let span of this._colorSwatchSpans) {
         // Adding this swatch to the list of swatches our colorpicker
         // knows about
-        this.ruleView.tooltips.colorPicker.addSwatch(span, {
+        this.ruleView.tooltips.getTooltip("colorPicker").addSwatch(span, {
           onShow: this._onStartEditing,
           onPreview: this._onSwatchPreview,
           onCommit: this._onSwatchCommit,
           onRevert: this._onSwatchRevert
         });
         span.on("unit-change", this._onSwatchCommit);
         let title = l10n("rule.colorSwatch.tooltip");
         span.setAttribute("title", title);
@@ -390,34 +390,34 @@ TextPropertyEditor.prototype = {
 
     // Attach the cubic-bezier tooltip to the bezier swatches
     this._bezierSwatchSpans =
       this.valueSpan.querySelectorAll("." + BEZIER_SWATCH_CLASS);
     if (this.ruleEditor.isEditable) {
       for (let span of this._bezierSwatchSpans) {
         // Adding this swatch to the list of swatches our colorpicker
         // knows about
-        this.ruleView.tooltips.cubicBezier.addSwatch(span, {
+        this.ruleView.tooltips.getTooltip("cubicBezier").addSwatch(span, {
           onShow: this._onStartEditing,
           onPreview: this._onSwatchPreview,
           onCommit: this._onSwatchCommit,
           onRevert: this._onSwatchRevert
         });
         let title = l10n("rule.bezierSwatch.tooltip");
         span.setAttribute("title", title);
       }
     }
 
     // Attach the filter editor tooltip to the filter swatch
     let span = this.valueSpan.querySelector("." + FILTER_SWATCH_CLASS);
     if (this.ruleEditor.isEditable) {
       if (span) {
         parserOptions.filterSwatch = true;
 
-        this.ruleView.tooltips.filterEditor.addSwatch(span, {
+        this.ruleView.tooltips.getTooltip("filterEditor").addSwatch(span, {
           onShow: this._onStartEditing,
           onPreview: this._onSwatchPreview,
           onCommit: this._onSwatchCommit,
           onRevert: this._onSwatchRevert
         }, outputParser, parserOptions);
         let title = l10n("rule.filterSwatch.tooltip");
         span.setAttribute("title", title);
       }
@@ -737,17 +737,17 @@ TextPropertyEditor.prototype = {
    * direction.
    *
    * @param {Number} direction
    *        The move focus direction number.
    */
   remove: function (direction) {
     if (this._colorSwatchSpans && this._colorSwatchSpans.length) {
       for (let span of this._colorSwatchSpans) {
-        this.ruleView.tooltips.colorPicker.removeSwatch(span);
+        this.ruleView.tooltips.getTooltip("colorPicker").removeSwatch(span);
         span.off("unit-change", this._onSwatchCommit);
       }
     }
 
     if (this.angleSwatchSpans && this.angleSwatchSpans.length) {
       for (let span of this.angleSwatchSpans) {
         span.off("unit-change", this._onSwatchCommit);
       }
--- a/devtools/client/inspector/shared/style-inspector-menu.js
+++ b/devtools/client/inspector/shared/style-inspector-menu.js
@@ -409,17 +409,17 @@ StyleInspectorMenu.prototype = {
   }),
 
   /**
    *  Show docs from MDN for a CSS property.
    */
   _onShowMdnDocs: function () {
     let cssPropertyName = this.styleDocument.popupNode.textContent;
     let anchor = this.styleDocument.popupNode.parentNode;
-    let cssDocsTooltip = this.view.tooltips.cssDocs;
+    let cssDocsTooltip = this.view.tooltips.getTooltip("cssDocs");
     cssDocsTooltip.show(anchor, cssPropertyName);
   },
 
   /**
    * Add a new rule to the current element.
    */
   _onAddNewRule: function () {
     this.view._onAddRule();
--- a/devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-color_02.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-color_02.js
@@ -75,17 +75,17 @@ function* testManualEdit(inspector, view
 function* testColorPickerEdit(inspector, view) {
   info("Testing colors edited via color picker");
   yield selectNode("div", inspector);
 
   let swatchElement = getRuleViewProperty(view, "div", "color").valueSpan
     .querySelector(".ruleview-colorswatch");
 
   info("Opening the color picker");
-  let picker = view.tooltips.colorPicker;
+  let picker = view.tooltips.getTooltip("colorPicker");
   let onColorPickerReady = picker.once("ready");
   swatchElement.click();
   yield onColorPickerReady;
 
   let rgbaColor = [83, 183, 89, 1];
   let rgbaColorText = "rgba(83, 183, 89, 1)";
   yield simulateColorPickerChange(view, picker, rgbaColor);
 
--- a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-background-image.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-background-image.js
@@ -47,79 +47,79 @@ add_task(function* () {
   yield onComputedViewReady;
 
   info("Testing that the background-image computed style has a tooltip too");
   yield testComputedView(view);
 });
 
 function* testBodyRuleView(view) {
   info("Testing tooltips in the rule view");
-  let panel = view.tooltips.previewTooltip.panel;
+  let panel = view.tooltips.getTooltip("previewTooltip").panel;
 
   // Check that the rule view has a tooltip and that a XUL panel has
   // been created
-  ok(view.tooltips.previewTooltip, "Tooltip instance exists");
+  ok(view.tooltips.getTooltip("previewTooltip"), "Tooltip instance exists");
   ok(panel, "XUL panel exists");
 
   // Get the background-image property inside the rule view
   let {valueSpan} = getRuleViewProperty(view, "body", "background-image");
   let uriSpan = valueSpan.querySelector(".theme-link");
 
-  yield assertHoverTooltipOn(view.tooltips.previewTooltip, uriSpan);
+  yield assertHoverTooltipOn(view.tooltips.getTooltip("previewTooltip"), uriSpan);
 
   let images = panel.getElementsByTagName("img");
   is(images.length, 1, "Tooltip contains an image");
   ok(images[0].getAttribute("src")
     .indexOf("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHe") !== -1,
     "The image URL seems fine");
 }
 
 function* testDivRuleView(view) {
-  let panel = view.tooltips.previewTooltip.panel;
+  let panel = view.tooltips.getTooltip("previewTooltip").panel;
 
   // Get the background property inside the rule view
   let {valueSpan} = getRuleViewProperty(view, ".test-element", "background");
   let uriSpan = valueSpan.querySelector(".theme-link");
 
-  yield assertHoverTooltipOn(view.tooltips.previewTooltip, uriSpan);
+  yield assertHoverTooltipOn(view.tooltips.getTooltip("previewTooltip"), uriSpan);
 
   let images = panel.getElementsByTagName("img");
   is(images.length, 1, "Tooltip contains an image");
   ok(images[0].getAttribute("src").startsWith("data:"),
     "Tooltip contains a data-uri image as expected");
 }
 
 function* testTooltipAppearsEvenInEditMode(view) {
   info("Switching to edit mode in the rule view");
   let editor = yield turnToEditMode(view);
 
   info("Now trying to show the preview tooltip");
   let {valueSpan} = getRuleViewProperty(view, ".test-element", "background");
   let uriSpan = valueSpan.querySelector(".theme-link");
-  yield assertHoverTooltipOn(view.tooltips.previewTooltip, uriSpan);
+  yield assertHoverTooltipOn(view.tooltips.getTooltip("previewTooltip"), uriSpan);
 
   is(view.styleDocument.activeElement, editor.input,
     "Tooltip was shown in edit mode, and inplace-editor still focused");
 }
 
 function turnToEditMode(ruleView) {
   let brace = ruleView.styleDocument.querySelector(".ruleview-ruleclose");
   return focusEditableField(ruleView, brace);
 }
 
 function* testComputedView(view) {
-  let tooltip = view.tooltips.previewTooltip;
+  let tooltip = view.tooltips.getTooltip("previewTooltip");
   ok(tooltip, "The computed-view has a tooltip defined");
 
   let panel = tooltip.panel;
   ok(panel, "The computed-view tooltip has a XUL panel");
 
   let {valueSpan} = getComputedViewProperty(view, "background-image");
   let uriSpan = valueSpan.querySelector(".theme-link");
 
-  yield assertHoverTooltipOn(view.tooltips.previewTooltip, uriSpan);
+  yield assertHoverTooltipOn(view.tooltips.getTooltip("previewTooltip"), uriSpan);
 
   let images = panel.getElementsByTagName("img");
   is(images.length, 1, "Tooltip contains an image");
 
   ok(images[0].getAttribute("src").startsWith("data:"),
     "Tooltip contains a data-uri in the computed-view too");
 }
--- a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-closes-on-new-selection.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-closes-on-new-selection.js
@@ -20,17 +20,17 @@ add_task(function* () {
   info("Testing computed view tooltip closes on new selection");
   view = selectComputedView(inspector);
   yield testComputedView(view, inspector);
 });
 
 function* testRuleView(ruleView, inspector) {
   info("Showing the tooltip");
 
-  let tooltip = ruleView.tooltips.previewTooltip;
+  let tooltip = ruleView.tooltips.getTooltip("previewTooltip");
   let tooltipContent = ruleView.styleDocument.createElementNS(XHTML_NS, "div");
   yield tooltip.setContent(tooltipContent, {width: 100, height: 30});
 
   // Stop listening for mouse movements because it's not needed for this test,
   // and causes intermittent failures on Linux. When this test runs in the suite
   // sometimes a mouseleave event is dispatched at the start, which causes the
   // tooltip to hide in the middle of being shown, which causes timeouts later.
   tooltip.stopTogglingOnHover();
@@ -45,17 +45,17 @@ function* testRuleView(ruleView, inspect
   yield onHidden;
 
   ok(true, "Rule view tooltip closed after a new node got selected");
 }
 
 function* testComputedView(computedView, inspector) {
   info("Showing the tooltip");
 
-  let tooltip = computedView.tooltips.previewTooltip;
+  let tooltip = computedView.tooltips.getTooltip("previewTooltip");
   let tooltipContent = computedView.styleDocument.createElementNS(XHTML_NS, "div");
   yield tooltip.setContent(tooltipContent, {width: 100, height: 30});
 
   // Stop listening for mouse movements because it's not needed for this test,
   // and causes intermittent failures on Linux. When this test runs in the suite
   // sometimes a mouseleave event is dispatched at the start, which causes the
   // tooltip to hide in the middle of being shown, which causes timeouts later.
   tooltip.stopTogglingOnHover();
--- a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-longhand-fontfamily.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-longhand-fontfamily.js
@@ -31,17 +31,17 @@ add_task(function* () {
   yield testComputedView(view, inspector.selection.nodeFront);
 
   yield testExpandedComputedViewProperty(view, inspector.selection.nodeFront);
 });
 
 function* testRuleView(ruleView, nodeFront) {
   info("Testing font-family tooltips in the rule view");
 
-  let tooltip = ruleView.tooltips.previewTooltip;
+  let tooltip = ruleView.tooltips.getTooltip("previewTooltip");
   let panel = tooltip.panel;
 
   // Check that the rule view has a tooltip and that a XUL panel has
   // been created
   ok(tooltip, "Tooltip instance exists");
   ok(panel, "XUL panel exists");
 
   // Get the font family property inside the rule view
@@ -59,17 +59,17 @@ function* testRuleView(ruleView, nodeFro
   let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
   is(images[0].getAttribute("src"), dataURL,
     "Tooltip contains the correct data-uri image");
 }
 
 function* testComputedView(computedView, nodeFront) {
   info("Testing font-family tooltips in the computed view");
 
-  let tooltip = computedView.tooltips.previewTooltip;
+  let tooltip = computedView.tooltips.getTooltip("previewTooltip");
   let panel = tooltip.panel;
   let {valueSpan} = getComputedViewProperty(computedView, "font-family");
 
   yield assertHoverTooltipOn(tooltip, valueSpan);
 
   let images = panel.getElementsByTagName("img");
   is(images.length, 1, "Tooltip contains an image");
   ok(images[0].getAttribute("src").startsWith("data:"),
@@ -87,17 +87,17 @@ function* testExpandedComputedViewProper
   info("Expanding the font-family property to reveal matched selectors");
   let propertyView = getPropertyView(computedView, "font-family");
   propertyView.matchedExpanded = true;
   yield propertyView.refreshMatchedSelectors();
 
   let valueSpan = propertyView.matchedSelectorsContainer
     .querySelector(".bestmatch .other-property-value");
 
-  let tooltip = computedView.tooltips.previewTooltip;
+  let tooltip = computedView.tooltips.getTooltip("previewTooltip");
   let panel = tooltip.panel;
 
   yield assertHoverTooltipOn(tooltip, valueSpan);
 
   let images = panel.getElementsByTagName("img");
   is(images.length, 1, "Tooltip contains an image");
   ok(images[0].getAttribute("src").startsWith("data:"),
     "Tooltip contains a data-uri image as expected");
--- a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-multiple-background-images.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-multiple-background-images.js
@@ -46,18 +46,18 @@ function* testComputedViewUrls(inspector
 function* performChecks(view, propertyValue) {
   function checkTooltip(panel, imageSrc) {
     let images = panel.getElementsByTagName("img");
     is(images.length, 1, "Tooltip contains an image");
     is(images[0].getAttribute("src"), imageSrc, "The image URL is correct");
   }
 
   let links = propertyValue.querySelectorAll(".theme-link");
-  let panel = view.tooltips.previewTooltip.panel;
+  let panel = view.tooltips.getTooltip("previewTooltip").panel;
 
   info("Checking first link tooltip");
-  yield assertHoverTooltipOn(view.tooltips.previewTooltip, links[0]);
+  yield assertHoverTooltipOn(view.tooltips.getTooltip("previewTooltip"), links[0]);
   checkTooltip(panel, YELLOW_DOT);
 
   info("Checking second link tooltip");
-  yield assertHoverTooltipOn(view.tooltips.previewTooltip, links[1]);
+  yield assertHoverTooltipOn(view.tooltips.getTooltip("previewTooltip"), links[1]);
   checkTooltip(panel, BLUE_DOT);
 }
--- a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-shorthand-fontfamily.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-shorthand-fontfamily.js
@@ -21,17 +21,17 @@ add_task(function* () {
 
   yield selectNode("#testElement", inspector);
   yield testRuleView(view, inspector.selection.nodeFront);
 });
 
 function* testRuleView(ruleView, nodeFront) {
   info("Testing font-family tooltips in the rule view");
 
-  let tooltip = ruleView.tooltips.previewTooltip;
+  let tooltip = ruleView.tooltips.getTooltip("previewTooltip");
   let panel = tooltip.panel;
 
   // Check that the rule view has a tooltip and that a XUL panel has
   // been created
   ok(tooltip, "Tooltip instance exists");
   ok(panel, "XUL panel exists");
 
   // Get the computed font family property inside the font rule view
--- a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-size.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-size.js
@@ -23,17 +23,17 @@ add_task(function* () {
   yield selectNode("div", inspector);
   yield testImageDimension(view);
   yield testPickerDimension(view);
 });
 
 function* testImageDimension(ruleView) {
   info("Testing background-image tooltip dimensions");
 
-  let tooltip = ruleView.tooltips.previewTooltip;
+  let tooltip = ruleView.tooltips.getTooltip("previewTooltip");
   let panel = tooltip.panel;
   let {valueSpan} = getRuleViewProperty(ruleView, "div", "background");
   let uriSpan = valueSpan.querySelector(".theme-link");
 
   // Make sure there is a hover tooltip for this property, this also will fill
   // the tooltip with its content
   yield assertHoverTooltipOn(tooltip, uriSpan);
 
@@ -57,17 +57,17 @@ function* testImageDimension(ruleView) {
   yield onHidden;
 }
 
 function* testPickerDimension(ruleView) {
   info("Testing color-picker tooltip dimensions");
 
   let {valueSpan} = getRuleViewProperty(ruleView, "div", "background");
   let swatch = valueSpan.querySelector(".ruleview-colorswatch");
-  let cPicker = ruleView.tooltips.colorPicker;
+  let cPicker = ruleView.tooltips.getTooltip("colorPicker");
 
   let onReady = cPicker.once("ready");
   swatch.click();
   yield onReady;
 
   // The colorpicker spectrum's iframe has a fixed width height, so let's
   // make sure the tooltip is at least as big as that
   let spectrumRect = cPicker.spectrum.element.getBoundingClientRect();
--- a/devtools/client/inspector/shared/tooltips-overlay.js
+++ b/devtools/client/inspector/shared/tooltips-overlay.js
@@ -13,125 +13,147 @@
 
 const { Task } = require("devtools/shared/task");
 const Services = require("Services");
 const {
   VIEW_NODE_VALUE_TYPE,
   VIEW_NODE_IMAGE_URL_TYPE,
 } = require("devtools/client/inspector/shared/node-types");
 const { getColor } = require("devtools/client/shared/theme");
-const { getCssProperties } = require("devtools/shared/fronts/css-properties");
-const CssDocsTooltip = require("devtools/client/shared/widgets/tooltip/CssDocsTooltip");
 const { HTMLTooltip } = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
-const {
-  getImageDimensions,
-  setImageTooltip,
-  setBrokenImageTooltip,
-} = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
-const SwatchColorPickerTooltip = require("devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip");
-const SwatchCubicBezierTooltip = require("devtools/client/shared/widgets/tooltip/SwatchCubicBezierTooltip");
-const SwatchFilterTooltip = require("devtools/client/shared/widgets/tooltip/SwatchFilterTooltip");
+
+loader.lazyRequireGetter(this, "getCssProperties",
+  "devtools/shared/fronts/css-properties", true);
+
+loader.lazyRequireGetter(this, "getImageDimensions",
+  "devtools/client/shared/widgets/tooltip/ImageTooltipHelper", true);
+loader.lazyRequireGetter(this, "setImageTooltip",
+  "devtools/client/shared/widgets/tooltip/ImageTooltipHelper", true);
+loader.lazyRequireGetter(this, "setBrokenImageTooltip",
+  "devtools/client/shared/widgets/tooltip/ImageTooltipHelper", true);
 
 const PREF_IMAGE_TOOLTIP_SIZE = "devtools.inspector.imagePreviewTooltipSize";
 
 // Types of existing tooltips
 const TOOLTIP_IMAGE_TYPE = "image";
 const TOOLTIP_FONTFAMILY_TYPE = "font-family";
 
 /**
  * Manages all tooltips in the style-inspector.
  *
  * @param {CssRuleView|CssComputedView} view
  *        Either the rule-view or computed-view panel
  */
 function TooltipsOverlay(view) {
   this.view = view;
-
-  let {CssRuleView} = require("devtools/client/inspector/rules/rules");
-  this.isRuleView = view instanceof CssRuleView;
-  this._cssProperties = getCssProperties(this.view.inspector.toolbox);
+  this._instances = new Map();
 
   this._onNewSelection = this._onNewSelection.bind(this);
   this.view.inspector.selection.on("new-node-front", this._onNewSelection);
+
+  this.addToView();
 }
 
 TooltipsOverlay.prototype = {
+  get _cssProperties() {
+    delete TooltipsOverlay.prototype._cssProperties;
+    let properties = getCssProperties(this.view.inspector.toolbox);
+    TooltipsOverlay.prototype._cssProperties = properties;
+    return properties;
+  },
+
   get isEditing() {
-    return this.colorPicker.tooltip.isVisible() ||
-           this.colorPicker.eyedropperOpen ||
-           this.cubicBezier.tooltip.isVisible() ||
-           this.filterEditor.tooltip.isVisible();
+    for (let [, tooltip] of this._instances) {
+      if (typeof (tooltip.isEditing) == "function" && tooltip.isEditing()) {
+        return true;
+      }
+    }
+    return false;
   },
 
   /**
    * Add the tooltips overlay to the view. This will start tracking mouse
    * movements and display tooltips when needed
    */
   addToView: function () {
     if (this._isStarted || this._isDestroyed) {
       return;
     }
 
-    let { toolbox } = this.view.inspector;
+    this._isStarted = true;
 
-    // Initializing the different tooltips that are used in the inspector.
-    // These tooltips are attached to the toolbox document if they require a popup panel.
-    // Otherwise, it is attached to the inspector panel document if it is an inline
-    // editor.
-    this.previewTooltip = new HTMLTooltip(toolbox.doc, {
-      type: "arrow",
-      useXulWrapper: true
-    });
-    this.previewTooltip.startTogglingOnHover(this.view.element,
-      this._onPreviewTooltipTargetHover.bind(this));
+    // For now, preview tooltip has to be instanciated on startup in order to
+    // call tooltip.startTogglingOnHover. Ideally startTogglingOnHover wouldn't be part
+    // of HTMLTooltip and offer a way to lazy load this tooltip.
+    this.getTooltip("previewTooltip");
+  },
 
-    // MDN CSS help tooltip
-    this.cssDocs = new CssDocsTooltip(toolbox.doc);
-
-    if (this.isRuleView) {
-      // Color picker tooltip
-      this.colorPicker = new SwatchColorPickerTooltip(toolbox.doc,
-                                                      this.view.inspector,
-                                                      this._cssProperties);
-      // Cubic bezier tooltip
-      this.cubicBezier = new SwatchCubicBezierTooltip(toolbox.doc);
-      // Filter editor tooltip
-      this.filterEditor = new SwatchFilterTooltip(toolbox.doc,
-        this._cssProperties.getValidityChecker(this.view.inspector.panelDoc));
+  /**
+   * Lazily fetch and initialize the different tooltips that are used in the inspector.
+   * These tooltips are attached to the toolbox document if they require a popup panel.
+   * Otherwise, it is attached to the inspector panel document if it is an inline editor.
+   *
+   * @param {String} name
+   *        Identifier name for the tooltip
+   */
+  getTooltip: function (name) {
+    let tooltip = this._instances.get(name);
+    if (tooltip) {
+      return tooltip;
     }
-
-    this._isStarted = true;
+    let { doc } = this.view.inspector.toolbox;
+    switch (name) {
+      case "colorPicker":
+        const SwatchColorPickerTooltip =
+          require("devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip");
+        tooltip = new SwatchColorPickerTooltip(doc, this.view.inspector,
+          this._cssProperties);
+        break;
+      case "cubicBezier":
+        const SwatchCubicBezierTooltip =
+          require("devtools/client/shared/widgets/tooltip/SwatchCubicBezierTooltip");
+        tooltip = new SwatchCubicBezierTooltip(doc);
+        break;
+      case "filterEditor":
+        const SwatchFilterTooltip =
+          require("devtools/client/shared/widgets/tooltip/SwatchFilterTooltip");
+        tooltip = new SwatchFilterTooltip(doc,
+          this._cssProperties.getValidityChecker(this.view.inspector.panelDoc));
+        break;
+      case "cssDocs":
+        const CssDocsTooltip =
+          require("devtools/client/shared/widgets/tooltip/CssDocsTooltip");
+        tooltip = new CssDocsTooltip(doc);
+        break;
+      case "previewTooltip":
+        tooltip = new HTMLTooltip(doc, {
+          type: "arrow",
+          useXulWrapper: true
+        });
+        tooltip.startTogglingOnHover(this.view.element,
+          this._onPreviewTooltipTargetHover.bind(this));
+        break;
+      default:
+        throw new Error(`Unsupported tooltip '${name}'`);
+    }
+    this._instances.set(name, tooltip);
+    return tooltip;
   },
 
   /**
    * Remove the tooltips overlay from the view. This will stop tracking mouse
    * movements and displaying tooltips
    */
   removeFromView: function () {
     if (!this._isStarted || this._isDestroyed) {
       return;
     }
 
-    this.previewTooltip.stopTogglingOnHover(this.view.element);
-    this.previewTooltip.destroy();
-
-    if (this.colorPicker) {
-      this.colorPicker.destroy();
-    }
-
-    if (this.cubicBezier) {
-      this.cubicBezier.destroy();
-    }
-
-    if (this.cssDocs) {
-      this.cssDocs.destroy();
-    }
-
-    if (this.filterEditor) {
-      this.filterEditor.destroy();
+    for (let [, tooltip] of this._instances) {
+      tooltip.destroy();
     }
 
     this._isStarted = false;
   },
 
   /**
    * Given a hovered node info, find out which type of tooltip should be shown,
    * if any
@@ -177,42 +199,31 @@ TooltipsOverlay.prototype = {
     }
 
     let type = this._getTooltipType(nodeInfo);
     if (!type) {
       // There is no tooltip type defined for the hovered node
       return false;
     }
 
-    if (this.isRuleView && this.colorPicker.tooltip.isVisible()) {
-      this.colorPicker.revert();
-      this.colorPicker.hide();
-    }
-
-    if (this.isRuleView && this.cubicBezier.tooltip.isVisible()) {
-      this.cubicBezier.revert();
-      this.cubicBezier.hide();
-    }
-
-    if (this.isRuleView && this.cssDocs.tooltip.isVisible()) {
-      this.cssDocs.hide();
-    }
-
-    if (this.isRuleView && this.filterEditor.tooltip.isVisible()) {
-      this.filterEditor.revert();
-      this.filterEdtior.hide();
+    for (let [, tooltip] of this._instances) {
+      if (tooltip.isVisible()) {
+        tooltip.revert();
+        tooltip.hide();
+      }
     }
 
     let inspector = this.view.inspector;
 
     if (type === TOOLTIP_IMAGE_TYPE) {
       try {
         yield this._setImagePreviewTooltip(nodeInfo.value.url);
       } catch (e) {
-        yield setBrokenImageTooltip(this.previewTooltip, this.view.inspector.panelDoc);
+        yield setBrokenImageTooltip(this.getTooltip("previewTooltip"),
+          this.view.inspector.panelDoc);
       }
       return true;
     }
 
     if (type === TOOLTIP_FONTFAMILY_TYPE) {
       let font = nodeInfo.value.value;
       let nodeFront = inspector.selection.nodeFront;
       yield this._setFontPreviewTooltip(font, nodeFront);
@@ -244,17 +255,17 @@ TooltipsOverlay.prototype = {
     } else {
       let inspectorFront = this.view.inspector.inspector;
       let {data, size} = yield inspectorFront.getImageDataFromURL(imageUrl, maxDim);
       imageUrl = yield data.string();
       naturalWidth = size.naturalWidth;
       naturalHeight = size.naturalHeight;
     }
 
-    yield setImageTooltip(this.previewTooltip, doc, imageUrl,
+    yield setImageTooltip(this.getTooltip("previewTooltip"), doc, imageUrl,
       {maxDim, naturalWidth, naturalHeight});
   }),
 
   /**
    * Set the content of the preview tooltip to display a font family preview.
    *
    * @param {String} font
    *        The font family value.
@@ -274,40 +285,24 @@ TooltipsOverlay.prototype = {
 
     let fillStyle = getColor("body-color");
     let {data, size: maxDim} = yield nodeFront.getFontFamilyDataURL(font, fillStyle);
 
     let imageUrl = yield data.string();
     let doc = this.view.inspector.panelDoc;
     let {naturalWidth, naturalHeight} = yield getImageDimensions(doc, imageUrl);
 
-    yield setImageTooltip(this.previewTooltip, doc, imageUrl,
+    yield setImageTooltip(this.getTooltip("previewTooltip"), doc, imageUrl,
       {hideDimensionLabel: true, hideCheckeredBackground: true,
        maxDim, naturalWidth, naturalHeight});
   }),
 
   _onNewSelection: function () {
-    if (this.previewTooltip) {
-      this.previewTooltip.hide();
-    }
-
-    if (this.colorPicker) {
-      this.colorPicker.hide();
-    }
-
-    if (this.cubicBezier) {
-      this.cubicBezier.hide();
-    }
-
-    if (this.cssDocs) {
-      this.cssDocs.hide();
-    }
-
-    if (this.filterEditor) {
-      this.filterEditor.hide();
+    for (let [, tooltip] of this._instances) {
+      tooltip.hide();
     }
   },
 
   /**
    * Destroy this overlay instance, removing it from the view
    */
   destroy: function () {
     this.removeFromView();
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-xul.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-xul.js
@@ -21,17 +21,17 @@ add_task(function* () {
   yield selectNode("#scale", inspector);
 
   // Find the color swatch in the rule-view.
   let ruleView = inspector.getPanel("ruleview").view;
   let ruleViewDocument = ruleView.styleDocument;
   let swatchEl = ruleViewDocument.querySelector(".ruleview-colorswatch");
 
   info("Open the color picker");
-  let cPicker = ruleView.tooltips.colorPicker;
+  let cPicker = ruleView.tooltips.getTooltip("colorPicker");
   let onColorPickerReady = cPicker.once("ready");
   swatchEl.click();
   yield onColorPickerReady;
 
   button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
   ok(isDisabled(button), "The button is disabled in the color picker");
 
   info("Navigate to a HTML document");
@@ -45,17 +45,17 @@ add_task(function* () {
   // Find the color swatch in the rule-view.
   yield selectNode("h1", inspector);
 
   ruleView = inspector.getPanel("ruleview").view;
   ruleViewDocument = ruleView.styleDocument;
   swatchEl = ruleViewDocument.querySelector(".ruleview-colorswatch");
 
   info("Open the color picker in HTML document");
-  cPicker = ruleView.tooltips.colorPicker;
+  cPicker = ruleView.tooltips.getTooltip("colorPicker");
   onColorPickerReady = cPicker.once("ready");
   swatchEl.click();
   yield onColorPickerReady;
 
   button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
   ok(!isDisabled(button), "The button is enabled in the color picker");
 });
 
--- a/devtools/client/shared/widgets/tooltip/CssDocsTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/CssDocsTooltip.js
@@ -34,30 +34,41 @@ function CssDocsTooltip(toolboxDoc) {
   this.shortcuts = new KeyShortcuts({ window: this.tooltip.topWindow });
   this._onShortcut = this._onShortcut.bind(this);
 
   this.shortcuts.on("Escape", this._onShortcut);
 }
 
 CssDocsTooltip.prototype = {
   /**
+   * Reports if the tooltip is currently shown
+   *
+   * @return {Boolean} True if the tooltip is displayed.
+   */
+  isVisible: function () {
+    return this.tooltip.isVisible();
+  },
+
+  /**
    * Load CSS docs for the given property,
    * then display the tooltip.
    */
   show: function (anchor, propertyName) {
     this.tooltip.once("shown", () => {
       this.widget.loadCssDocs(propertyName);
     });
     this.tooltip.show(anchor);
   },
 
   hide: function () {
     this.tooltip.hide();
   },
 
+  revert: function () {},
+
   _onShortcut: function (shortcut, event) {
     if (!this.tooltip.isVisible()) {
       return;
     }
     event.stopPropagation();
     event.preventDefault();
     this.hide();
   },
--- a/devtools/client/shared/widgets/tooltip/HTMLTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/HTMLTooltip.js
@@ -478,16 +478,17 @@ HTMLTooltip.prototype = {
    * tooltip container from the document.
    */
   destroy: function () {
     this.hide();
     this.container.remove();
     if (this.xulPanelWrapper) {
       this.xulPanelWrapper.remove();
     }
+    this._toggle.destroy();
   },
 
   _createContainer: function () {
     let container = this.doc.createElementNS(XHTML_NS, "div");
     container.setAttribute("type", this.type);
     container.classList.add("tooltip-container");
 
     let html = '<div class="tooltip-filler"></div>';
--- a/devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip.js
@@ -76,16 +76,34 @@ function SwatchBasedEditorTooltip(docume
   // that was clicked
   this.activeSwatch = null;
 
   this._onSwatchClick = this._onSwatchClick.bind(this);
 }
 
 SwatchBasedEditorTooltip.prototype = {
   /**
+   * Reports if the tooltip is currently shown
+   *
+   * @return {Boolean} True if the tooltip is displayed.
+   */
+  isVisible: function () {
+    return this.tooltip.isVisible();
+  },
+
+  /**
+   * Reports if the tooltip is currently editing the targeted value
+   *
+   * @return {Boolean} True if the tooltip is editing.
+   */
+  isEditing: function () {
+    return this.isVisible();
+  },
+
+  /**
    * Show the editor tooltip for the currently active swatch.
    *
    * @return {Promise} a promise that resolves once the editor tooltip is displayed, or
    *         immediately if there is no currently active swatch.
    */
   show: function () {
     let tooltipAnchor = this.useInline ?
       this.activeSwatch.closest(`.${INLINE_TOOLTIP_CLASS}`) :
--- a/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
@@ -199,16 +199,24 @@ SwatchColorPickerTooltip.prototype = Her
   },
 
   _toDefaultType: function (color) {
     let colorObj = new colorUtils.CssColor(color);
     colorObj.setAuthoredUnitFromColor(this._originalColor, this.cssColor4);
     return colorObj.toString();
   },
 
+  /**
+   * Overriding the SwatchBasedEditorTooltip.isEditing function to consider the
+   * eyedropper.
+   */
+  isEditing: function () {
+    return this.tooltip.isVisible() || this.eyedropperOpen;
+  },
+
   destroy: function () {
     SwatchBasedEditorTooltip.prototype.destroy.call(this);
     this.inspector = null;
     this.currentSwatchColor = null;
     this.spectrum.off("changed", this._onSpectrumColorChange);
     this.spectrum.destroy();
   }
 });