forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			265 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 | 
						|
/* vim: set ts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
"use strict";
 | 
						|
 | 
						|
const {Cu} = require("chrome");
 | 
						|
 | 
						|
let {TiltVisualizer} = require("devtools/tilt/tilt-visualizer");
 | 
						|
let TiltGL = require("devtools/tilt/tilt-gl");
 | 
						|
let TiltUtils = require("devtools/tilt/tilt-utils");
 | 
						|
let EventEmitter = require("devtools/toolkit/event-emitter");
 | 
						|
let Telemetry = require("devtools/shared/telemetry");
 | 
						|
 | 
						|
Cu.import("resource://gre/modules/Services.jsm");
 | 
						|
 | 
						|
// Tilt notifications dispatched through the nsIObserverService.
 | 
						|
const TILT_NOTIFICATIONS = {
 | 
						|
  // Called early in the startup of a new tilt instance
 | 
						|
  STARTUP: "tilt-startup",
 | 
						|
 | 
						|
  // Fires when Tilt starts the initialization.
 | 
						|
  INITIALIZING: "tilt-initializing",
 | 
						|
 | 
						|
  // Fires immediately after initialization is complete.
 | 
						|
  // (when the canvas overlay is visible and the 3D mesh is completely created)
 | 
						|
  INITIALIZED: "tilt-initialized",
 | 
						|
 | 
						|
  // Fires immediately before the destruction is started.
 | 
						|
  DESTROYING: "tilt-destroying",
 | 
						|
 | 
						|
  // Fires immediately before the destruction is finished.
 | 
						|
  // (just before the canvas overlay is removed from its parent node)
 | 
						|
  BEFORE_DESTROYED: "tilt-before-destroyed",
 | 
						|
 | 
						|
  // Fires when Tilt is completely destroyed.
 | 
						|
  DESTROYED: "tilt-destroyed",
 | 
						|
 | 
						|
  // Fires when Tilt is shown (after a tab-switch).
 | 
						|
  SHOWN: "tilt-shown",
 | 
						|
 | 
						|
  // Fires when Tilt is hidden (after a tab-switch).
 | 
						|
  HIDDEN: "tilt-hidden",
 | 
						|
 | 
						|
  // Fires once Tilt highlights an element in the page.
 | 
						|
  HIGHLIGHTING: "tilt-highlighting",
 | 
						|
 | 
						|
  // Fires once Tilt stops highlighting any element.
 | 
						|
  UNHIGHLIGHTING: "tilt-unhighlighting",
 | 
						|
 | 
						|
  // Fires when a node is removed from the 3D mesh.
 | 
						|
  NODE_REMOVED: "tilt-node-removed"
 | 
						|
};
 | 
						|
 | 
						|
let TiltManager = {
 | 
						|
  _instances: new WeakMap(),
 | 
						|
  getTiltForBrowser: function(aChromeWindow)
 | 
						|
  {
 | 
						|
    if (this._instances.has(aChromeWindow)) {
 | 
						|
      return this._instances.get(aChromeWindow);
 | 
						|
    } else {
 | 
						|
      let tilt = new Tilt(aChromeWindow);
 | 
						|
      this._instances.set(aChromeWindow, tilt);
 | 
						|
      return tilt;
 | 
						|
    }
 | 
						|
  },
 | 
						|
}
 | 
						|
 | 
						|
exports.TiltManager = TiltManager;
 | 
						|
 | 
						|
/**
 | 
						|
 * Object managing instances of the visualizer.
 | 
						|
 *
 | 
						|
 * @param {Window} aWindow
 | 
						|
 *                 the chrome window used by each visualizer instance
 | 
						|
 */
 | 
						|
