Bug 1277707 - Decouple the fronts from the actors in the shader editor; r=ejpbruel
authorNick Fitzgerald <fitzgen@gmail.com>
Fri, 03 Jun 2016 10:45:10 -0700
changeset 341374 b6511016fd244575b9114c9f36382c1db402385d
parent 341373 4bacacb4d1cf8ea75b75a3bd9933fce249fc4d74
child 341375 bf0c04641d265583b386e8dab9d776e199f3c79e
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersejpbruel
bugs1277707
milestone49.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 1277707 - Decouple the fronts from the actors in the shader editor; r=ejpbruel
devtools/client/framework/toolbox.js
devtools/client/shadereditor/panel.js
devtools/client/shadereditor/test/head.js
devtools/client/webide/modules/app-manager.js
devtools/server/actors/preference.js
devtools/server/actors/settings.js
devtools/server/actors/webgl.js
devtools/server/tests/mochitest/test_preference.html
devtools/server/tests/mochitest/test_settings.html
devtools/shared/fronts/moz.build
devtools/shared/fronts/preference.js
devtools/shared/fronts/settings.js
devtools/shared/fronts/webgl.js
devtools/shared/specs/moz.build
devtools/shared/specs/preference.js
devtools/shared/specs/settings.js
devtools/shared/specs/webgl.js
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -62,17 +62,17 @@ loader.lazyRequireGetter(this, "DevTools
   "devtools/shared/DevToolsUtils");
 loader.lazyRequireGetter(this, "showDoorhanger",
   "devtools/client/shared/doorhanger", true);
 loader.lazyRequireGetter(this, "createPerformanceFront",
   "devtools/server/actors/performance", true);
 loader.lazyRequireGetter(this, "system",
   "devtools/shared/system");
 loader.lazyRequireGetter(this, "getPreferenceFront",
-  "devtools/server/actors/preference", true);
+  "devtools/shared/fronts/preference", true);
 loader.lazyRequireGetter(this, "KeyShortcuts",
   "devtools/client/shared/key-shortcuts", true);
 loader.lazyRequireGetter(this, "ZoomKeys",
   "devtools/client/shared/zoom-keys");
 
 loader.lazyGetter(this, "osString", () => {
   return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
 });
--- a/devtools/client/shadereditor/panel.js
+++ b/devtools/client/shadereditor/panel.js
@@ -3,17 +3,17 @@
 /* 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 { Cc, Ci, Cu, Cr } = require("chrome");
 const promise = require("promise");
 const EventEmitter = require("devtools/shared/event-emitter");
-const { WebGLFront } = require("devtools/server/actors/webgl");
+const { WebGLFront } = require("devtools/shared/fronts/webgl");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 function ShaderEditorPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
   this._destroyer = null;
 
   EventEmitter.decorate(this);
--- a/devtools/client/shadereditor/test/head.js
+++ b/devtools/client/shadereditor/test/head.js
@@ -7,17 +7,17 @@ var { classes: Cc, interfaces: Ci, utils
 var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
 var { Task } = require("devtools/shared/task");
 
 var Services = require("Services");
 var promise = require("promise");
 var { gDevTools } = require("devtools/client/framework/devtools");
 var { DebuggerClient } = require("devtools/shared/client/main");
 var { DebuggerServer } = require("devtools/server/main");
-var { WebGLFront } = require("devtools/server/actors/webgl");
+var { WebGLFront } = require("devtools/shared/fronts/webgl");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var { TargetFactory } = require("devtools/client/framework/target");
 var { Toolbox } = require("devtools/client/framework/toolbox");
 var { isWebGLSupported } = require("devtools/client/shared/webgl-utils");
 var mm = null;
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js";
 const EXAMPLE_URL = "http://example.com/browser/devtools/client/shadereditor/test/";
--- a/devtools/client/webide/modules/app-manager.js
+++ b/devtools/client/webide/modules/app-manager.js
@@ -11,18 +11,18 @@ const {FileUtils} = Cu.import("resource:
 const EventEmitter = require("devtools/shared/event-emitter");
 const {TextEncoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
 const {AppProjects} = require("devtools/client/webide/modules/app-projects");
 const TabStore = require("devtools/client/webide/modules/tab-store");
 const {AppValidator} = require("devtools/client/webide/modules/app-validator");
 const {ConnectionManager, Connection} = require("devtools/shared/client/connection-manager");
 const {AppActorFront} = require("devtools/shared/apps/app-actor-front");
 const {getDeviceFront} = require("devtools/server/actors/device");
-const {getPreferenceFront} = require("devtools/server/actors/preference");
-const {getSettingsFront} = require("devtools/server/actors/settings");
+const {getPreferenceFront} = require("devtools/shared/fronts/preference");
+const {getSettingsFront} = require("devtools/shared/fronts/settings");
 const {Task} = require("devtools/shared/task");
 const {RuntimeScanners, RuntimeTypes} = require("devtools/client/webide/modules/runtimes");
 const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 const Telemetry = require("devtools/client/shared/telemetry");
 const {ProjectBuilding} = require("./build");
 
 const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties");
 
--- a/devtools/server/actors/preference.js
+++ b/devtools/server/actors/preference.js
@@ -1,49 +1,41 @@
 /* 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/. */
 
 const {Cc, Ci, Cu, CC} = require("chrome");
 const protocol = require("devtools/shared/protocol");
 const {Arg, method, RetVal} = protocol;
 const Services = require("Services");
