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 300367 b6511016fd244575b9114c9f36382c1db402385d
parent 300366 4bacacb4d1cf8ea75b75a3bd9933fce249fc4d74
child 300368 bf0c04641d265583b386e8dab9d776e199f3c79e
push id19522
push usernfitzgerald@mozilla.com
push dateFri, 03 Jun 2016 17:45:42 +0000
treeherderfx-team@b6511016fd24 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersejpbruel
bugs1277707
milestone49.0a1
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;