function Tilt(aWindow)
 | 
						|
{
 | 
						|
  /**
 | 
						|
   * Save a reference to the top-level window.
 | 
						|
   */
 | 
						|
  this.chromeWindow = aWindow;
 | 
						|
 | 
						|
  /**
 | 
						|
   * All the instances of TiltVisualizer.
 | 
						|
   */
 | 
						|
  this.visualizers = {};
 | 
						|
 | 
						|
  /**
 | 
						|
   * Shortcut for accessing notifications strings.
 | 
						|
   */
 | 
						|
  this.NOTIFICATIONS = TILT_NOTIFICATIONS;
 | 
						|
 | 
						|
  EventEmitter.decorate(this);
 | 
						|
 | 
						|
  this.setup();
 | 
						|
 | 
						|
  this._telemetry = new Telemetry();
 | 
						|
}
 | 
						|
 | 
						|
Tilt.prototype = {
 | 
						|
 | 
						|
  /**
 | 
						|
   * Initializes a visualizer for the current tab or closes it if already open.
 | 
						|
   */
 | 
						|
  toggle: function T_toggle()
 | 
						|
  {
 | 
						|
    let contentWindow = this.chromeWindow.gBrowser.selectedBrowser.contentWindow;
 | 
						|
    let id = this.currentWindowId;
 | 
						|
    let self = this;
 | 
						|
 | 
						|
    contentWindow.addEventListener("beforeunload", function onUnload() {
 | 
						|
      contentWindow.removeEventListener("beforeunload", onUnload, false);
 | 
						|
      self.destroy(id, true);
 | 
						|
    }, false);
 | 
						|
 | 
						|
    // if the visualizer for the current tab is already open, destroy it now
 | 
						|
    if (this.visualizers[id]) {
 | 
						|
      this.destroy(id, true);
 | 
						|
      this._telemetry.toolClosed("tilt");
 | 
						|
      return;
 | 
						|
    } else {
 | 
						|
      this._telemetry.toolOpened("tilt");
 | 
						|
    }
 | 
						|
 | 
						|
    // create a visualizer instance for the current tab
 | 
						|
    this.visualizers[id] = new TiltVisualizer({
 | 
						|
      chromeWindow: this.chromeWindow,
 | 
						|
      contentWindow: contentWindow,
 | 
						|
      parentNode: this.chromeWindow.gBrowser.selectedBrowser.parentNode,
 | 
						|
      notifications: this.NOTIFICATIONS,
 | 
						|
      tab: this.chromeWindow.gBrowser.selectedTab
 | 
						|
    });
 | 
						|
 | 
						|
    Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.STARTUP, null);
 | 
						|
    this.visualizers[id].init();
 | 
						|
 | 
						|
    // make sure the visualizer object was initialized properly
 | 
						|
    if (!this.visualizers[id].isInitialized()) {
 | 
						|
      this.destroy(id);
 | 
						|
      this.failureCallback && this.failureCallback();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    this.lastInstanceId = id;
 | 
						|
    // E10S: We should be using target here. See bug 1028234
 | 
						|
    this.emit("change", { tab: this.chromeWindow.gBrowser.selectedTab });
 | 
						|
    Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.INITIALIZING, null);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Starts destroying a specific instance of the visualizer.
 | 
						|
   *
 | 
						|
   * @param {String} aId
 | 
						|
   *                 the identifier of the instance in the visualizers array
 | 
						|
   * @param {Boolean} aAnimateFlag
 | 
						|
   *                  optional, set to true to display a destruction transition
 | 
						|
   */
 | 
						|
  destroy: function T_destroy(aId, aAnimateFlag)
 | 
						|
  {
 | 
						|
    // if the visualizer is destroyed or destroying, don't do anything
 | 
						|
    if (!this.visualizers[aId] || this._isDestroying) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    this._isDestroying = true;
 | 
						|
 | 
						|
    let controller = this.visualizers[aId].controller;
 | 
						|
    let presenter = this.visualizers[aId].presenter;
 | 
						|
 | 
						|
    let content = presenter.contentWindow;
 | 
						|
    let pageXOffset = content.pageXOffset * presenter.transforms.zoom;
 | 
						|
    let pageYOffset = content.pageYOffset * presenter.transforms.zoom;
 | 
						|
    TiltUtils.setDocumentZoom(this.chromeWindow, presenter.transforms.zoom);
 | 
						|
 | 
						|
    // if we're not doing any outro animation, just finish destruction directly
 | 
						|
    if (!aAnimateFlag) {
 | 
						|
      this._finish(aId);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // otherwise, trigger the outro animation and notify necessary observers
 | 
						|
    Services.obs.notifyObservers(content, TILT_NOTIFICATIONS.DESTROYING, null);
 | 
						|
 | 
						|
    controller.removeEventListeners();
 | 
						|
    controller.arcball.reset([-pageXOffset, -pageYOffset]);
 | 
						|
    presenter.executeDestruction(this._finish.bind(this, aId));
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Finishes detroying a specific instance of the visualizer.
 | 
						|
   *
 | 
						|
   * @param {String} aId
 | 
						|
   *                 the identifier of the instance in the visualizers array
 | 
						|
   */
 | 
						|
  _finish: function T__finish(aId)
 | 
						|
  {
 | 
						|
    let contentWindow = this.visualizers[aId].presenter.contentWindow;
 | 
						|
    this.visualizers[aId].removeOverlay();
 | 
						|
    this.visualizers[aId].cleanup();
 | 
						|
    this.visualizers[aId] = null;
 | 
						|
 | 
						|
    this._isDestroying = false;
 | 
						|
    this.chromeWindow.gBrowser.selectedBrowser.focus();
 | 
						|
    // E10S: We should be using target here. See bug 1028234
 | 
						|
    this.emit("change", { tab: this.chromeWindow.gBrowser.selectedTab });
 | 
						|
    Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.DESTROYED, null);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Handles the event fired when a tab is selected.
 | 
						|
   */
 | 
						|
  _onTabSelect: function T__onTabSelect()
 | 
						|
  {
 | 
						|
    if (this.visualizers[this.lastInstanceId]) {
 | 
						|
      let contentWindow = this.visualizers[this.lastInstanceId].presenter.contentWindow;
 | 
						|
      Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.HIDDEN, null);
 | 
						|
    }
 | 
						|
 | 
						|
    if (this.currentInstance) {
 | 
						|
      let contentWindow = this.currentInstance.presenter.contentWindow;
 | 
						|
      Services.obs.notifyObservers(contentWindow, TILT_NOTIFICATIONS.SHOWN, null);
 | 
						|
    }
 | 
						|
 | 
						|
    this.lastInstanceId = this.currentWindowId;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Add the browser event listeners to handle state changes.
 | 
						|
   */
 | 
						|
  setup: function T_setup()
 | 
						|
  {
 | 
						|
    // load the preferences from the devtools.tilt branch
 | 
						|
    TiltVisualizer.Prefs.load();
 | 
						|
 | 
						|
    this.chromeWindow.gBrowser.tabContainer.addEventListener(
 | 
						|
      "TabSelect", this._onTabSelect.bind(this), false);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns true if this tool is enabled.
 | 
						|
   */
 | 
						|
  get enabled()
 | 
						|
  {
 | 
						|
    return (TiltVisualizer.Prefs.enabled &&
 | 
						|
           (TiltGL.isWebGLForceEnabled() || TiltGL.isWebGLSupported()));
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the ID of the current window object to identify the visualizer.
 | 
						|
   */
 | 
						|
  get currentWindowId()
 | 
						|
  {
 | 
						|
    return TiltUtils.getWindowId(
 | 
						|
      this.chromeWindow.gBrowser.selectedBrowser.contentWindow);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the visualizer instance for the current tab.
 | 
						|
   */
 | 
						|
  get currentInstance()
 | 
						|
  {
 | 
						|
    return this.visualizers[this.currentWindowId];
 | 
						|
  },
 | 
						|
};
 |