browser/devtools/tilt/tilt.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6 "use strict";
michael@0 7
michael@0 8 const {Cu} = require("chrome");
michael@0 9
michael@0 10 let {TiltVisualizer} = require("devtools/tilt/tilt-visualizer");
michael@0 11 let TiltGL = require("devtools/tilt/tilt-gl");
michael@0 12 let TiltUtils = require("devtools/tilt/tilt-utils");
michael@0 13 let EventEmitter = require("devtools/toolkit/event-emitter");
michael@0 14 let Telemetry = require("devtools/shared/telemetry");
michael@0 15
michael@0 16 Cu.import("resource://gre/modules/Services.jsm");
michael@0 17
michael@0 18 // Tilt notifications dispatched through the nsIObserverService.
michael@0 19 const TILT_NOTIFICATIONS = {
michael@0 20 // Called early in the startup of a new tilt instance
michael@0 21 STARTUP: "tilt-startup",
michael@0 22
michael@0 23 // Fires when Tilt starts the initialization.
michael@0 24 INITIALIZING: "tilt-initializing",
michael@0 25
michael@0 26 // Fires immediately after initialization is complete.
michael@0 27 // (when the canvas overlay is visible and the 3D mesh is completely created)
michael@0 28 INITIALIZED: "tilt-initialized",
michael@0 29
michael@0 30 // Fires immediately before the destruction is started.
michael@0 31 DESTROYING: "tilt-destroying",
michael@0 32
michael@0 33 // Fires immediately before the destruction is finished.
michael@0 34 // (just before the canvas overlay is removed from its parent node)
michael@0 35 BEFORE_DESTROYED: "tilt-before-destroyed",
michael@0 36
michael@0 37 // Fires when Tilt is completely destroyed.
michael@0 38 DESTROYED: "tilt-destroyed",
michael@0 39
michael@0 40 // Fires when Tilt is shown (after a tab-switch).
michael@0 41 SHOWN: "tilt-shown",
michael@0 42
michael@0 43 // Fires when Tilt is hidden (after a tab-switch).
michael@0 44 HIDDEN: "tilt-hidden",
michael@0 45
michael@0 46 // Fires once Tilt highlights an element in the page.
michael@0 47 HIGHLIGHTING: "tilt-highlighting",
michael@0 48
michael@0 49 // Fires once Tilt stops highlighting any element.
michael@0 50 UNHIGHLIGHTING: "tilt-unhighlighting",
michael@0 51
michael@0 52 // Fires when a node is removed from the 3D mesh.
michael@0 53 NODE_REMOVED: "tilt-node-removed"
michael@0 54 };
michael@0 55
michael@0 56 let TiltManager = {
michael@0 57 _instances: new WeakMap(),
michael@0 58 getTiltForBrowser: function(aChromeWindow)
michael@0 59 {
michael@0 60 if (this._instances.has(aChromeWindow)) {
michael@0 61 return this._instances.get(aChromeWindow);
michael@0 62 } else {
michael@0 63 let tilt = new Tilt(aChromeWindow);
michael@0 64 this._instances.set(aChromeWindow, tilt);
michael@0 65 return tilt;
michael@0 66 }
michael@0 67 },
michael@0 68 }
michael@0 69
michael@0 70 exports.TiltManager = TiltManager;
michael@0 71
michael@0 72 /**
michael@0 73 * Object managing instances of the visualizer.
michael@0 74 *
michael@0 75 * @param {Window} aWindow
michael@0 76 * the chrome window used by each visualizer instance
michael@0 77 */
michael@0 78 function Tilt(aWindow)
michael@0 79 {
michael@0 80 /**
michael@0 81 * Save a reference to the top-level window.
michael@0 82 */
michael@0 83 this.chromeWindow = aWindow;
michael@0 84
michael@0 85 /**
michael@0 86 * All the instances of TiltVisualizer.
michael@0 87 */
michael@0 88 this.visualizers = {};
michael@0 89
michael@0 90 /**
michael@0 91 * Shortcut for accessing notifications strings.
michael@0 92 */
michael@0 93 this.NOTIFICATIONS = TILT_NOTIFICATIONS;
michael@0 94
michael@0 95 EventEmitter.decorate(this);
michael@0 96
michael@0 97 this.setup();
michael@0 98
michael@0 99 this._telemetry = new Telemetry();
michael@0 100 }
michael@0 101
michael@0 102 Tilt.prototype = {
michael@0 103
michael@0 104 /**
michael@0 105 * Initializes a visualizer for the current tab or closes it if already open.
michael@0 106 */
michael@0 107 toggle: function T_toggle()
michael@0 108 {
michael@0 109 let contentWindow = this.chromeWindow.gBrowser.selectedBrowser.contentWindow;
michael@0 110 let id = this.currentWindowId;
michael@0 111 let self = this;
michael@0 112
michael@0 113 contentWindow.addEventListener("beforeunload", function onUnload() {
michael@0 114 contentWindow.removeEventListener("beforeunload", onUnload, false);
michael@0 115 self.destroy(id, true);
michael@0 116 }, false);
michael@0 117
michael@0 118 // if the visualizer for the current tab is already open, destroy it now
michael@0 119 if (this.visualizers[id]) {
michael@0 120 this.destroy(id, true);
michael@0 121 this._telemetry.toolClosed("tilt");
michael@0 122 return;
michael@0 123 } else {
michael@0 124 this._telemetry.toolOpened("tilt");
michael@0 125 }
michael@0 126
michael@0 127 // create a visualizer instance for the current tab
michael@0 128 this.visualizers[id] = new TiltVisualizer({
michael@0 129 chromeWindow: this.chromeWindow,
michael@0 130 contentWindow: contentWindow,
michael@0 131 parentNode: this.chromeWindow.gBrowser.selectedBrowser.parentNode,
michael@0 132 notifications: this.NOTIFICATIONS,
michael@0 133 tab: this.chromeWindow.gBrowser.selectedTab
michael@0 134 });
michael@0 135
michael@0 136 Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.STARTUP, null);
michael@0 137 this.visualizers[id].init();
michael@0 138
michael@0 139 // make sure the visualizer object was initialized properly
michael@0 140 if (!this.visualizers[id].isInitialized()) {
michael@0 141 this.destroy(id);
michael@0 142 this.failureCallback && this.failureCallback();
michael@0 143 return;
michael@0 144 }
michael@0 145
michael@0 146 this.lastInstanceId = id;
michael@0 147 this.emit("change", this.chromeWindow.gBrowser.selectedTab);
michael@0 148 Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.INITIALIZING, null);
michael@0 149 },
michael@0 150
michael@0 151 /**
michael@0 152 * Starts destroying a specific instance of the visualizer.
michael@0 153 *
michael@0 154 * @param {String} aId
michael@0 155 * the identifier of the instance in the visualizers array
michael@0 156 * @param {Boolean} aAnimateFlag
michael@0 157 * optional, set to true to display a destruction transition
michael@0 158 */
michael@0 159 destroy: function T_destroy(aId, aAnimateFlag)
michael@0 160 {
michael@0 161 // if the visualizer is destroyed or destroying, don't do anything
michael@0 162 if (!this.visualizers[aId] || this._isDestroying) {
michael@0 163 return;
michael@0 164 }
michael@0 165 this._isDestroying = true;
michael@0 166
michael@0 167 let controller = this.visualizers[aId].controller;
michael@0 168 let presenter = this.visualizers[aId].presenter;
michael@0 169
michael@0 170 let content = presenter.contentWindow;
michael@0 171 let pageXOffset = content.pageXOffset * presenter.transforms.zoom;
michael@0 172 let pageYOffset = content.pageYOffset * presenter.transforms.zoom;
michael@0 173 TiltUtils.setDocumentZoom(this.chromeWindow, presenter.transforms.zoom);
michael@0 174
michael@0 175 // if we're not doing any outro animation, just finish destruction directly
michael@0 176 if (!aAnimateFlag) {
michael@0 177 this._finish(aId);
michael@0 178 return;
michael@0 179 }
michael@0 180
michael@0 181 // otherwise, trigger the outro animation and notify necessary observers
michael@0 182 Services.obs.notifyObservers(content, TILT_NOTIFICATIONS.DESTROYING, null);
michael@0 183
michael@0 184 controller.removeEventListeners();
michael@0 185 controller.arcball.reset([-pageXOffset, -pageYOffset]);
michael@0 186 presenter.executeDestruction(this._finish.bind(this, aId));
michael@0 187 },
michael@0 188
michael@0 189 /**
michael@0 190 * Finishes detroying a specific instance of the visualizer.
michael@0 191 *
michael@0 192 * @param {String} aId
michael@0 193 * the identifier of the instance in the visualizers array
michael@0 194 */
michael@0 195 _finish: function T__finish(aId)
michael@0 196 {
michael@0 197 let contentWindow = this.visualizers[aId].presenter.contentWindow;
michael@0 198 this.visualizers[aId].removeOverlay();
michael@0 199 this.visualizers[aId].cleanup();
michael@0 200 this.visualizers[aId] = null;
michael@0 201
michael@0 202 this._isDestroying = false;
michael@0 203 this.chromeWindow.gBrowser.selectedBrowser.focus();
michael@0 204 this.emit("change", this.chromeWindow.gBrowser.selectedTab);
michael@0 205 Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.DESTROYED, null);
michael@0 206 },
michael@0 207
michael@0 208 /**
michael@0 209 * Handles the event fired when a tab is selected.
michael@0 210 */
michael@0 211 _onTabSelect: function T__onTabSelect()
michael@0 212 {
michael@0 213 if (this.visualizers[this.lastInstanceId]) {
michael@0 214 let contentWindow = this.visualizers[this.lastInstanceId].presenter.contentWindow;
michael@0 215 Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.HIDDEN, null);
michael@0 216 }
michael@0 217
michael@0 218 if (this.currentInstance) {
michael@0 219 let contentWindow = this.currentInstance.presenter.contentWindow;
michael@0 220 Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.SHOWN, null);
michael@0 221 }
michael@0 222
michael@0 223 this.lastInstanceId = this.currentWindowId;
michael@0 224 },
michael@0 225
michael@0 226 /**
michael@0 227 * Add the browser event listeners to handle state changes.
michael@0 228 */
michael@0 229 setup: function T_setup()
michael@0 230 {
michael@0 231 // load the preferences from the devtools.tilt branch
michael@0 232 TiltVisualizer.Prefs.load();
michael@0 233
michael@0 234 this.chromeWindow.gBrowser.tabContainer.addEventListener(
michael@0 235 "TabSelect", this._onTabSelect.bind(this), false);
michael@0 236 },
michael@0 237
michael@0 238 /**
michael@0 239 * Returns true if this tool is enabled.
michael@0 240 */
michael@0 241 get enabled()
michael@0 242 {
michael@0 243 return (TiltVisualizer.Prefs.enabled &&
michael@0 244 (TiltGL.isWebGLForceEnabled() || TiltGL.isWebGLSupported()));
michael@0 245 },
michael@0 246
michael@0 247 /**
michael@0 248 * Gets the ID of the current window object to identify the visualizer.
michael@0 249 */
michael@0 250 get currentWindowId()
michael@0 251 {
michael@0 252 return TiltUtils.getWindowId(
michael@0 253 this.chromeWindow.gBrowser.selectedBrowser.contentWindow);
michael@0 254 },
michael@0 255
michael@0 256 /**
michael@0 257 * Gets the visualizer instance for the current tab.
michael@0 258 */
michael@0 259 get currentInstance()
michael@0 260 {
michael@0 261 return this.visualizers[this.currentWindowId];
michael@0 262 },
michael@0 263 };

mercurial