+const {preferenceSpec} = require("devtools/shared/specs/preference");
 
 exports.register = function (handle) {
   handle.addGlobalActor(PreferenceActor, "preferenceActor");
 };
 
 exports.unregister = function (handle) {
 };
 
-var PreferenceActor = exports.PreferenceActor = protocol.ActorClass({
+var PreferenceActor = exports.PreferenceActor = protocol.ActorClassWithSpec(preferenceSpec, {
   typeName: "preference",
 
-  getBoolPref: method(function (name) {
+  getBoolPref: function (name) {
     return Services.prefs.getBoolPref(name);
-  }, {
-    request: { value: Arg(0) },
-    response: { value: RetVal("boolean") }
-  }),
+  },
 
-  getCharPref: method(function (name) {
+  getCharPref: function (name) {
     return Services.prefs.getCharPref(name);
-  }, {
-    request: { value: Arg(0) },
-    response: { value: RetVal("string") }
-  }),
+  },
 
-  getIntPref: method(function (name) {
+  getIntPref: function (name) {
     return Services.prefs.getIntPref(name);
-  }, {
-    request: { value: Arg(0) },
-    response: { value: RetVal("number") }
-  }),
+  },
 
-  getAllPrefs: method(function () {
+  getAllPrefs: function () {
     let prefs = {};
     Services.prefs.getChildList("").forEach(function (name, index) {
       // append all key/value pairs into a huge json object.
       try {
         let value;
         switch (Services.prefs.getPrefType(name)) {
           case Ci.nsIPrefBranch.PREF_STRING:
             value = Services.prefs.getCharPref(name);
@@ -60,69 +52,30 @@ var PreferenceActor = exports.Preference
           value: value,
           hasUserValue: Services.prefs.prefHasUserValue(name)
         };
       } catch (e) {
         // pref exists but has no user or default value
       }
     });
     return prefs;
-  }, {
-    request: {},
-    response: { value: RetVal("json") }
-  }),
+  },
 
-  setBoolPref: method(function (name, value) {
+  setBoolPref: function (name, value) {
     Services.prefs.setBoolPref(name, value);
     Services.prefs.savePrefFile(null);
-  }, {
-    request: { name: Arg(0), value: Arg(1) },
-    response: {}
-  }),
+  },
 
-  setCharPref: method(function (name, value) {
+  setCharPref: function (name, value) {
     Services.prefs.setCharPref(name, value);
     Services.prefs.savePrefFile(null);
-  }, {
-    request: { name: Arg(0), value: Arg(1) },
-    response: {}
-  }),
+  },
 
-  setIntPref: method(function (name, value) {
+  setIntPref: function (name, value) {
     Services.prefs.setIntPref(name, value);
     Services.prefs.savePrefFile(null);
-  }, {
-    request: { name: Arg(0), value: Arg(1) },
-    response: {}
-  }),
+  },
 
-  clearUserPref: method(function (name) {
+  clearUserPref: function (name) {
     Services.prefs.clearUserPref(name);
     Services.prefs.savePrefFile(null);
-  }, {
-    request: { name: Arg(0) },
-    response: {}
-  }),
-});
-
-var PreferenceFront = protocol.FrontClass(PreferenceActor, {
-  initialize: function (client, form) {
-    protocol.Front.prototype.initialize.call(this, client);
-    this.actorID = form.preferenceActor;
-    this.manage(this);
   },
 });
-
-const _knownPreferenceFronts = new WeakMap();
-
-exports.getPreferenceFront = function (client, form) {
-  if (!form.preferenceActor) {
-    return null;
-  }
-
-  if (_knownPreferenceFronts.has(client)) {
-    return _knownPreferenceFronts.get(client);
-  }
-
-  let front = new PreferenceFront(client, form);
-  _knownPreferenceFronts.set(client, front);
-  return front;
-};
--- a/devtools/server/actors/settings.js
+++ b/devtools/server/actors/settings.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cc, Ci, Cu, CC} = require("chrome");
 const protocol = require("devtools/shared/protocol");
 const {Arg, method, RetVal} = protocol;
 const {DebuggerServer} = require("devtools/server/main");
 const promise = require("promise");
 const Services = require("Services");
+const { settingsSpec } = require("devtools/shared/specs/settings");
 
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 
 var defaultSettings = {};
 var settingsFile;
 
 exports.register = function (handle) {
@@ -58,66 +59,58 @@ function loadSettingsFile() {
     }
   }
 
   if (settingsFile.exists()) {
     getDefaultSettings();
   }
 }
 
-var SettingsActor = exports.SettingsActor = protocol.ActorClass({
-  typeName: "settings",
-
+var SettingsActor = exports.SettingsActor = protocol.ActorClassWithSpec(settingsSpec, {
   _getSettingsService: function () {
     let win = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
     return win.navigator.mozSettings;
   },
 
-  getSetting: method(function (name) {
+  getSetting: function (name) {
     let deferred = promise.defer();
     let lock = this._getSettingsService().createLock();
     let req = lock.get(name);
     req.onsuccess = function () {
       deferred.resolve(req.result[name]);
     };
     req.onerror = function () {
       deferred.reject(req.error);
     };
     return deferred.promise;
-  }, {
-    request: { value: Arg(0) },
-    response: { value: RetVal("json") }
-  }),
+  },
 
-  setSetting: method(function (name, value) {
+  setSetting: function (name, value) {
     let deferred = promise.defer();
     let data = {};
     data[name] = value;
     let lock = this._getSettingsService().createLock();
     let req = lock.set(data);
     req.onsuccess = function () {
       deferred.resolve(true);
     };
     req.onerror = function () {
       deferred.reject(req.error);
     };
     return deferred.promise;
-  }, {
-    request: { name: Arg(0), value: Arg(1) },
-    response: {}
-  }),
+  },
 
   _hasUserSetting: function (name, value) {
     if (typeof value === "object") {
       return JSON.stringify(defaultSettings[name]) !== JSON.stringify(value);
     }
     return (defaultSettings[name] !== value);
   },
 
-  getAllSettings: method(function () {
+  getAllSettings: function () {
     loadSettingsFile();
     let settings = {};
     let self = this;
 
     let deferred = promise.defer();
     let lock = this._getSettingsService().createLock();
     let req = lock.get("*");
 
@@ -130,52 +123,24 @@ var SettingsActor = exports.SettingsActo
       }
       deferred.resolve(settings);
     };
     req.onfailure = function () {
       deferred.reject(req.error);
     };
 
     return deferred.promise;
-  }, {
-    request: {},
-    response: { value: RetVal("json") }
-  }),
+  },
 
-  clearUserSetting: method(function (name) {
+  clearUserSetting: function (name) {
     loadSettingsFile();
     try {
       this.setSetting(name, defaultSettings[name]);
     } catch (e) {
       console.log(e);
     }
-  }, {
-    request: { name: Arg(0) },
-    response: {}
-  })
-});
-
-var SettingsFront = protocol.FrontClass(SettingsActor, {
-  initialize: function (client, form) {
-    protocol.Front.prototype.initialize.call(this, client);
-    this.actorID = form.settingsActor;
-    this.manage(this);
-  },
+  }
 });
 
-const _knownSettingsFronts = new WeakMap();
-
-exports.getSettingsFront = function (client, form) {
-  if (!form.settingsActor) {
-    return null;
-  }
-  if (_knownSettingsFronts.has(client)) {
-    return _knownSettingsFronts.get(client);
-  }
-  let front = new SettingsFront(client, form);
-  _knownSettingsFronts.set(client, front);
-  return front;
-};
-
 // For tests
 exports._setDefaultSettings = function (settings) {
   defaultSettings = settings || {};
 };
--- a/devtools/server/actors/webgl.js
+++ b/devtools/server/actors/webgl.js
@@ -5,32 +5,35 @@
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 const events = require("sdk/event/core");
 const promise = require("promise");
 const protocol = require("devtools/shared/protocol");
 const { ContentObserver } = require("devtools/shared/content-observer");
 const { on, once, off, emit } = events;
 const { method, Arg, Option, RetVal } = protocol;
+const {
+  shaderSpec,
+  programSpec,
+  webGLSpec,
+} = require("devtools/shared/specs/webgl");
 
 const WEBGL_CONTEXT_NAMES = ["webgl", "experimental-webgl", "moz-webgl"];
 
 // These traits are bit masks. Make sure they're powers of 2.
 const PROGRAM_DEFAULT_TRAITS = 0;
 const PROGRAM_BLACKBOX_TRAIT = 1;
 const PROGRAM_HIGHLIGHT_TRAIT = 2;
 
 /**
  * A WebGL Shader contributing to building a WebGL Program.
  * You can either retrieve, or compile the source of a shader, which will
  * automatically inflict the necessary changes to the WebGL state.
  */
-var ShaderActor = protocol.ActorClass({
-  typeName: "gl-shader",
-
+var ShaderActor = protocol.ActorClassWithSpec(shaderSpec, {
   /**
    * Create the shader actor.
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param WebGLProgram program
    *        The WebGL program being linked.
    * @param WebGLShader shader
@@ -44,64 +47,48 @@ var ShaderActor = protocol.ActorClass({
     this.shader = shader;
     this.text = proxy.getShaderSource(shader);
     this.linkedProxy = proxy;
   },
 
   /**
    * Gets the source code for this shader.
    */
-  getText: method(function () {
+  getText: function () {
     return this.text;
-  }, {
-    response: { text: RetVal("string") }
-  }),
+  },
 
   /**
    * Sets and compiles new source code for this shader.
    */
-  compile: method(function (text) {
+  compile: function (text) {
     // Get the shader and corresponding program to change via the WebGL proxy.
     let { linkedProxy: proxy, shader, program } = this;
 
     // Get the new shader source to inject.
     let oldText = this.text;
     let newText = text;
 
     // Overwrite the shader's source.
     let error = proxy.compileShader(program, shader, this.text = newText);
 
     // If something went wrong, revert to the previous shader.
     if (error.compile || error.link) {
       proxy.compileShader(program, shader, this.text = oldText);
       return error;
     }
     return undefined;
-  }, {
-    request: { text: Arg(0, "string") },
-    response: { error: RetVal("nullable:json") }
-  })
-});
-
-/**
- * The corresponding Front object for the ShaderActor.
- */
-var ShaderFront = protocol.FrontClass(ShaderActor, {
-  initialize: function (client, form) {
-    protocol.Front.prototype.initialize.call(this, client, form);
   }
 });
 
 /**
  * A WebGL program is composed (at the moment, analogue to OpenGL ES 2.0)
  * of two shaders: a vertex shader and a fragment shader.
  */
-var ProgramActor = protocol.ActorClass({
-  typeName: "gl-program",
-
+var ProgramActor = protocol.ActorClassWithSpec(programSpec, {
   /**
    * Create the program actor.
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param WebGLProgram program
    *        The WebGL program being linked.
    * @param WebGLShader[] shaders
@@ -127,69 +114,56 @@ var ProgramActor = protocol.ActorClass({
   get ownerContext() {
     return this.linkedCache.ownerContext;
   },
 
   /**
    * Gets the vertex shader linked to this program. This method guarantees
    * a single actor instance per shader.
    */
-  getVertexShader: method(function () {
+  getVertexShader: function () {
     return this._getShaderActor("vertex");
-  }, {
-    response: { shader: RetVal("gl-shader") }
-  }),
+  },
 
   /**
    * Gets the fragment shader linked to this program. This method guarantees
    * a single actor instance per shader.
    */
-  getFragmentShader: method(function () {
+  getFragmentShader: function () {
     return this._getShaderActor("fragment");
-  }, {
-    response: { shader: RetVal("gl-shader") }
-  }),
+  },
 
   /**
    * Highlights any geometry rendered using this program.
    */
-  highlight: method(function (tint) {
+  highlight: function (tint) {
     this.linkedProxy.highlightTint = tint;
     this.linkedCache.setProgramTrait(this.program, PROGRAM_HIGHLIGHT_TRAIT);
-  }, {
-    request: { tint: Arg(0, "array:number") },
-    oneway: true
-  }),
+  },
 
   /**
    * Allows geometry to be rendered normally using this program.
    */
-  unhighlight: method(function () {
+  unhighlight: function () {
     this.linkedCache.unsetProgramTrait(this.program, PROGRAM_HIGHLIGHT_TRAIT);
-  }, {
-    oneway: true
-  }),
+  },
 
   /**
    * Prevents any geometry from being rendered using this program.
    */
-  blackbox: method(function () {
+  blackbox: function () {
     this.linkedCache.setProgramTrait(this.program, PROGRAM_BLACKBOX_TRAIT);
-  }, {
-    oneway: true
-  }),
+  },
 
   /**
    * Allows geometry to be rendered using this program.
    */
-  unblackbox: method(function () {
+  unblackbox: function () {
     this.linkedCache.unsetProgramTrait(this.program, PROGRAM_BLACKBOX_TRAIT);
-  }, {
-    oneway: true
-  }),
+  },
 
   /**
    * Returns a cached ShaderActor instance based on the required shader type.
    *
    * @param string type
    *        Either "vertex" or "fragment".
    * @return ShaderActor
    *         The respective shader actor instance.
@@ -201,31 +175,21 @@ var ProgramActor = protocol.ActorClass({
     let proxy = this.linkedProxy;
     let shader = proxy.getShaderOfType(this.shaders, type);
     let shaderActor = new ShaderActor(this.conn, this.program, shader, proxy);
     return this._shaderActorsCache[type] = shaderActor;
   }
 });
 
 /**
- * The corresponding Front object for the ProgramActor.
- */
-var ProgramFront = protocol.FrontClass(ProgramActor, {
-  initialize: function (client, form) {
-    protocol.Front.prototype.initialize.call(this, client, form);
-  }
-});
-
-/**
  * The WebGL Actor handles simple interaction with a WebGL context via a few
  * high-level methods. After instantiating this actor, you'll need to set it
  * up by calling setup().
  */
-var WebGLActor = exports.WebGLActor = protocol.ActorClass({
-  typeName: "webgl",
+var WebGLActor = exports.WebGLActor = protocol.ActorClassWithSpec(webGLSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._onGlobalCreated = this._onGlobalCreated.bind(this);
     this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
     this._onProgramLinked = this._onProgramLinked.bind(this);
   },
   destroy: function (conn) {
@@ -235,143 +199,107 @@ var WebGLActor = exports.WebGLActor = pr
 
   /**
    * Starts waiting for the current tab actor's document global to be
    * created, in order to instrument the Canvas context and become
    * aware of everything the content does WebGL-wise.
    *
    * See ContentObserver and WebGLInstrumenter for more details.
    */
-  setup: method(function ({ reload }) {
+  setup: function ({ reload }) {
     if (this._initialized) {
       return;
     }
     this._initialized = true;
 
     this._programActorsCache = [];
     this._webglObserver = new WebGLObserver();
 
     on(this.tabActor, "window-ready", this._onGlobalCreated);
     on(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
     on(this._webglObserver, "program-linked", this._onProgramLinked);
 
     if (reload) {
       this.tabActor.window.location.reload();
     }
-  }, {
-    request: { reload: Option(0, "boolean") },
-    oneway: true
-  }),
+  },
 
   /**
    * Stops listening for document global changes and puts this actor
    * to hibernation. This method is called automatically just before the
    * actor is destroyed.
    */
-  finalize: method(function () {
+  finalize: function () {
     if (!this._initialized) {
       return;
     }
     this._initialized = false;
 
     off(this.tabActor, "window-ready", this._onGlobalCreated);
     off(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
     off(this._webglObserver, "program-linked", this._onProgramLinked);
 
     this._programActorsCache = null;
     this._contentObserver = null;
     this._webglObserver = null;
-  }, {
-    oneway: true
-  }),
+  },
 
   /**
    * Gets an array of cached program actors for the current tab actor's window.
    * This is useful for dealing with bfcache, when no new programs are linked.
    */
-  getPrograms: method(function () {
+  getPrograms: function () {
     let id = ContentObserver.GetInnerWindowID(this.tabActor.window);
     return this._programActorsCache.filter(e => e.ownerWindow == id);
-  }, {
-    response: { programs: RetVal("array:gl-program") }
-  }),
+  },
 
   /**
    * Waits for one frame via `requestAnimationFrame` on the tab actor's window.
    * Used in tests.
    */
-  waitForFrame: method(function () {
+  waitForFrame: function () {
     let deferred = promise.defer();
     this.tabActor.window.requestAnimationFrame(deferred.resolve);
     return deferred.promise;
-  }, {
-    response: { success: RetVal("nullable:json") }
-  }),
+  },
 
   /**
    * Gets a pixel's RGBA value from a context specified by selector
    * and the coordinates of the pixel in question.
    * Currently only used in tests.
    *
    * @param string selector
    *        A string selector to select the canvas in question from the DOM.
    * @param Object position
    *        An object with an `x` and `y` property indicating coordinates of the pixel being inspected.
    * @return Object
    *        An object containing `r`, `g`, `b`, and `a` properties of the pixel.
    */
-  getPixel: method(function ({ selector, position }) {
+  getPixel: function ({ selector, position }) {
     let { x, y } = position;
     let canvas = this.tabActor.window.document.querySelector(selector);
     let context = XPCNativeWrapper.unwrap(canvas.getContext("webgl"));
     let { proxy } = this._webglObserver.for(context);
     let height = canvas.height;
 
     let buffer = new this.tabActor.window.Uint8Array(4);
     buffer = XPCNativeWrapper.unwrap(buffer);
 
     proxy.readPixels(x, height - y - 1, 1, 1, context.RGBA, context.UNSIGNED_BYTE, buffer);
 
     return { r: buffer[0], g: buffer[1], b: buffer[2], a: buffer[3] };
-  }, {
-    request: {
-      selector: Option(0, "string"),
-      position: Option(0, "json")
-    },
-    response: { pixels: RetVal("json") }
-  }),
-
-  /**
-   * Events emitted by this actor. The "program-linked" event is fired
-   * every time a WebGL program was linked with its respective two shaders.
-   */
-  events: {
-    "program-linked": {
-      type: "programLinked",
-      program: Arg(0, "gl-program")
-    },
-    "global-destroyed": {
-      type: "globalDestroyed",
-      program: Arg(0, "number")
-    },
-    "global-created": {
-      type: "globalCreated",
-      program: Arg(0, "number")
-    }
   },
 
   /**
    * Gets an array of all cached program actors belonging to all windows.
    * This should only be used for tests.
    */
-  _getAllPrograms: method(function () {
+  _getAllPrograms: function () {
     return this._programActorsCache;
-  }, {
-    response: { programs: RetVal("array:gl-program") }
-  }),
+  },
 
 
   /**
    * Invoked whenever the current tab actor's document global is created.
    */
   _onGlobalCreated: function ({id, window, isTopLevel}) {
     if (isTopLevel) {
       WebGLInstrumenter.handle(window, this._webglObserver);
@@ -396,26 +324,16 @@ var WebGLActor = exports.WebGLActor = pr
   _onProgramLinked: function (...args) {
     let programActor = new ProgramActor(this.conn, args);
     this._programActorsCache.push(programActor);
     events.emit(this, "program-linked", programActor);
   }
 });
 
 /**
- * The corresponding Front object for the WebGLActor.
- */
-var WebGLFront = exports.WebGLFront = protocol.FrontClass(WebGLActor, {
-  initialize: function (client, { webglActor }) {
-    protocol.Front.prototype.initialize.call(this, client, { actor: webglActor });
-    this.manage(this);
-  }
-});
-
-/**
  * Instruments a HTMLCanvasElement with the appropriate inspection methods.
  */
 var WebGLInstrumenter = {
   /**
    * Overrides the getContext method in the HTMLCanvasElement prototype.
    *
    * @param nsIDOMWindow window
    *        The window to perform the instrumentation in.
--- a/devtools/server/tests/mochitest/test_preference.html
+++ b/devtools/server/tests/mochitest/test_preference.html
@@ -20,17 +20,17 @@ function runTests() {
 
   var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
   var {DebuggerClient} = require("devtools/shared/client/main");
   var {DebuggerServer} = require("devtools/server/main");
   var Services = require("Services");
 
   SimpleTest.waitForExplicitFinish();
 
-  var {getPreferenceFront} = require("devtools/server/actors/preference");
+  var {getPreferenceFront} = require("devtools/shared/fronts/preference");
 
   DebuggerServer.init();
   DebuggerServer.addBrowserActors();
 
   var client = new DebuggerClient(DebuggerServer.connectPipe());
   client.connect().then(function onConnect() {
     client.listTabs(function onListTabs(aResponse) {
       var p = getPreferenceFront(client, aResponse);
--- a/devtools/server/tests/mochitest/test_settings.html
+++ b/devtools/server/tests/mochitest/test_settings.html
@@ -24,17 +24,18 @@ function runTests() {
   var {DebuggerServer} = require("devtools/server/main");
 
   if (SpecialPowers.isMainProcess()) {
     Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
   }
 
   SimpleTest.waitForExplicitFinish();
 
-  var {getSettingsFront, _setDefaultSettings} = require("devtools/server/actors/settings");
+  var {getSettingsFront} = require("devtools/shared/fronts/settings");
+  var {_setDefaultSettings} = require("devtools/server/actors/settings");
 
   DebuggerServer.init(function () { return true; });
   DebuggerServer.addBrowserActors();
 
   var client = new DebuggerClient(DebuggerServer.connectPipe());
   client.connect().then(function onConnect() {
     client.listTabs(function onListTabs(aResponse) {
       var s = getSettingsFront(client, aResponse);
--- a/devtools/shared/fronts/moz.build
+++ b/devtools/shared/fronts/moz.build
@@ -8,13 +8,16 @@ DevToolsModules(
     'actor-registry.js',
     'addons.js',
     'animation.js',
     'call-watcher.js',
     'canvas.js',
     'css-properties.js',
     'highlighters.js',
     'inspector.js',
+    'preference.js',
+    'settings.js',
     'storage.js',
     'styles.js',
     'stylesheets.js',
-    'webaudio.js'
+    'webaudio.js',
+    'webgl.js'
 )
new file mode 100644
--- /dev/null
+++ b/devtools/shared/fronts/preference.js
@@ -0,0 +1,31 @@
+/* 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 {preferenceSpec} = require("devtools/shared/specs/preference");
+const protocol = require("devtools/shared/protocol");
+
+const PreferenceFront = protocol.FrontClassWithSpec(preferenceSpec, {
+  initialize: function (client, form) {
+    protocol.Front.prototype.initialize.call(this, client);
+    this.actorID = form.preferenceActor;
+    this.manage(this);
+  },
+});
+
+const _knownPreferenceFronts = new WeakMap();
+
+exports.getPreferenceFront = function (client, form) {
+  if (!form.preferenceActor) {
+    return null;
+  }
+
+  if (_knownPreferenceFronts.has(client)) {
+    return _knownPreferenceFronts.get(client);
+  }
+
+  let front = new PreferenceFront(client, form);
+  _knownPreferenceFronts.set(client, front);
+  return front;
+};
new file mode 100644
--- /dev/null
+++ b/devtools/shared/fronts/settings.js
@@ -0,0 +1,29 @@
+/* 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 {settingsSpec} = require("devtools/shared/specs/settings");
+const protocol = require("devtools/shared/protocol");
+
+const SettingsFront = protocol.FrontClassWithSpec(settingsSpec, {
+  initialize: function (client, form) {
+    protocol.Front.prototype.initialize.call(this, client);
+    this.actorID = form.settingsActor;
+    this.manage(this);
+  },
+});
+
+const _knownSettingsFronts = new WeakMap();
+
+exports.getSettingsFront = function (client, form) {
+  if (!form.settingsActor) {
+    return null;
+  }
+  if (_knownSettingsFronts.has(client)) {
+    return _knownSettingsFronts.get(client);
+  }
+  let front = new SettingsFront(client, form);
+  _knownSettingsFronts.set(client, front);
+  return front;
+};
new file mode 100644
--- /dev/null
+++ b/devtools/shared/fronts/webgl.js
@@ -0,0 +1,45 @@
+/* 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 {
+  shaderSpec,
+  programSpec,
+  webGLSpec,
+} = require("devtools/shared/specs/webgl");
+const protocol = require("devtools/shared/protocol");
+
+/**
+ * The corresponding Front object for the ShaderActor.
+ */
+const ShaderFront = protocol.FrontClassWithSpec(shaderSpec, {
+  initialize: function (client, form) {
+    protocol.Front.prototype.initialize.call(this, client, form);
+  }
+});
+
+exports.ShaderFront = ShaderFront;
+
+/**
+ * The corresponding Front object for the ProgramActor.
+ */
+const ProgramFront = protocol.FrontClassWithSpec(programSpec, {
+  initialize: function (client, form) {
+    protocol.Front.prototype.initialize.call(this, client, form);
+  }
+});
+
+exports.ProgramFront = ProgramFront;
+
+/**
+ * The corresponding Front object for the WebGLActor.
+ */
+const WebGLFront = protocol.FrontClassWithSpec(webGLSpec, {
+  initialize: function (client, { webglActor }) {
+    protocol.Front.prototype.initialize.call(this, client, { actor: webglActor });
+    this.manage(this);
+  }
+});
+
+exports.WebGLFront = WebGLFront;
--- a/devtools/shared/specs/moz.build
+++ b/devtools/shared/specs/moz.build
@@ -9,15 +9,24 @@ DevToolsModules(
     'addons.js',
     'animation.js',
     'call-watcher.js',
     'canvas.js',
     'css-properties.js',
     'heap-snapshot-file.js',
     'highlighters.js',
     'inspector.js',
+<<<<<<< HEAD
+<<<<<<< HEAD
     'node.js',
+=======
+=======
+    'preference.js',
+>>>>>>> 2b386d5... Bug 1277717 - Decouple the PreferenceFront from the PreferenceActor; r=ejpbruel
+    'settings.js',
+>>>>>>> e4a75c4... Bug 1277715 - Decouple the SettingsFront from the SettingsActor; r=ejpbruel
     'storage.js',
     'styleeditor.js',
     'styles.js',
     'stylesheets.js',
-    'webaudio.js'
+    'webaudio.js',
+    'webgl.js'
 )
new file mode 100644
--- /dev/null
+++ b/devtools/shared/specs/preference.js
@@ -0,0 +1,47 @@
+/* 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 {Arg, RetVal, generateActorSpec} = require("devtools/shared/protocol");
+
+const preferenceSpec = generateActorSpec({
+  typeName: "preference",
+
+  methods: {
+    getBoolPref: {
+      request: { value: Arg(0) },
+      response: { value: RetVal("boolean") }
+    },
+    getCharPref: {
+      request: { value: Arg(0) },
+      response: { value: RetVal("string") }
+    },
+    getIntPref: {
+      request: { value: Arg(0) },
+      response: { value: RetVal("number") }
+    },
+    getAllPrefs: {
+      request: {},
+      response: { value: RetVal("json") }
+    },
+    setBoolPref: {
+      request: { name: Arg(0), value: Arg(1) },
+      response: {}
+    },
+    setCharPref: {
+      request: { name: Arg(0), value: Arg(1) },
+      response: {}
+    },
+    setIntPref: {
+      request: { name: Arg(0), value: Arg(1) },
+      response: {}
+    },
+    clearUserPref: {
+      request: { name: Arg(0) },
+      response: {}
+    }
+  },
+});
+
+exports.preferenceSpec = preferenceSpec;
new file mode 100644
--- /dev/null
+++ b/devtools/shared/specs/settings.js
@@ -0,0 +1,31 @@
+/* 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 {Arg, RetVal, generateActorSpec} = require("devtools/shared/protocol");
+
+const settingsSpec = generateActorSpec({
+  typeName: "settings",
+
+  methods: {
+    getSetting: {
+      request: { value: Arg(0) },
+      response: { value: RetVal("json") }
+    },
+    setSetting: {
+      request: { name: Arg(0), value: Arg(1) },
+      response: {}
+    },
+    getAllSettings: {
+      request: {},
+      response: { value: RetVal("json") }
+    },
+    clearUserSetting: {
+      request: { name: Arg(0) },
+      response: {}
+    }
+  },
+});
+
+exports.settingsSpec = settingsSpec;
new file mode 100644
--- /dev/null
+++ b/devtools/shared/specs/webgl.js
@@ -0,0 +1,101 @@
+/* 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 {Arg, Option, RetVal, generateActorSpec} = require("devtools/shared/protocol");
+
+const shaderSpec = generateActorSpec({
+  typeName: "gl-shader",
+
+  methods: {
+    getText: {
+      response: { text: RetVal("string") }
+    },
+    compile: {
+      request: { text: Arg(0, "string") },
+      response: { error: RetVal("nullable:json") }
+    },
+  },
+});
+
+exports.shaderSpec = shaderSpec;
+
+const programSpec = generateActorSpec({
+  typeName: "gl-program",
+
+  methods: {
+    getVertexShader: {
+      response: { shader: RetVal("gl-shader") }
+    },
+    getFragmentShader: {
+      response: { shader: RetVal("gl-shader") }
+    },
+    highlight: {
+      request: { tint: Arg(0, "array:number") },
+      oneway: true
+    },
+    unhighlight: {
+      oneway: true
+    },
+    blackbox: {
+      oneway: true
+    },
+    unblackbox: {
+      oneway: true
+    },
+  }
+});
+
+exports.programSpec = programSpec;
+
+const webGLSpec = generateActorSpec({
+  typeName: "webgl",
+
+  /**
+   * Events emitted by this actor. The "program-linked" event is fired every
+   * time a WebGL program was linked with its respective two shaders.
+   */
+  events: {
+    "program-linked": {
+      type: "programLinked",
+      program: Arg(0, "gl-program")
+    },
+    "global-destroyed": {
+      type: "globalDestroyed",
+      program: Arg(0, "number")
+    },
+    "global-created": {
+      type: "globalCreated",
+      program: Arg(0, "number")
+    }
+  },
+
+  methods: {
+    setup: {
+      request: { reload: Option(0, "boolean") },
+      oneway: true
+    },
+    finalize: {
+      oneway: true
+    },
+    getPrograms: {
+      response: { programs: RetVal("array:gl-program") }
+    },
+    waitForFrame: {
+      response: { success: RetVal("nullable:json") }
+    },
+    getPixel: {
+      request: {
+        selector: Option(0, "string"),
+        position: Option(0, "json")
+      },
+      response: { pixels: RetVal("json") }
+    },
+    _getAllPrograms: {
+      response: { programs: RetVal("array:gl-program") }
+    }
+  }
+});
+
+exports.webGLSpec = webGLSpec;