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