Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 26 Jul 2012 18:19:02 -0700
changeset 102416 31f9c38e4cb9719649d9b974c00fe232e3bbb71e
parent 102231 02f44534f7f55b9115924d8eeeedb66e899ef5ce (current diff)
parent 102415 f528e021ceb1daff2d854d9c460e907d4397b0d4 (diff)
child 102417 1274d6819bae7c97d22a872ac8092d8c51c80b01
push id18
push usershu@rfrn.org
push dateMon, 06 Aug 2012 22:42:45 +0000
milestone17.0a1
Merge from mozilla-central.
accessible/src/base/AccEvent.h
accessible/src/base/Makefile.in
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessibilityService.h
accessible/src/generic/Accessible.cpp
accessible/src/generic/DocAccessible.cpp
accessible/src/generic/DocAccessible.h
accessible/src/generic/HyperTextAccessible.h
accessible/src/generic/RootAccessible.cpp
accessible/src/html/HTMLFormControlAccessible.cpp
accessible/src/mac/AccessibleWrap.h
accessible/src/mac/AccessibleWrap.mm
accessible/src/msaa/DocAccessibleWrap.cpp
accessible/src/xul/XULTreeAccessible.cpp
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
configure.in
content/base/public/nsIContent.h
content/base/public/nsINode.h
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/base/src/nsXMLHttpRequest.cpp
content/base/test/test_XHR.html
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
content/canvas/test/test_canvas.html
content/events/src/nsDOMApplicationEvent.cpp
content/events/src/nsDOMApplicationEvent.h
content/events/src/nsDOMDeviceLightEvent.cpp
content/events/src/nsDOMDeviceLightEvent.h
content/events/src/nsDOMDeviceOrientationEvent.cpp
content/events/src/nsDOMDeviceOrientationEvent.h
content/html/content/src/nsHTMLObjectElement.cpp
content/html/content/src/nsHTMLSharedObjectElement.cpp
content/html/document/src/PluginDocument.cpp
content/media/MediaResource.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginStreamListenerPeer.cpp
dom/plugins/ipc/PluginInstanceParent.cpp
dom/workers/XMLHttpRequest.cpp
extensions/auth/nsAuthGSSAPI.cpp
extensions/auth/nsAuthSASL.cpp
extensions/auth/nsAuthSSPI.cpp
extensions/auth/nsAuthSambaNTLM.cpp
gfx/angle/Makefile.in
gfx/angle/README.mozilla
gfx/angle/angle-castrate-bug-241.patch
gfx/angle/angle-intrinsic-msvc2005.patch
gfx/angle/angle-renaming-debug.patch
gfx/angle/angle-use-xmalloc.patch
gfx/angle/samples/translator/translator.cpp
gfx/angle/src/common/version.h
gfx/angle/src/compiler/Compiler.cpp
gfx/angle/src/compiler/MapLongVariableNames.cpp
gfx/angle/src/compiler/OutputGLSLBase.cpp
gfx/angle/src/compiler/OutputHLSL.cpp
gfx/angle/src/compiler/OutputHLSL.h
gfx/angle/src/compiler/ParseHelper.cpp
gfx/angle/src/compiler/ShHandle.h
gfx/angle/src/compiler/UnfoldSelect.cpp
gfx/angle/src/compiler/UnfoldSelect.h
gfx/angle/src/compiler/intermediate.h
gfx/angle/src/compiler/osinclude.h
gfx/angle/src/compiler/preprocessor/lexer_glue.cpp
gfx/angle/src/compiler/preprocessor/lexer_glue.h
gfx/angle/src/compiler/preprocessor/new/Context.cpp
gfx/angle/src/compiler/preprocessor/new/Context.h
gfx/angle/src/compiler/preprocessor/new/Macro.h
gfx/angle/src/compiler/preprocessor/new/Preprocessor.cpp
gfx/angle/src/compiler/preprocessor/new/Preprocessor.h
gfx/angle/src/compiler/preprocessor/new/Token.cpp
gfx/angle/src/compiler/preprocessor/new/Token.h
gfx/angle/src/compiler/preprocessor/new/pp.l
gfx/angle/src/compiler/preprocessor/new/pp.y
gfx/angle/src/compiler/preprocessor/new/pp_lex.cpp
gfx/angle/src/compiler/preprocessor/new/pp_tab.h
gfx/angle/src/compiler/preprocessor/new/token_type.h
gfx/angle/src/libEGL/Display.cpp
gfx/angle/src/libEGL/Display.h
gfx/angle/src/libEGL/Makefile.in
gfx/angle/src/libEGL/Surface.cpp
gfx/angle/src/libGLESv2/Context.cpp
gfx/angle/src/libGLESv2/Context.h
gfx/angle/src/libGLESv2/Makefile.in
gfx/angle/src/libGLESv2/Program.cpp
gfx/angle/src/libGLESv2/Program.h
gfx/angle/src/libGLESv2/VertexDataManager.cpp
gfx/angle/src/libGLESv2/libGLESv2.cpp
gfx/gl/GLContextProviderEGL.cpp
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/d3d10/CanvasLayerD3D10.cpp
gfx/layers/d3d10/LayerManagerD3D10.cpp
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxAndroidPlatform.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformGtk.cpp
gfx/thebes/gfxPlatformGtk.h
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxPlatformMac.h
gfx/thebes/gfxQtPlatform.cpp
gfx/thebes/gfxQtPlatform.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
js/src/builtin/Eval.cpp
js/src/config/autoconf.mk.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/gc/Barrier.h
js/src/gc/Heap.h
js/src/gc/Root.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jsinfer.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsreflect.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsutil.h
js/src/jsval.h
js/src/jsxml.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCJSRuntime.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsDocumentViewer.cpp
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/generic/nsFrame.cpp
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/generic/nsObjectFrame.cpp
layout/generic/nsTextFrame.h
layout/generic/nsTextFrameThebes.cpp
layout/generic/nsVideoFrame.cpp
layout/ipc/RenderFrameParent.cpp
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
layout/style/nsAnimationManager.cpp
layout/style/nsAnimationManager.h
layout/style/nsStyleAnimation.cpp
layout/style/nsStyleAnimation.h
layout/style/nsStyleTransformMatrix.cpp
layout/style/nsStyleTransformMatrix.h
layout/style/nsTransitionManager.cpp
layout/style/nsTransitionManager.h
layout/svg/base/src/nsSVGTextContainerFrame.cpp
layout/tools/reftest/remotereftest.py
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/base/resources/drawable-hdpi/sync_fx_icon.png
mobile/android/base/resources/drawable-hdpi/sync_ic_launcher.png
mobile/android/base/resources/drawable-ldpi/sync_fx_icon.png
mobile/android/base/resources/drawable-ldpi/sync_ic_launcher.png
mobile/android/base/resources/drawable-mdpi/sync_fx_icon.png
mobile/android/base/resources/drawable-mdpi/sync_ic_launcher.png
mobile/android/base/resources/drawable/sync_ic_launcher.png
mobile/android/base/resources/layout/sync_stub.xml
mobile/android/base/resources/xml/sync_authenticator.xml
mobile/android/chrome/content/browser.js
modules/libpref/src/init/all.js
mozglue/android/APKOpen.cpp
netwerk/cache/nsDeleteDir.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
netwerk/protocol/http/nsHttpChannelAuthProvider.h
netwerk/protocol/http/nsHttpNTLMAuth.cpp
profile/dirserviceprovider/src/nsProfileLock.cpp
security/manager/ssl/src/nsNTLMAuthModule.cpp
testing/mochitest/runtestsremote.py
testing/testsuite-targets.mk
toolkit/components/parentalcontrols/nsParentalControlsServiceWin.cpp
toolkit/components/places/nsFaviconService.cpp
toolkit/components/telemetry/TelemetryPing.js
widget/android/GfxInfo.cpp
widget/android/GfxInfo.h
widget/cocoa/GfxInfo.h
widget/cocoa/GfxInfo.mm
widget/windows/GfxInfo.cpp
widget/windows/GfxInfo.h
widget/windows/TaskbarPreview.cpp
widget/windows/nsFilePicker.cpp
widget/windows/nsNativeDragTarget.cpp
widget/windows/nsNativeDragTarget.h
widget/xpwidgets/GfxInfoX11.cpp
widget/xpwidgets/GfxInfoX11.h
xpcom/base/nsCycleCollector.cpp
xpcom/ds/TimeStamp.h
xpcom/glue/nsThreadUtils.cpp
xpcom/glue/nsThreadUtils.h
--- a/accessible/src/msaa/DocAccessibleWrap.cpp
+++ b/accessible/src/msaa/DocAccessibleWrap.cpp
@@ -253,17 +253,17 @@ DocAccessibleWrap::DoInitialUpdate()
   if (nsWinUtils::IsWindowEmulationStarted()) {
     // Create window for tab document.
     if (nsCoreUtils::IsTabDocument(mDocument)) {
       mozilla::dom::TabChild* tabChild =
         mozilla::dom::GetTabChildFrom(mDocument->GetShell());
 
       a11y::RootAccessible* rootDocument = RootAccessible();
 
-      mozilla::WindowsHandle nativeData = nsnull;
+      mozilla::WindowsHandle nativeData = NULL;
       if (tabChild)
         tabChild->SendGetWidgetNativeData(&nativeData);
       else
         nativeData = reinterpret_cast<mozilla::WindowsHandle>(
           rootDocument->GetNativeWindow());
 
       bool isActive = true;
       PRInt32 x = CW_USEDEFAULT, y = CW_USEDEFAULT, width = 0, height = 0;
--- a/b2g/chrome/content/dbg-browser-actors.js
+++ b/b2g/chrome/content/dbg-browser-actors.js
@@ -1,15 +1,19 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ft=javascript 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';
+/**
+ * B2G-specific actors that extend BrowserRootActor and BrowserTabActor,
+ * overriding some of their methods.
+ */
 
 /**
  * The function that creates the root actor. DebuggerServer expects to find this
  * function in the loaded actors in order to initialize properly.
  */
 function createRootActor(connection) {
   return new DeviceRootActor(connection);
 }
@@ -19,77 +23,62 @@ function createRootActor(connection) {
  * The root actor is responsible for the initial 'hello' packet and for
  * responding to a 'listTabs' request that produces the list of currently open
  * tabs.
  *
  * @param connection DebuggerServerConnection
  *        The conection to the client.
  */
 function DeviceRootActor(connection) {
-  this.conn = connection;
-  this._tabActors = new WeakMap();
-  this._tabActorPool = null;
-  this._actorFactories = null;
+  BrowserRootActor.call(this, connection);
   this.browser = Services.wm.getMostRecentWindow('navigator:browser');
 }
 
-DeviceRootActor.prototype = {
-  /**
-   * Return a 'hello' packet as specified by the Remote Debugging Protocol.
-   */
-  sayHello: function DRA_sayHello() {
-    return {
-      from: 'root',
-      applicationType: 'browser',
-      traits: []
-    };
-  },
+DeviceRootActor.prototype = new BrowserRootActor();
 
-  /**
-   * Disconnects the actor from the browser window.
-   */
-  disconnect: function DRA_disconnect() {
-    let actor = this._tabActors.get(this.browser);
-    if (actor) {
-      actor.exit();
-    }
-  },
+/**
+ * Disconnects the actor from the browser window.
+ */
+DeviceRootActor.prototype.disconnect = function DRA_disconnect() {
+  let actor = this._tabActors.get(this.browser);
+  if (actor) {
+    actor.exit();
+  }
+};
 
-  /**
-   * Handles the listTabs request.  Builds a list of actors for the single
-   * tab (window) running in the process. The actors will survive
-   * until at least the next listTabs request.
-   */
-  onListTabs: function DRA_onListTabs() {
-    let actor = this._tabActors.get(this.browser);
-    if (!actor) {
-      actor = new DeviceTabActor(this.conn, this.browser);
-      // this.actorID is set by ActorPool when an actor is put into one.
-      actor.parentID = this.actorID;
-      this._tabActors.set(this.browser, actor);
-    }
-
-    let actorPool = new ActorPool(this.conn);
-    actorPool.addActor(actor);
-
-    // Now drop the old actorID -> actor map. Actors that still mattered were
-    // added to the new map, others will go away.
-    if (this._tabActorPool) {
-      this.conn.removeActorPool(this._tabActorPool);
-    }
-    this._tabActorPool = actorPool;
-    this.conn.addActorPool(this._tabActorPool);
-
-    return {
-      'from': 'root',
-      'selected': 0,
-      'tabs': [actor.grip()]
-    };
+/**
+ * Handles the listTabs request.  Builds a list of actors for the single
+ * tab (window) running in the process. The actors will survive
+ * until at least the next listTabs request.
+ */
+DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
+  let actor = this._tabActors.get(this.browser);
+  if (!actor) {
+    actor = new DeviceTabActor(this.conn, this.browser);
+    // this.actorID is set by ActorPool when an actor is put into one.
+    actor.parentID = this.actorID;
+    this._tabActors.set(this.browser, actor);
   }
 
+  let actorPool = new ActorPool(this.conn);
+  actorPool.addActor(actor);
+
+  // Now drop the old actorID -> actor map. Actors that still mattered were
+  // added to the new map, others will go away.
+  if (this._tabActorPool) {
+    this.conn.removeActorPool(this._tabActorPool);
+  }
+  this._tabActorPool = actorPool;
+  this.conn.addActorPool(this._tabActorPool);
+
+  return {
+    'from': 'root',
+    'selected': 0,
+    'tabs': [actor.grip()]
+  };
 };
 
 /**
  * The request types this actor can handle.
  */
 DeviceRootActor.prototype.requestTypes = {
   'listTabs': DeviceRootActor.prototype.onListTabs
 };
@@ -99,224 +88,63 @@ DeviceRootActor.prototype.requestTypes =
  * and detaching.
  *
  * @param connection DebuggerServerConnection
  *        The connection to the client.
  * @param browser browser
  *        The browser instance that contains this tab.
  */
 function DeviceTabActor(connection, browser) {
-  this.conn = connection;
-  this._browser = browser;
+  BrowserTabActor.call(this, connection, browser);
 }
 
-DeviceTabActor.prototype = {
-  get browser() {
-    return this._browser;
-  },
-
-  get exited() {
-    return !this.browser;
-  },
-
-  get attached() {
-    return !!this._attached
-  },
-
-  _tabPool: null,
-  get tabActorPool() {
-    return this._tabPool;
-  },
-
-  _contextPool: null,
-  get contextActorPool() {
-    return this._contextPool;
-  },
-
-  /**
-   * Add the specified breakpoint to the default actor pool connection, in order
-   * to be alive as long as the server is.
-   *
-   * @param BreakpointActor actor
-   *        The actor object.
-   */
-  addToBreakpointPool: function DTA_addToBreakpointPool(actor) {
-    this.conn.addActor(actor);
-  },
-
-  /**
-   * Remove the specified breakpint from the default actor pool.
-   *
-   * @param string actor
-   *        The actor ID.
-   */
-  removeFromBreakpointPool: function DTA_removeFromBreakpointPool(actor) {
-    this.conn.removeActor(actor);
-  },
-
-  actorPrefix: 'tab',
-
-  grip: function DTA_grip() {
-    dbg_assert(!this.exited,
-               'grip() should not be called on exited browser actor.');
-    dbg_assert(this.actorID,
-               'tab should have an actorID.');
-    return {
-      'actor': this.actorID,
-      'title': this.browser.title,
-      'url': this.browser.document.documentURI
-    }
-  },
-
-  /**
-   * Called when the actor is removed from the connection.
-   */
-  disconnect: function DTA_disconnect() {
-    this._detach();
-  },
-
-  /**
-   * Called by the root actor when the underlying tab is closed.
-   */
-  exit: function DTA_exit() {
-    if (this.exited) {
-      return;
-    }
-
-    if (this.attached) {
-      this._detach();
-      this.conn.send({
-        'from': this.actorID,
-        'type': 'tabDetached'
-      });
-    }
-
-    this._browser = null;
-  },
-
-  /**
-   * Does the actual work of attaching to a tab.
-   */
-  _attach: function DTA_attach() {
-    if (this._attached) {
-      return;
-    }
-
-    // Create a pool for tab-lifetime actors.
-    dbg_assert(!this._tabPool, 'Should not have a tab pool if we were not attached.');
-    this._tabPool = new ActorPool(this.conn);
-    this.conn.addActorPool(this._tabPool);
-
-    // ... and a pool for context-lifetime actors.
-    this._pushContext();
+DeviceTabActor.prototype = new BrowserTabActor();
 
-    this._attached = true;
-  },
-
-  /**
-   * Creates a thread actor and a pool for context-lifetime actors. It then sets
-   * up the content window for debugging.
-   */
-  _pushContext: function DTA_pushContext() {
-    dbg_assert(!this._contextPool, "Can't push multiple contexts");
-
-    this._contextPool = new ActorPool(this.conn);
-    this.conn.addActorPool(this._contextPool);
-
-    this.threadActor = new ThreadActor(this);
-    this._addDebuggees(this.browser.wrappedJSObject);
-    this._contextPool.addActor(this.threadActor);
-  },
-
-  /**
-   * Add the provided window and all windows in its frame tree as debuggees.
-   */
-  _addDebuggees: function DTA__addDebuggees(content) {
-    this.threadActor.addDebuggee(content);
-    let frames = content.frames;
-    for (let i = 0; i < frames.length; i++) {
-      this._addDebuggees(frames[i]);
-    }
-  },
-
-  /**
-   * Exits the current thread actor and removes the context-lifetime actor pool.
-   * The content window is no longer being debugged after this call.
-   */
-  _popContext: function DTA_popContext() {
-    dbg_assert(!!this._contextPool, 'No context to pop.');
-
-    this.conn.removeActorPool(this._contextPool);
-    this._contextPool = null;
-    this.threadActor.exit();
-    this.threadActor = null;
-  },
-
-  /**
-   * Does the actual work of detaching from a tab.
-   */
-  _detach: function DTA_detach() {
-    if (!this.attached) {
-      return;
-    }
-
-    this._popContext();
-
-    // Shut down actors that belong to this tab's pool.
-    this.conn.removeActorPool(this._tabPool);
-    this._tabPool = null;
-
-    this._attached = false;
-  },
-
-  // Protocol Request Handlers
-
-  onAttach: function DTA_onAttach(aRequest) {
-    if (this.exited) {
-      return { type: 'exited' };
-    }
-
-    this._attach();
-
-    return { type: 'tabAttached', threadActor: this.threadActor.actorID };
-  },
-
-  onDetach: function DTA_onDetach(aRequest) {
-    if (!this.attached) {
-      return { error: 'wrongState' };
-    }
-
-    this._detach();
-
-    return { type: 'detached' };
-  },
-
-  /**
-   * Prepare to enter a nested event loop by disabling debuggee events.
-   */
-  preNest: function DTA_preNest() {
-    let windowUtils = this.browser
-                          .QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDOMWindowUtils);
-    windowUtils.suppressEventHandling(true);
-    windowUtils.suspendTimeouts();
-  },
-
-  /**
-   * Prepare to exit a nested event loop by enabling debuggee events.
-   */
-  postNest: function DTA_postNest(aNestData) {
-    let windowUtils = this.browser
-                          .QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDOMWindowUtils);
-    windowUtils.resumeTimeouts();
-    windowUtils.suppressEventHandling(false);
+DeviceTabActor.prototype.grip = function DTA_grip() {
+  dbg_assert(!this.exited,
+             'grip() should not be called on exited browser actor.');
+  dbg_assert(this.actorID,
+             'tab should have an actorID.');
+  return {
+    'actor': this.actorID,
+    'title': this.browser.title,
+    'url': this.browser.document.documentURI
   }
-
 };
 
 /**
- * The request types this actor can handle.
+ * Creates a thread actor and a pool for context-lifetime actors. It then sets
+ * up the content window for debugging.
+ */
+DeviceTabActor.prototype._pushContext = function DTA_pushContext() {
+  dbg_assert(!this._contextPool, "Can't push multiple contexts");
+
+  this._contextPool = new ActorPool(this.conn);
+  this.conn.addActorPool(this._contextPool);
+
+  this.threadActor = new ThreadActor(this);
+  this._addDebuggees(this.browser.wrappedJSObject);
+  this._contextPool.addActor(this.threadActor);
+};
+
+// Protocol Request Handlers
+
+/**
+ * Prepare to enter a nested event loop by disabling debuggee events.
  */
-DeviceTabActor.prototype.requestTypes = {
-  'attach': DeviceTabActor.prototype.onAttach,
-  'detach': DeviceTabActor.prototype.onDetach
+DeviceTabActor.prototype.preNest = function DTA_preNest() {
+  let windowUtils = this.browser
+                        .QueryInterface(Ci.nsIInterfaceRequestor)
+                        .getInterface(Ci.nsIDOMWindowUtils);
+  windowUtils.suppressEventHandling(true);
+  windowUtils.suspendTimeouts();
 };
+
+/**
+ * Prepare to exit a nested event loop by enabling debuggee events.
+ */
+DeviceTabActor.prototype.postNest = function DTA_postNest(aNestData) {
+  let windowUtils = this.browser
+                        .QueryInterface(Ci.nsIInterfaceRequestor)
+                        .getInterface(Ci.nsIDOMWindowUtils);
+  windowUtils.resumeTimeouts();
+  windowUtils.suppressEventHandling(false);
+};
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -539,16 +539,17 @@ var WebappsHelper = {
   }
 }
 
 // Start the debugger server.
 function startDebugger() {
   if (!DebuggerServer.initialized) {
     // Allow remote connections.
     DebuggerServer.init(function () { return true; });
+    DebuggerServer.addBrowserActors();
     DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
   }
 
   let port = Services.prefs.getIntPref('devtools.debugger.remote-port') || 6000;
   try {
     DebuggerServer.openListener(port);
   } catch (e) {
     dump('Unable to start debugger server: ' + e + '\n');
@@ -608,8 +609,28 @@ Services.obs.addObserver(function Conten
     name: 'view',
     data: {
       type: handler.type,
       url: handler.url
     }
   });
 }, 'content-handler', false);
 
+(function geolocationStatusTracker() {
+  let gGeolocationActiveCount = 0;
+
+  Services.obs.addObserver(function(aSubject, aTopic, aData) {
+    let oldCount = gGeolocationActiveCount;
+    if (aData == "starting") {
+      gGeolocationActiveCount += 1;
+    } else if (aData == "shutdown") {
+      gGeolocationActiveCount -= 1;
+    }
+
+    // We need to track changes from 1 <-> 0
+    if (gGeolocationActiveCount + oldCount == 1) {
+      shell.sendChromeEvent({
+        type: 'geolocation-status',
+        active: (gGeolocationActiveCount == 1)
+      });
+    }
+}, "geolocation-device-events", false);
+})();
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -327,30 +327,30 @@
                 key="key_openAddons"/>
       <splitmenu id="appmenu_customize"
 #ifdef XP_UNIX
                  label="&preferencesCmdUnix.label;"
 #else
                  label="&preferencesCmd2.label;"
 #endif
                  oncommand="openPreferences();">
-          <menuitem id="appmenu_socialToggle"
-                    type="checkbox"
-                    autocheck="false"
-                    command="Social:Toggle"/>
           <menupopup id="appmenu_customizeMenu"
                      onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('appmenu_toggleToolbarsSeparator'));">
             <menuitem id="appmenu_preferences"
 #ifdef XP_UNIX
                       label="&preferencesCmdUnix.label;"
 #else
                       label="&preferencesCmd2.label;"
 #endif
                       oncommand="openPreferences();"/>
             <menuseparator/>
+            <menuitem id="appmenu_socialToggle"
+                      type="checkbox"
+                      autocheck="false"
+                      command="Social:Toggle"/>
             <menuseparator id="appmenu_toggleToolbarsSeparator"/>
             <menuitem id="appmenu_toggleTabsOnTop"
                       label="&viewTabsOnTop.label;"
                       type="checkbox"
                       command="cmd_ToggleTabsOnTop"/>
             <menuitem id="appmenu_toolbarLayout"
                       label="&appMenuToolbarLayout.label;"
                       command="cmd_CustomizeToolbars"/>
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -83,27 +83,28 @@
     <command id="cmd_fullZoomReduce"  oncommand="FullZoom.reduce()"/>
     <command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
     <command id="cmd_fullZoomReset"   oncommand="FullZoom.reset()"/>
     <command id="cmd_fullZoomToggle"  oncommand="ZoomManager.toggleZoom();"/>
     <command id="Browser:OpenLocation" oncommand="openLocation();"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
-    <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();"/>
+    <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focus();" disabled="true"/>
     <command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
-    <command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();"/>
-    <command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();"/>
-    <command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();"/>
-    <command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();"/>
-    <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/>
-    <command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();"/>
-    <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/>
+    <command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true" hidden="true"/>
+    <command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true" hidden="true"/>
+    <command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true" hidden="true"/>
+    <command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true" hidden="true"/>
+    <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
+    <command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();" disabled="true" hidden="true"/>
+    <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
+    <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
     <command id="Social:SharePage" oncommand="SocialShareButton.sharePage();"/>
     <command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
@@ -185,69 +186,60 @@
     <broadcaster id="workOfflineMenuitemState"/>
     <broadcaster id="socialSidebarBroadcaster" hidden="true"/>
 
     <!-- DevTools broadcasters -->
     <broadcaster id="devtoolsMenuBroadcaster_DevToolbar"
                  label="&devToolbarMenu.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:DevToolbar"
-                 key="key_devToolbar"
-                 disabled="true" hidden="true"/>
+                 key="key_devToolbar"/>
     <broadcaster id="devtoolsMenuBroadcaster_WebConsole"
                  label="&webConsoleCmd.label;"
                  type="checkbox" autocheck="false"
                  key="key_webConsole"
                  command="Tools:WebConsole"/>
     <broadcaster id="devtoolsMenuBroadcaster_Inspect"
                  label="&inspectMenu.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:Inspect"
-                 key="key_inspect"
-                 disabled="true" hidden="true"/>
+                 key="key_inspect"/>
     <broadcaster id="devtoolsMenuBroadcaster_Debugger"
                  label="&debuggerMenu.label2;"
                  type="checkbox" autocheck="false"
                  command="Tools:Debugger"
-                 key="key_debugger"
-                 disabled="true" hidden="true"/>
+                 key="key_debugger"/>
     <broadcaster id="devtoolsMenuBroadcaster_RemoteDebugger"
                  label="&remoteDebuggerMenu.label;"
-                 command="Tools:RemoteDebugger"
-                 disabled="true" hidden="true"/>
+                 command="Tools:RemoteDebugger"/>
     <broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger"
                  label="&chromeDebuggerMenu.label;"
-                 command="Tools:ChromeDebugger"
-                 disabled="true" hidden="true"/>
+                 command="Tools:ChromeDebugger"/>
     <broadcaster id="devtoolsMenuBroadcaster_Scratchpad"
                  label="&scratchpad.label;"
                  command="Tools:Scratchpad"
-                 key="key_scratchpad"
-                 disabled="true" hidden="true"/>
+                 key="key_scratchpad"/>
     <broadcaster id="devtoolsMenuBroadcaster_StyleEditor"
                  label="&styleeditor.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:StyleEditor"
-                 key="key_styleeditor"
-                 disabled="true" hidden="true"/>
+                 key="key_styleeditor"/>
     <broadcaster id="devtoolsMenuBroadcaster_ResponsiveUI"
                  label="&responsiveDesignTool.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:ResponsiveUI"
-                 key="key_responsiveUI"
-                 disabled="true" hidden="true"/>
+                 key="key_responsiveUI"/>
     <broadcaster id="devtoolsMenuBroadcaster_PageSource"
                  label="&pageSourceCmd.label;"
                  key="key_viewSource"
                  command="View:PageSource"/>
     <broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
-                 hidden="true"
                  label="&errorConsoleCmd.label;"
                  key="key_errorConsole"
-                 oncommand="toJavaScriptConsole();"/>
+                 command="Tools:ErrorConsole"/>
     <broadcaster id="devtoolsMenuBroadcaster_GetMoreTools"
                  label="&getMoreDevtoolsCmd.label;"
                  oncommand="openUILinkIn('https://addons.mozilla.org/firefox/collections/mozilla/webdeveloper/', 'tab');"/>
   </broadcasterset>
 
   <keyset id="mainKeyset">
     <key id="key_newNavigator"
          key="&newNavigatorCmd.key;"
@@ -287,17 +279,17 @@
 #endif
 #ifdef XP_GNOME
     <key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/>
     <key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/>
 #else
     <key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
 #endif
     <key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
-    <key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
+    <key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" command="Tools:ErrorConsole" modifiers="accel,shift"/>
     <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
          keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
     <key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
 #ifdef XP_MACOSX
         modifiers="accel,alt"
 #else
         modifiers="accel,shift"
 #endif
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -38,16 +38,17 @@ let SocialUI = {
         SocialToolbar.updateButtonHiddenState();
         SocialSidebar.updateSidebar();
         break;
       case "social:ambient-notification-changed":
         SocialToolbar.updateButton();
         break;
       case "social:profile-changed":
         SocialToolbar.updateProfile();
+        SocialShareButton.updateProfileInfo();
         break;
       case "nsPref:changed":
         SocialSidebar.updateSidebar();
     }
   },
 
   get toggleCommand() {
     return document.getElementById("Social:Toggle");
@@ -148,17 +149,20 @@ let SocialUI = {
     this.notificationPanel.hidePopup();
   }
 }
 
 let SocialShareButton = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SSB_init() {
     this.updateButtonHiddenState();
+    this.updateProfileInfo();
+  },
 
+  updateProfileInfo: function SSB_updateProfileInfo() {
     let profileRow = document.getElementById("editSharePopupHeader");
     let profile = Social.provider.profile;
     if (profile && profile.portrait && profile.displayName) {
       profileRow.hidden = false;
       let portrait = document.getElementById("socialUserPortrait");
       portrait.style.listStyleImage = profile.portrait;
       let displayName = document.getElementById("socialUserDisplayName");
       displayName.setAttribute("label", profile.displayName);
@@ -369,16 +373,20 @@ var SocialToolbar = {
     this.button.setAttribute("open", "true");
     panel.openPopup(iconImage, "bottomcenter topleft", 0, 0, false, false);
   }
 }
 
 var SocialSidebar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialSidebar_init() {
+    let sbrowser = document.getElementById("social-sidebar-browser");
+    // setting isAppTab causes clicks on untargeted links to open new tabs
+    sbrowser.docShell.isAppTab = true;
+  
     this.updateSidebar();
   },
 
   // Whether the sidebar can be shown for this window.
   get canShow() {
     return Social.uiVisible && Social.provider.sidebarURL && !this.chromeless;
   },
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1397,101 +1397,101 @@ var gBrowserInit = {
     window.addEventListener("resize", function resizeHandler(event) {
       if (event.target == window)
         setUrlAndSearchBarWidthForConditionalForwardButton();
     });
 
     // Enable developer toolbar?
     let devToolbarEnabled = gPrefService.getBoolPref("devtools.toolbar.enabled");
     if (devToolbarEnabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_DevToolbar");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:DevToolbar");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
       document.getElementById("Tools:DevToolbarFocus").removeAttribute("disabled");
 
       // Show the toolbar if it was previously visible
       if (gPrefService.getBoolPref("devtools.toolbar.visible")) {
         DeveloperToolbar.show(false);
       }
     }
 
     // Enable Inspector?
     let enabled = gPrefService.getBoolPref("devtools.inspector.enabled");
     if (enabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_Inspect");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:Inspect");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
     }
 
     // Enable Debugger?
     let enabled = gPrefService.getBoolPref("devtools.debugger.enabled");
     if (enabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_Debugger");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:Debugger");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
     }
 
     // Enable Remote Debugger?
     let enabled = gPrefService.getBoolPref("devtools.debugger.remote-enabled");
     if (enabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_RemoteDebugger");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:RemoteDebugger");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
     }
 
     // Enable Chrome Debugger?
     let enabled = gPrefService.getBoolPref("devtools.chrome.enabled") &&
                   gPrefService.getBoolPref("devtools.debugger.chrome-enabled") &&
                   gPrefService.getBoolPref("devtools.debugger.remote-enabled");
     if (enabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_ChromeDebugger");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:ChromeDebugger");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
     }
 
     // Enable Error Console?
     // XXX Temporarily always-enabled, see bug 601201
     let consoleEnabled = true || gPrefService.getBoolPref("devtools.errorconsole.enabled");
     if (consoleEnabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_ErrorConsole");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:ErrorConsole");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
     }
 
     // Enable Scratchpad in the UI, if the preference allows this.
     let scratchpadEnabled = gPrefService.getBoolPref(Scratchpad.prefEnabledName);
     if (scratchpadEnabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_Scratchpad");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:Scratchpad");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
     }
 
     // Enable Style Editor?
     let styleEditorEnabled = gPrefService.getBoolPref(StyleEditor.prefEnabledName);
     if (styleEditorEnabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_StyleEditor");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:StyleEditor");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
     }
 
 #ifdef MENUBAR_CAN_AUTOHIDE
     // If the user (or the locale) hasn't enabled the top-level "Character
     // Encoding" menu via the "browser.menu.showCharacterEncoding" preference,
     // hide it.
     if ("true" != gPrefService.getComplexValue("browser.menu.showCharacterEncoding",
                                                Ci.nsIPrefLocalizedString).data)
       document.getElementById("appmenu_charsetMenu").hidden = true;
 #endif
 
     // Enable Responsive UI?
     let responsiveUIEnabled = gPrefService.getBoolPref("devtools.responsiveUI.enabled");
     if (responsiveUIEnabled) {
-      let broadcaster = document.getElementById("devtoolsMenuBroadcaster_ResponsiveUI");
-      broadcaster.removeAttribute("disabled");
-      broadcaster.removeAttribute("hidden");
+      let cmd = document.getElementById("Tools:ResponsiveUI");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
     }
 
     let appMenuButton = document.getElementById("appmenu-button");
     let appMenuPopup = document.getElementById("appmenu-popup");
     if (appMenuButton && appMenuPopup) {
       let appMenuOpening = null;
       appMenuButton.addEventListener("mousedown", function(event) {
         if (event.button == 0)
@@ -4676,25 +4676,19 @@ var TabsOnTop = {
 }
 
 var TabsInTitlebar = {
   init: function () {
 #ifdef CAN_DRAW_IN_TITLEBAR
     this._readPref();
     Services.prefs.addObserver(this._prefName, this, false);
 
-    // Don't trust the initial value of the sizemode attribute; wait for the resize event.
+    // Don't trust the initial value of the sizemode attribute; wait for
+    // the resize event (handled in tabbrowser.xml).
     this.allowedBy("sizemode", false);
-    window.addEventListener("resize", function (event) {
-      if (event.target != window)
-        return;
-      let sizemode = document.documentElement.getAttribute("sizemode");
-      TabsInTitlebar.allowedBy("sizemode",
-                               sizemode == "maximized" || sizemode == "fullscreen");
-    }, false);
 
     this._initialized = true;
 #endif
   },
 
   allowedBy: function (condition, allow) {
 #ifdef CAN_DRAW_IN_TITLEBAR
     if (allow) {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1065,35 +1065,35 @@
       <tabbrowser id="content" disablehistory="true"
                   flex="1" contenttooltip="aHTMLTooltip"
                   tabcontainer="tabbrowser-tabs"
                   contentcontextmenu="contentAreaContextMenu"
                   autocompletepopup="PopupAutoComplete"
                   onclick="contentAreaClick(event, false);"/>
       <statuspanel id="statusbar-display" inactive="true"/>
     </vbox>
+    <splitter id="devtools-side-splitter" hidden="true"/>
+    <vbox id="devtools-sidebar-box" hidden="true"
+          style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
+      <toolbar id="devtools-sidebar-toolbar"
+               class="devtools-toolbar"
+               nowindowdrag="true"/>
+      <deck id="devtools-sidebar-deck" flex="1"/>
+    </vbox>
     <splitter id="social-sidebar-splitter"
               class="chromeclass-extrachrome"
               observes="socialSidebarBroadcaster"/>
     <vbox id="social-sidebar-box"
           class="chromeclass-extrachrome"
           observes="socialSidebarBroadcaster">
       <browser id="social-sidebar-browser"
                type="content"
                flex="1"
                style="min-width: 14em; width: 18em; max-width: 36em;"/>
     </vbox>
-    <splitter id="devtools-side-splitter" hidden="true"/>
-    <vbox id="devtools-sidebar-box" hidden="true"
-          style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
-      <toolbar id="devtools-sidebar-toolbar"
-               class="devtools-toolbar"
-               nowindowdrag="true"/>
-      <deck id="devtools-sidebar-deck" flex="1"/>
-    </vbox>
     <vbox id="browser-border-end" hidden="true" layer="true"/>
   </hbox>
 
   <hbox id="full-screen-warning-container" hidden="true" fadeout="true">
     <hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
       <vbox id="full-screen-warning-message" align="center">
         <description id="full-screen-domain-text"/>
         <description class="full-screen-description" value="&fullscreenExitHint.value;"/>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3087,23 +3087,29 @@
         <body><![CDATA[
           switch (aEvent.type) {
             case "load":
               this.updateVisibility();
               break;
             case "resize":
               if (aEvent.target != window)
                 break;
+
+              let sizemode = document.documentElement.getAttribute("sizemode");
+              TabsInTitlebar.allowedBy("sizemode",
+                                       sizemode == "maximized" || sizemode == "fullscreen");
+
               var width = this.mTabstrip.boxObject.width;
               if (width != this.mTabstripWidth) {
                 this.adjustTabstrip();
                 this._fillTrailingGap();
                 this._handleTabSelect();
                 this.mTabstripWidth = width;
               }
+
               this.tabbrowser.updateWindowResizers();
               break;
             case "mouseout":
               // If the "related target" (the node to which the pointer went) is not
               // a child of the current document, the mouse just left the window.
               let relatedTarget = aEvent.relatedTarget;
               if (relatedTarget && relatedTarget.ownerDocument == document)
                 break;
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -256,16 +256,17 @@ endif
                  browser_tabDrop.js \
                  browser_lastAccessedTab.js \
                  browser_bug734076.js \
                  browser_social_toolbar.js \
                  browser_social_sidebar.js \
                  browser_social_mozSocial_API.js \
                  social_panel.html \
                  social_sidebar.html \
+                 social_window.html \
                  social_worker.js \
                  $(NULL)
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += \
 		browser_bug462289.js \
 		$(NULL)
 else
--- a/browser/base/content/test/browser_social_mozSocial_API.js
+++ b/browser/base/content/test/browser_social_mozSocial_API.js
@@ -5,83 +5,130 @@
 let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
 
 function test() {
   // XXX Bug 775779
   if (Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2).isDebugBuild) {
     ok(true, "can't run social sidebar test in debug builds because they falsely report leaks");
     return;
   }
-
   waitForExplicitFinish();
 
   let manifest = { // normal provider
     name: "provider 1",
     origin: "http://example.com",
     sidebarURL: "http://example.com/browser/browser/base/content/test/social_sidebar.html",
     workerURL: "http://example.com/browser/browser/base/content/test/social_worker.js",
     iconURL: "chrome://branding/content/icon48.png"
   };
-  runSocialTestWithProvider(manifest, doTest);
+  runSocialTestWithProvider(manifest, function () {
+    runSocialTests(tests, undefined, undefined, function () {
+      SocialService.removeProvider(Social.provider.origin, finish);
+    });
+  });
 }
 
-function doTest() {
-  let iconsReady = false;
-  let gotSidebarMessage = false;
+var tests = {
+  testStatusIcons: function(next) {
+    let iconsReady = false;
+    let gotSidebarMessage = false;
+
+    function checkNext() {
+      if (iconsReady && gotSidebarMessage)
+        triggerIconPanel();
+    }
+
+    function triggerIconPanel() {
+      let statusIcons = document.getElementById("social-status-iconbox");
+      ok(!statusIcons.firstChild.collapsed, "status icon is visible");
+      // Click the button to trigger its contentPanel
+      let panel = document.getElementById("social-notification-panel");
+      EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
+    }
 
-  function checkNext() {
-    if (iconsReady && gotSidebarMessage)
-      triggerIconPanel();
-  }
-
-  function triggerIconPanel() {
-    let statusIcons = document.getElementById("social-status-iconbox");
-    ok(!statusIcons.firstChild.collapsed, "status icon is visible");
-    // Click the button to trigger its contentPanel
-    let panel = document.getElementById("social-notification-panel");
-    EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
-  }
+    let port = Social.provider.port;
+    ok(port, "provider has a port");
+    port.postMessage({topic: "test-init"});
+    Social.provider.port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "got-panel-message":
+          ok(true, "got panel message");
+          // Wait for the panel to close before ending the test
+          let panel = document.getElementById("social-notification-panel");
+          panel.addEventListener("popuphidden", function hiddenListener() {
+            panel.removeEventListener("popuphidden", hiddenListener);
+            next();
+          });
+          panel.hidePopup();
+          break;
+        case "got-sidebar-message":
+          // The sidebar message will always come first, since it loads by default
+          ok(true, "got sidebar message");
+          gotSidebarMessage = true;
+          checkNext();
+          break;
+      }
+    }
 
-  let port = Social.provider.port;
-  ok(port, "provider has a port");
-  port.postMessage({topic: "test-init"});
-  Social.provider.port.onmessage = function (e) {
-    let topic = e.data.topic;
-    switch (topic) {
-      case "got-panel-message":
-        ok(true, "got panel message");
-        // Wait for the panel to close before ending the test
-        let panel = document.getElementById("social-notification-panel");
-        panel.addEventListener("popuphidden", function hiddenListener() {
-          panel.removeEventListener("popuphidden", hiddenListener);
-          SocialService.removeProvider(Social.provider.origin, finish);
+    // Our worker sets up ambient notification at the same time as it responds to
+    // the workerAPI initialization. If it's already initialized, we can
+    // immediately check the icons, otherwise wait for initialization by
+    // observing the topic sent out by the social service.
+    if (Social.provider.workerAPI.initialized) {
+      iconsReady = true;
+      checkNext();
+    } else {
+      Services.obs.addObserver(function obs() {
+        Services.obs.removeObserver(obs, "social:ambient-notification-changed");
+        // Let the other observers (like the one that updates the UI) run before
+        // checking the icons.
+        executeSoon(function () {
+          iconsReady = true;
+          checkNext();
         });
-        panel.hidePopup();
-        break;
-      case "got-sidebar-message":
-        // The sidebar message will always come first, since it loads by default
-        ok(true, "got sidebar message");
-        info(topic);
-        gotSidebarMessage = true;
-        checkNext();
-        break;
+      }, "social:ambient-notification-changed", false);
+    }
+  },
+
+  testServiceWindow: function(next) {
+    // our test provider was initialized in the test above, we just
+    // initiate our specific test now.
+    let port = Social.provider.port;
+    ok(port, "provider has a port");
+    port.postMessage({topic: "test-service-window"});
+    port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "got-service-window-message":
+          // The sidebar message will always come first, since it loads by default
+          ok(true, "got service window message");
+          port.postMessage({topic: "test-close-service-window"});
+          break;
+        case "got-service-window-closed-message":
+          ok(true, "got service window closed message");
+          next();
+          break;
+      }
+    }
+  },
+
+  testServiceWindowTwice: function(next) {
+    let port = Social.provider.port;
+    port.postMessage({topic: "test-service-window-twice"});
+    Social.provider.port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "test-service-window-twice-result":
+          is(e.data.result, "ok", "only one window should open when name is reused");
+          break;
+        case "got-service-window-message":
+          ok(true, "got service window message");
+          port.postMessage({topic: "test-close-service-window"});
+          break;
+        case "got-service-window-closed-message":
+          ok(true, "got service window closed message");
+          next();
+          break;
+      }
     }
   }
-
-  // Our worker sets up ambient notification at the same time as it responds to
-  // the workerAPI initialization. If it's already initialized, we can
-  // immediately check the icons, otherwise wait for initialization by
-  // observing the topic sent out by the social service.
-  if (Social.provider.workerAPI.initialized) {
-    iconsReady = true;
-    checkNext();
-  } else {
-    Services.obs.addObserver(function obs() {
-      Services.obs.removeObserver(obs, "social:ambient-notification-changed");
-      // Let the other observers (like the one that updates the UI) run before
-      // checking the icons.
-      executeSoon(function () {
-        iconsReady = true;
-        checkNext();
-      });
-    }, "social:ambient-notification-changed", false);
-  }
 }
--- a/browser/base/content/test/browser_social_toolbar.js
+++ b/browser/base/content/test/browser_social_toolbar.js
@@ -9,17 +9,17 @@ function test() {
 
   let manifest = { // normal provider
     name: "provider 1",
     origin: "https://example1.com",
     workerURL: "https://example1.com/worker.js",
     iconURL: "chrome://branding/content/icon48.png"
   };
   runSocialTestWithProvider(manifest, function () {
-    runTests(tests, undefined, undefined, function () {
+    runSocialTests(tests, undefined, undefined, function () {
       SocialService.removeProvider(Social.provider.origin, finish);
     });
   });
 }
 
 var tests = {
   testProfileSet: function(next) {
     let profile = {
@@ -69,47 +69,8 @@ var tests = {
       ok(ambience.collapsed, "ambient icon is collapsed");
       ambience = ambience.nextSibling;
     }
     
     next();
   }
 }
 
-function runTests(tests, cbPreTest, cbPostTest, cbFinish) {
-  let testIter = Iterator(tests);
-
-  if (cbPreTest === undefined) {
-    cbPreTest = function(cb) {cb()};
-  }
-  if (cbPostTest === undefined) {
-    cbPostTest = function(cb) {cb()};
-  }
-
-  function runNextTest() {
-    let name, func;
-    try {
-      [name, func] = testIter.next();
-    } catch (err if err instanceof StopIteration) {
-      // out of items:
-      (cbFinish || finish)();
-      return;
-    }
-    // We run on a timeout as the frameworker also makes use of timeouts, so
-    // this helps keep the debug messages sane.
-    executeSoon(function() {
-      function cleanupAndRunNextTest() {
-        info("sub-test " + name + " complete");
-        cbPostTest(runNextTest);
-      }
-      cbPreTest(function() {
-        info("sub-test " + name + " starting");
-        try {
-          func.call(tests, cleanupAndRunNextTest);
-        } catch (ex) {
-          ok(false, "sub-test " + name + " failed: " + ex.toString() +"\n"+ex.stack);
-          cleanupAndRunNextTest();
-        }
-      })
-    });
-  }
-  runNextTest();
-}
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head.js
@@ -113,8 +113,49 @@ function runSocialTestWithProvider(manif
     } else {
       Services.obs.addObserver(function obs() {
         Services.obs.removeObserver(obs, "test-social-ui-ready");
         saveOldProviderAndStartTestWith(provider);
       }, "test-social-ui-ready", false);
     }
   });
 }
+
+
+function runSocialTests(tests, cbPreTest, cbPostTest, cbFinish) {
+  let testIter = Iterator(tests);
+
+  if (cbPreTest === undefined) {
+    cbPreTest = function(cb) {cb()};
+  }
+  if (cbPostTest === undefined) {
+    cbPostTest = function(cb) {cb()};
+  }
+
+  function runNextTest() {
+    let name, func;
+    try {
+      [name, func] = testIter.next();
+    } catch (err if err instanceof StopIteration) {
+      // out of items:
+      (cbFinish || finish)();
+      return;
+    }
+    // We run on a timeout as the frameworker also makes use of timeouts, so
+    // this helps keep the debug messages sane.
+    executeSoon(function() {
+      function cleanupAndRunNextTest() {
+        info("sub-test " + name + " complete");
+        cbPostTest(runNextTest);
+      }
+      cbPreTest(function() {
+        info("sub-test " + name + " starting");
+        try {
+          func.call(tests, cleanupAndRunNextTest);
+        } catch (ex) {
+          ok(false, "sub-test " + name + " failed: " + ex.toString() +"\n"+ex.stack);
+          cleanupAndRunNextTest();
+        }
+      })
+    });
+  }
+  runNextTest();
+}
--- a/browser/base/content/test/social_sidebar.html
+++ b/browser/base/content/test/social_sidebar.html
@@ -1,14 +1,40 @@
 <html>
   <head>
     <meta charset="utf-8">
     <script>
+      var win;
       function pingWorker() {
         var port = navigator.mozSocial.getWorker().port;
+        port.onmessage = function(e) {
+          var topic = e.data.topic;
+          switch (topic) {
+            case "test-service-window":
+              win = navigator.mozSocial.openServiceWindow("social_window.html", "test-service-window", "width=300,height=300");
+              break;
+            case "test-service-window-twice":
+              win = navigator.mozSocial.openServiceWindow("social_window.html", "test-service-window", "width=300,height=300");
+              var win2 = navigator.mozSocial.openServiceWindow("social_window.html", "test-service-window", "");
+              var result;
+              if (win == win2)
+                result = "ok";
+              else
+                result = "not ok: " + win2 + " != " + win;
+              port.postMessage({topic: "test-service-window-twice-result", result: result});
+              break;
+            case "test-close-service-window":
+              win.addEventListener("unload", function watchClose() {
+                win.removeEventListener("unload", watchClose);
+                port.postMessage({topic: "service-window-closed-message", result: "ok"});
+              }, false)
+              win.close();
+              break;
+          }
+        }
         port.postMessage({topic: "sidebar-message", result: "ok"});
       }
     </script>
   </head>
   <body onload="pingWorker();">
     <p>This is a test social sidebar.</p>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social_window.html
@@ -0,0 +1,14 @@
+<html>
+  <head>
+    <meta charset="utf-8">
+    <script>
+      function pingWorker() {
+        var port = navigator.mozSocial.getWorker().port;
+        port.postMessage({topic: "service-window-message", result: "ok"});
+      }
+    </script>
+  </head>
+  <body onload="pingWorker();">
+    <p>This is a test social service window.</p>
+  </body>
+</html>
--- a/browser/base/content/test/social_worker.js
+++ b/browser/base/content/test/social_worker.js
@@ -1,26 +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/. */
 
-let testPort;
+let testPort, sidebarPort;
 
 onconnect = function(e) {
   let port = e.ports[0];
   port.onmessage = function onMessage(event) {
     let topic = event.data.topic;
     switch (topic) {
       case "test-init":
         testPort = port;
         break;
       case "sidebar-message":
+        sidebarPort = port;
         if (testPort && event.data.result == "ok")
           testPort.postMessage({topic:"got-sidebar-message"});
         break;
+      case "service-window-message":
+        testPort.postMessage({topic:"got-service-window-message"});
+        break;
+      case "service-window-closed-message":
+        testPort.postMessage({topic:"got-service-window-closed-message"});
+        break;
+      case "test-service-window":
+        sidebarPort.postMessage({topic:"test-service-window"});
+        break;
+      case "test-service-window-twice":
+        sidebarPort.postMessage({topic:"test-service-window-twice"});
+        break;
+      case "test-service-window-twice-result":
+        testPort.postMessage({topic: "test-service-window-twice-result", result: event.data.result })
+        break;
+      case "test-close-service-window":
+        sidebarPort.postMessage({topic:"test-close-service-window"});
+        break;
       case "panel-message":
         if (testPort && event.data.result == "ok")
           testPort.postMessage({topic:"got-panel-message"});
         break;
       case "social.initialize":
         // This is the workerAPI port, respond and set up a notification icon.
         port.postMessage({topic: "social.initialize-response"});
         let profile = {
--- a/browser/devtools/tilt/test/Makefile.in
+++ b/browser/devtools/tilt/test/Makefile.in
@@ -5,21 +5,18 @@
 DEPTH			= ../../../..
 topsrcdir		= @top_srcdir@
 srcdir			= @srcdir@
 VPATH			= @srcdir@
 relativesrcdir 	= browser/devtools/tilt/test
 
 include $(DEPTH)/config/autoconf.mk
 
-MOCHITEST_BROWSER_FILES = head.js
-
-# browser_tilt* disabled on Linux due to bug 759157
-ifneq (gtk2,$(MOZ_WIDGET_TOOLKIT))
-MOCHITEST_BROWSER_FILES += \
+MOCHITEST_BROWSER_FILES = \
+	head.js \
 	browser_tilt_01_lazy_getter.js \
 	browser_tilt_02_notifications-seq.js \
 	browser_tilt_02_notifications.js \
 	browser_tilt_03_tab_switch.js \
 	browser_tilt_04_initialization-key.js \
 	browser_tilt_04_initialization.js \
 	browser_tilt_05_destruction-esc.js \
 	browser_tilt_05_destruction-url.js \
@@ -55,11 +52,10 @@ MOCHITEST_BROWSER_FILES += \
 	browser_tilt_utils03.js \
 	browser_tilt_utils04.js \
 	browser_tilt_utils05.js \
 	browser_tilt_utils06.js \
 	browser_tilt_utils07.js \
 	browser_tilt_visualizer.js \
 	browser_tilt_zoom.js \
 	$(NULL)
-endif
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/devtools/webconsole/WebConsoleUtils.jsm
+++ b/browser/devtools/webconsole/WebConsoleUtils.jsm
@@ -533,17 +533,17 @@ var WebConsoleUtils = {
         value = "";
         presentable = {type: TYPES.GETTER, display: "Getter"};
       }
       else {
         try {
           value = aObject[propName];
           presentable = this.presentableValueFor(value);
         }
-	      catch (ex) {
+        catch (ex) {
           continue;
         }
       }
 
       let pair = {};
       pair.name = propName;
       pair.value = presentable.display;
       pair.inspectable = false;
@@ -730,16 +730,18 @@ const STATE_DQUOTE = 3;
 const OPEN_BODY = "{[(".split("");
 const CLOSE_BODY = "}])".split("");
 const OPEN_CLOSE_BODY = {
   "{": "}",
   "[": "]",
   "(": ")",
 };
 
+const MAX_COMPLETIONS = 256;
+
 /**
  * Analyses a given string to find the last statement that is interesting for
  * later completion.
  *
  * @param   string aStr
  *          A string to analyse.
  *
  * @returns object
@@ -890,19 +892,19 @@ function JSPropertyProvider(aScope, aInp
   if (properties.length > 1) {
     matchProp = properties.pop().trimLeft();
     for (let i = 0; i < properties.length; i++) {
       let prop = properties[i].trim();
       if (!prop) {
         return null;
       }
 
-      // If obj is undefined or null, then there is no chance to run completion
-      // on it. Exit here.
-      if (typeof obj === "undefined" || obj === null) {
+      // If obj is undefined or null (which is what "== null" does),
+      // then there is no chance to run completion on it. Exit here.
+      if (obj == null) {
         return null;
       }
 
       // Check if prop is a getter function on obj. Functions can change other
       // stuff so we can't execute them to get the next object. Stop here.
       if (WCU.isNonNativeGetter(obj, prop)) {
         return null;
       }
@@ -913,34 +915,79 @@ function JSPropertyProvider(aScope, aInp
         return null;
       }
     }
   }
   else {
     matchProp = properties[0].trimLeft();
   }
 
-  // If obj is undefined or null, then there is no chance to run
-  // completion on it. Exit here.
-  if (typeof obj === "undefined" || obj === null) {
+  // If obj is undefined or null (which is what "== null" does),
+  // then there is no chance to run completion on it. Exit here.
+  if (obj == null) {
     return null;
   }
 
   // Skip Iterators and Generators.
   if (WCU.isIteratorOrGenerator(obj)) {
     return null;
   }
 
-  let matches = [];
-  for (let prop in obj) {
-    if (prop.indexOf(matchProp) == 0) {
-      matches.push(prop);
-    }
-  }
+  let matches = Object.keys(getMatchedProps(obj, matchProp));
 
   return {
     matchProp: matchProp,
     matches: matches.sort(),
   };
 }
 
+/**
+ * Get all accessible properties on this object.
+ * Filter those properties by name.
+ * Take only a certain number of those.
+ *
+ * @param object obj
+ *        Object whose properties we want to collect.
+ *
+ * @param string matchProp
+ *        Filter for properties that match this one.
+ *        Defaults to the empty string (which always matches).
+ *
+ * @return object
+ *         Object whose keys are all accessible properties on the object.
+ */
+function getMatchedProps(aObj, aMatchProp = "")
+{
+  let c = MAX_COMPLETIONS;
+  let names = {};   // Using an Object to avoid duplicates.
+  let ownNames = Object.getOwnPropertyNames(aObj);
+  for (let i = 0; i < ownNames.length; i++) {
+    if (ownNames[i].indexOf(aMatchProp) == 0) {
+      if (names[ownNames[i]] != true) {
+        c--;
+        if (c < 0) {
+          return names;
+        }
+        names[ownNames[i]] = true;
+      }
+    }
+  }
+
+  // We need to recursively go up the prototype chain.
+  aObj = Object.getPrototypeOf(aObj);
+  if (aObj !== null) {
+    let parentScope = getMatchedProps(aObj, aMatchProp);
+    for (let name in parentScope) {
+      if (names[name] != true) {
+        c--;
+        if (c < 0) {
+          return names;
+        }
+        names[name] = true;
+      }
+    }
+  }
+  return names;
+}
+
+
 return JSPropertyProvider;
 })(WebConsoleUtils);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
@@ -30,43 +30,68 @@ function consoleOpened(aHud) {
 
   ok(!popup.isOpen, "popup is not open");
 
   popup._panel.addEventListener("popupshown", function onShown() {
     popup._panel.removeEventListener("popupshown", onShown, false);
 
     ok(popup.isOpen, "popup is open");
 
-    is(popup.itemCount, 4, "popup.itemCount is correct");
+    // 4 values, and the following properties:
+    // __defineGetter__  __defineSetter__ __lookupGetter__ __lookupSetter__
+    // hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString
+    // toSource unwatch valueOf watch constructor.
+    is(popup.itemCount, 18, "popup.itemCount is correct");
 
-    let sameItems = popup.getItems();
-    is(sameItems.every(function(aItem, aIndex) {
-      return aItem.label == "item" + aIndex;
-    }), true, "getItems returns back the same items");
+    let sameItems = popup.getItems().map(function(e) {return e.label;});
+    ok(sameItems.every(function(prop, index) {
+      return [
+        "__defineGetter__",
+        "__defineSetter__",
+        "__lookupGetter__",
+        "__lookupSetter__",
+        "constructor",
+        "hasOwnProperty",
+        "isPrototypeOf",
+        "item0",
+        "item1",
+        "item2",
+        "item3",
+        "propertyIsEnumerable",
+        "toLocaleString",
+        "toSource",
+        "toString",
+        "unwatch",
+        "valueOf",
+        "watch",
+      ][index] === prop}), "getItems returns the items we expect");
 
     is(popup.selectedIndex, -1, "no index is selected");
     EventUtils.synthesizeKey("VK_DOWN", {});
-      
+
     let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
 
     is(popup.selectedIndex, 0, "index 0 is selected");
-    is(popup.selectedItem.label, "item0", "item0 is selected");
-    is(completeNode.value, prefix + "item0", "completeNode.value holds item0");
+    is(popup.selectedItem.label, "__defineGetter__", "__defineGetter__ is selected");
+    is(completeNode.value, prefix + "__defineGetter__",
+        "completeNode.value holds __defineGetter__");
 
     EventUtils.synthesizeKey("VK_DOWN", {});
 
     is(popup.selectedIndex, 1, "index 1 is selected");
-    is(popup.selectedItem.label, "item1", "item1 is selected");
-    is(completeNode.value, prefix + "item1", "completeNode.value holds item1");
+    is(popup.selectedItem.label, "__defineSetter__", "__defineSetter__ is selected");
+    is(completeNode.value, prefix + "__defineSetter__",
+        "completeNode.value holds __defineSetter__");
 
     EventUtils.synthesizeKey("VK_UP", {});
 
     is(popup.selectedIndex, 0, "index 0 is selected");
-    is(popup.selectedItem.label, "item0", "item0 is selected");
-    is(completeNode.value, prefix + "item0", "completeNode.value holds item0");
+    is(popup.selectedItem.label, "__defineGetter__", "__defineGetter__ is selected");
+    is(completeNode.value, prefix + "__defineGetter__",
+        "completeNode.value holds __defineGetter__");
 
     popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false);
 
     EventUtils.synthesizeKey("VK_TAB", {});
   }, false);
 
   jsterm.setInputValue("window.foobarBug585991");
   EventUtils.synthesizeKey(".", {});
@@ -78,36 +103,37 @@ function autocompletePopupHidden()
   let popup = jsterm.autocompletePopup;
   let completeNode = jsterm.completeNode;
   let inputNode = jsterm.inputNode;
 
   popup._panel.removeEventListener("popuphidden", autocompletePopupHidden, false);
 
   ok(!popup.isOpen, "popup is not open");
 
-  is(inputNode.value, "window.foobarBug585991.item0",
+  is(inputNode.value, "window.foobarBug585991.__defineGetter__",
      "completion was successful after VK_TAB");
 
   ok(!completeNode.value, "completeNode is empty");
 
   popup._panel.addEventListener("popupshown", function onShown() {
     popup._panel.removeEventListener("popupshown", onShown, false);
 
     ok(popup.isOpen, "popup is open");
 
-    is(popup.itemCount, 4, "popup.itemCount is correct");
+    is(popup.itemCount, 18, "popup.itemCount is correct");
 
     is(popup.selectedIndex, -1, "no index is selected");
     EventUtils.synthesizeKey("VK_DOWN", {});
-    
+
     let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
 
     is(popup.selectedIndex, 0, "index 0 is selected");
-    is(popup.selectedItem.label, "item0", "item0 is selected");
-    is(completeNode.value, prefix + "item0", "completeNode.value holds item0");
+    is(popup.selectedItem.label, "__defineGetter__", "__defineGetter__ is selected");
+    is(completeNode.value, prefix + "__defineGetter__",
+        "completeNode.value holds __defineGetter__");
 
     popup._panel.addEventListener("popuphidden", function onHidden() {
       popup._panel.removeEventListener("popuphidden", onHidden, false);
 
       ok(!popup.isOpen, "popup is not open after VK_ESCAPE");
 
       is(inputNode.value, "window.foobarBug585991.",
          "completion was cancelled");
@@ -135,39 +161,41 @@ function testReturnKey()
   let completeNode = jsterm.completeNode;
   let inputNode = jsterm.inputNode;
 
   popup._panel.addEventListener("popupshown", function onShown() {
     popup._panel.removeEventListener("popupshown", onShown, false);
 
     ok(popup.isOpen, "popup is open");
 
-    is(popup.itemCount, 4, "popup.itemCount is correct");
-    
+    is(popup.itemCount, 18, "popup.itemCount is correct");
+
     is(popup.selectedIndex, -1, "no index is selected");
     EventUtils.synthesizeKey("VK_DOWN", {});
 
     let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
 
     is(popup.selectedIndex, 0, "index 0 is selected");
-    is(popup.selectedItem.label, "item0", "item0 is selected");
-    is(completeNode.value, prefix + "item0", "completeNode.value holds item0");
+    is(popup.selectedItem.label, "__defineGetter__", "__defineGetter__ is selected");
+    is(completeNode.value, prefix + "__defineGetter__",
+        "completeNode.value holds __defineGetter__");
 
     EventUtils.synthesizeKey("VK_DOWN", {});
 
     is(popup.selectedIndex, 1, "index 1 is selected");
-    is(popup.selectedItem.label, "item1", "item1 is selected");
-    is(completeNode.value, prefix + "item1", "completeNode.value holds item1");
+    is(popup.selectedItem.label, "__defineSetter__", "__defineSetter__ is selected");
+    is(completeNode.value, prefix + "__defineSetter__",
+        "completeNode.value holds __defineSetter__");
 
     popup._panel.addEventListener("popuphidden", function onHidden() {
       popup._panel.removeEventListener("popuphidden", onHidden, false);
 
       ok(!popup.isOpen, "popup is not open after VK_RETURN");
 
-      is(inputNode.value, "window.foobarBug585991.item1",
+      is(inputNode.value, "window.foobarBug585991.__defineSetter__",
          "completion was successful after VK_RETURN");
 
       ok(!completeNode.value, "completeNode is empty");
 
       executeSoon(finishTest);
     }, false);
 
     EventUtils.synthesizeKey("VK_RETURN", {});
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
@@ -29,18 +29,22 @@ function consoleOpened(aHud) {
 
   ok(!popup.isOpen, "popup is not open");
 
   popup._panel.addEventListener("popupshown", function onShown() {
     popup._panel.removeEventListener("popupshown", onShown, false);
 
     ok(popup.isOpen, "popup is open");
 
+    // |props| values, and the following properties:
+    // __defineGetter__  __defineSetter__ __lookupGetter__ __lookupSetter__
+    // constructor hasOwnProperty isPrototypeOf propertyIsEnumerable
+    // toLocaleString toSource toString unwatch valueOf watch.
     let props = WCU.namesAndValuesOf(content.wrappedJSObject.document.body);
-    is(popup.itemCount, props.length, "popup.itemCount is correct");
+    is(popup.itemCount, 14 + props.length, "popup.itemCount is correct");
 
     popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false);
 
     EventUtils.synthesizeKey("VK_ESCAPE", {});
   }, false);
 
   jsterm.setInputValue("document.body");
   EventUtils.synthesizeKey(".", {});
--- a/browser/devtools/webconsole/test/browser_webconsole_completion.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_completion.js
@@ -45,16 +45,24 @@ function testCompletion(hud) {
   jsterm.complete(jsterm.COMPLETE_FORWARD, testNext);
   yield;
 
   is(input.value, "document", "'docu' tab completion");
   is(input.selectionStart, 8, "start selection is alright");
   is(input.selectionEnd, 8, "end selection is alright");
   is(jsterm.completeNode.value.replace(/ /g, ""), "", "'docu' completed");
 
+  // Test typing 'window.O' and press tab.
+  input.value = "window.O";
+  input.setSelectionRange(8, 8);
+  jsterm.complete(jsterm.COMPLETE_FORWARD, testNext);
+  yield;
+
+  is(input.value, "window.Object", "'window.O' tab completion");
+
   // Test typing 'document.getElem'.
   input.value = "document.getElem";
   input.setSelectionRange(16, 16);
   jsterm.complete(jsterm.COMPLETE_FORWARD, testNext);
   yield;
 
   is(input.value, "document.getElem", "'document.getElem' completion");
   is(jsterm.completeNode.value, "                entById", "'document.getElem' completion");
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -449,66 +449,66 @@ addonDesc=Manipulate add-ons
 # LOCALIZATION NOTE (addonListDesc) A very short description of the 'addon list'
 # command. This string is designed to be shown in a menu alongside the command
 # name, which is why it should be as short as possible.
 addonListDesc=List installed add-ons
 
 # LOCALIZATION NOTE (addonListTypeDesc) A very short description of the
 # 'addon list <type>' command. This string is designed to be shown in a menu
 # alongside the command name, which is why it should be as short as possible.
-addonListTypeDesc=Select an addon type
+addonListTypeDesc=Select an add-on type
 
 # LOCALIZATION NOTE (addonListDictionaryHeading, addonListExtensionHeading,
 # addonListLocaleHeading, addonListPluginHeading, addonListThemeHeading,
 # addonListUnknownHeading) Used in the output of the 'addon list' command as the
 # first line of output.
 addonListDictionaryHeading=The following dictionaries are currently installed:
 addonListExtensionHeading=The following extensions are currently installed:
 addonListLocaleHeading=The following locales are currently installed:
 addonListPluginHeading=The following plugins are currently installed:
 addonListThemeHeading=The following themes are currently installed:
-addonListAllHeading=The following addons are currently installed:
-addonListUnknownHeading=The following addons of the selected type are currently installed:
+addonListAllHeading=The following add-ons are currently installed:
+addonListUnknownHeading=The following add-ons of the selected type are currently installed:
 
 # LOCALIZATION NOTE (addonNameDesc) A very short description of the
-# name parameter of numerous addon commands. This string is designed to be shown
+# name parameter of numerous add-on commands. This string is designed to be shown
 # in a menu alongside the command name, which is why it should be as short as
 # possible.
 addonNameDesc=The name of the add-on
 
 # LOCALIZATION NOTE (addonNoneOfType) Used in the output of the 'addon list'
-# command when a search for addons of a particular type were not found.
-addonNoneOfType=There are no addons of that type installed.
+# command when a search for add-ons of a particular type were not found.
+addonNoneOfType=There are no add-ons of that type installed.
 
 # LOCALIZATION NOTE (addonEnableDesc) A very short description of the
 # 'addon enable <type>' command. This string is designed to be shown in a menu
 # alongside the command name, which is why it should be as short as possible.
 addonEnableDesc=Enable the specified add-on
 
 # LOCALIZATION NOTE (addonAlreadyEnabled) Used in the output of the
-# 'addon enable' command when an attempt is made to enable an addon is already
+# 'addon enable' command when an attempt is made to enable an add-on is already
 # enabled.
 addonAlreadyEnabled=%S is already enabled.
 
 # LOCALIZATION NOTE (addonEnabled) Used in the output of the 'addon enable'
-# command when an addon is enabled.
+# command when an add-on is enabled.
 addonEnabled=%S enabled.
 
 # LOCALIZATION NOTE (addonDisableDesc) A very short description of the
 # 'addon disable <type>' command. This string is designed to be shown in a menu
 # alongside the command name, which is why it should be as short as possible.
 addonDisableDesc=Disable the specified add-on
 
 # LOCALIZATION NOTE (addonAlreadyDisabled) Used in the output of the
-# 'addon disable' command when an attempt is made to disable an addon is already
+# 'addon disable' command when an attempt is made to disable an add-on is already
 # disabled.
 addonAlreadyDisabled=%S is already disabled.
 
 # LOCALIZATION NOTE (addonDisabled) Used in the output of the 'addon disable'
-# command when an addon is disabled.
+# command when an add-on is disabled.
 addonDisabled=%S disabled.
 
 # LOCALIZATION NOTE (exportDesc) A very short description of the 'export'
 # command. This string is designed to be shown in a menu alongside the command
 # name, which is why it should be as short as possible.
 exportDesc=Export resources
 
 # LOCALIZATION NOTE (exportHtmlDesc) A very short description of the 'export
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -1263,16 +1263,17 @@ window[tabsontop="false"] richlistitem[t
 
 #socialUserDisplayName,
 #socialUserPortrait {
   cursor: pointer;
 }
 
 #socialUserDisplayName {
   -moz-appearance: none;
+  color: #fff;
   border: none;
   background-color: transparent;
   margin-top: 0;
   padding-top: 0;
   font-size: 130%;
   font-weight: bold;
 }
 
@@ -3414,18 +3415,16 @@ stack[anonid=browserStack][responsivemod
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
 }
 
 /* === end of social toolbar button === */
 
 /* === social toolbar provider menu  === */
 
 #social-statusarea-user {
-  background-color: white;
-  color: black;
   cursor: default;
   font-family: "lucida grande",tahoma,verdana,arial,sans-serif;
   font-size: 12px;
 }
 
 #social-statusarea-user-portrait {
   width: 32px;
   height: 32px;
@@ -3455,16 +3454,17 @@ stack[anonid=browserStack][responsivemod
   max-height: 600px;
   max-width: 400px;
 }
 
 #social-notification-panel .panel-arrowcontent {
   margin: -4px 0 0 0;
   padding: 0;
   border-radius: 0px;
+  background-color: white;
 }
 
 #social-notification-panel .panel-arrow[side="top"] {
   list-style-image: url("chrome://browser/skin/social/panelarrow-up.png");
   margin-top: -4px;
   margin-bottom: 3px;
   height: 21px;
 }
--- a/build/mobile/sutagent/android/DoCommand.java
+++ b/build/mobile/sutagent/android/DoCommand.java
@@ -102,30 +102,31 @@ public class DoCommand {
 
     String    currentDir = "/";
     String    sErrorPrefix = "##AGENT-WARNING## ";
     boolean bTraceOn = false;
 
     String ffxProvider = "org.mozilla.ffxcp";
     String fenProvider = "org.mozilla.fencp";
 
-    private final String prgVersion = "SUTAgentAndroid Version 1.10";
+    private final String prgVersion = "SUTAgentAndroid Version 1.11";
 
     public enum Command
         {
         RUN ("run"),
         EXEC ("exec"),
         EXECCWD ("execcwd"),
         ENVRUN ("envrun"),
         KILL ("kill"),
         PS ("ps"),
         DEVINFO ("info"),
         OS ("os"),
         ID ("id"),
         UPTIME ("uptime"),
+        UPTIMEMILLIS ("uptimemillis"),
         SETTIME ("settime"),
         SYSTIME ("systime"),
         SCREEN ("screen"),
         ROTATION ("rotation"),
         MEMORY ("memory"),
         POWER ("power"),
         PROCESS ("process"),
         GETAPPROOT ("getapproot"),
@@ -416,16 +417,18 @@ public class DoCommand {
                     strReturn += SUTAgentAndroid.sUniqueID;
                     strReturn += "\n";
                     strReturn += GetOSInfo();
                     strReturn += "\n";
                     strReturn += GetSystemTime();
                     strReturn += "\n";
                     strReturn += GetUptime();
                     strReturn += "\n";
+                    strReturn += GetUptimeMillis();
+                    strReturn += "\n";
                     strReturn += GetScreenInfo();
                     strReturn += "\n";
                     strReturn += GetRotationInfo();
                     strReturn += "\n";
                     strReturn += GetMemoryInfo();
                     strReturn += "\n";
                     strReturn += GetPowerInfo();
                     strReturn += "\n";
@@ -459,16 +462,20 @@ public class DoCommand {
                         case SYSTIME:
                             strReturn = GetSystemTime();
                             break;
 
                         case UPTIME:
                             strReturn = GetUptime();
                             break;
 
+                        case UPTIMEMILLIS:
+                            strReturn = GetUptimeMillis();
+                            break;
+
                         case MEMORY:
                             strReturn = GetMemoryInfo();
                             break;
 
                         case POWER:
                             strReturn += GetPowerInfo();
                             break;
 
@@ -2919,16 +2926,21 @@ private void CancelNotification()
             nSecs = (int)(lHold / 1000L);
             nMilliseconds = (int)(lHold % 1000);
             sRet = "" + nDays + " days " + nHours + " hours " + nMinutes + " minutes " + nSecs + " seconds " + nMilliseconds + " ms";
             }
 
         return (sRet);
         }
 
+    public String GetUptimeMillis()
+        {
+        return Long.toString(SystemClock.uptimeMillis());
+        }
+ 
     public String NewKillProc(String sProcId, OutputStream out)
         {
         String sRet = "";
 
         try
             {
             pProc = Runtime.getRuntime().exec("kill "+sProcId);
             RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
@@ -3766,16 +3778,17 @@ private void CancelNotification()
             "                               key=value pairs (comma separated)\n" +
             "kill [program name]          - kill program no path\n" +
             "killall                      - kill all processes started\n" +
             "ps                           - list of running processes\n" +
             "info                         - list of device info\n" +
             "        [os]                 - os version for device\n" +
             "        [id]                 - unique identifier for device\n" +
             "        [uptime]             - uptime for device\n" +
+            "        [uptimemillis]       - uptime for device in milliseconds\n" +
             "        [systime]            - current system time\n" +
             "        [screen]             - width, height and bits per pixel for device\n" +
             "        [memory]             - physical, free, available, storage memory\n" +
             "                               for device\n" +
             "        [processes]          - list of running processes see 'ps'\n" +
             "deadman timeout              - set the duration for the deadman timer\n" +
             "alrt [on/off]                - start or stop sysalert behavior\n" +
             "disk [arg]                   - prints disk space info\n" +
--- a/build/pymake/tests/vpath-directive.mk
+++ b/build/pymake/tests/vpath-directive.mk
@@ -1,13 +1,10 @@
-ifdef __WIN32__
-VPSEP = ;
-else
-VPSEP = :
-endif
+# On Windows, MSYS make takes Unix paths but Pymake takes Windows paths
+VPSEP := $(if $(and $(__WIN32__),$(.PYMAKE)),;,:)
 
 $(shell \
 mkdir subd1 subd2 subd3; \
 printf "reallybaddata" >subd1/foo.in; \
 printf "gooddata" >subd2/foo.in; \
 printf "baddata" >subd3/foo.in; \
 touch subd1/foo.in2 subd2/foo.in2 subd3/foo.in2; \
 )
--- a/build/virtualenv/packages.txt
+++ b/build/virtualenv/packages.txt
@@ -2,8 +2,10 @@ setup.py:other-licenses/simplejson-2.1.1
 setup.py:testing/mozbase/manifestdestiny:develop
 setup.py:testing/mozbase/mozinfo:develop
 setup.py:testing/mozbase/mozinstall:develop
 setup.py:testing/mozbase/mozlog:develop
 setup.py:testing/mozbase/mozprocess:develop
 setup.py:testing/mozbase/mozprofile:develop
 setup.py:testing/mozbase/mozrunner:develop
 setup.py:python/blessings:develop
+mozilla.pth:build
+mozilla.pth:config
--- a/build/virtualenv/populate_virtualenv.py
+++ b/build/virtualenv/populate_virtualenv.py
@@ -1,18 +1,20 @@
 # 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/.
 
 # This file contains code for populating the virtualenv environment for
 # Mozilla's build system. It is typically called as part of configure.
 
+from __future__ import with_statement
 import os.path
 import subprocess
 import sys
+import distutils.sysconfig
 
 def populate_virtualenv(top_source_directory, manifest_filename):
     """Populate the virtualenv from the contents of a manifest.
 
     The manifest file consists of colon-delimited fields. The first field
     specifies the action. The remaining fields are arguments to that action.
     The following actions are supported:
 
@@ -33,16 +35,21 @@ def populate_virtualenv(top_source_direc
     fh.close()
 
     for package in packages:
         if package[0] == 'setup.py':
             assert len(package) >= 2
 
             call_setup(os.path.join(top_source_directory, package[1]),
                 package[2:])
+        if package[0].endswith('.pth'):
+            assert len(package) == 2
+
+            with open(os.path.join(distutils.sysconfig.get_python_lib(), package[0]), 'a') as f:
+                f.write("%s\n" % os.path.join(top_source_directory, package[1]))
 
 def call_setup(directory, arguments):
     """Calls setup.py in a directory."""
     setup = os.path.join(directory, 'setup.py')
 
     program = [sys.executable, setup]
     program.extend(arguments)
 
--- a/config/Makefile.in
+++ b/config/Makefile.in
@@ -156,16 +156,17 @@ PYUNITS := \
   unit-Expression.py \
   unit-Preprocessor.py \
   unit-nsinstall.py \
   unit-printprereleasesuffix.py \
   unit-JarMaker.py \
   unit-buildlist.py \
   unit-expandlibs.py \
   unit-writemozinfo.py \
+  unit-mozunit.py \
   $(NULL)
 
 check-preqs = \
   check-python-modules \
   check-jar-mn \
   check-makefiles \
   $(NULL)
 
--- a/config/Preprocessor.py
+++ b/config/Preprocessor.py
@@ -121,21 +121,23 @@ class Preprocessor:
     if self.checkLineNumbers:
       self.writtenLines += 1
       ln = self.context['LINE']
       if self.writtenLines != ln:
         self.out.write('//@line %(line)d "%(file)s"%(le)s'%{'line': ln,
                                                             'file': self.context['FILE'],
                                                             'le': self.LE})
         self.writtenLines = ln
-    aLine = self.applyFilters(aLine)
+    filteredLine = self.applyFilters(aLine)
+    if filteredLine != aLine:
+      self.actionLevel = 2
     # ensure our line ending. Only need to handle \n, as we're reading
     # with universal line ending support, at least for files.
-    aLine = re.sub('\n', self.LE, aLine)
-    self.out.write(aLine)
+    filteredLine = re.sub('\n', self.LE, filteredLine)
+    self.out.write(filteredLine)
   
   def handleCommandLine(self, args, defaultToStdin = False):
     """
     Parse a commandline into this parser.
     Uses OptionParser internally, no args mean sys.argv[1:].
     """
     p = self.getCommandLineParser()
     (options, args) = p.parse_args(args=args)
--- a/config/mozunit.py
+++ b/config/mozunit.py
@@ -1,25 +1,28 @@
 # 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/.
 
 from unittest import TextTestRunner as _TestRunner, TestResult as _TestResult
+import unittest
 import inspect
+from StringIO import StringIO
+import os
 
 '''Helper to make python unit tests report the way that the Mozilla
 unit test infrastructure expects tests to report.
 
 Usage:
 
 import unittest
-from mozunit import MozTestRunner
+import mozunit
 
 if __name__ == '__main__':
-    unittest.main(testRunner=MozTestRunner())
+    mozunit.main()
 '''
 
 class _MozTestResult(_TestResult):
     def __init__(self, stream, descriptions):
         _TestResult.__init__(self)
         self.stream = stream
         self.descriptions = descriptions
 
@@ -63,8 +66,74 @@ class _MozTestResult(_TestResult):
 class MozTestRunner(_TestRunner):
     def _makeResult(self):
         return _MozTestResult(self.stream, self.descriptions)
     def run(self, test):
         result = self._makeResult()
         test(result)
         result.printErrorList()
         return result
+
+class MockedFile(StringIO):
+    def __init__(self, context, filename, content = ''):
+        self.context = context
+        self.name = filename
+        StringIO.__init__(self, content)
+
+    def close(self):
+        self.context.files[self.name] = self.getvalue()
+        StringIO.close(self)
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        self.close()
+
+class MockedOpen(object):
+    '''
+    Context manager diverting the open builtin such that opening files
+    can open "virtual" file instances given when creating a MockedOpen.
+
+    with MockedOpen({'foo': 'foo', 'bar': 'bar'}):
+        f = open('foo', 'r')
+
+    will thus open the virtual file instance for the file 'foo' to f.
+
+    MockedOpen also masks writes, so that creating or replacing files
+    doesn't touch the file system, while subsequently opening the file
+    will return the recorded content.
+
+    with MockedOpen():
+        f = open('foo', 'w')
+        f.write('foo')
+    self.assertRaises(Exception,f.open('foo', 'r'))
+    '''
+    def __init__(self, files = {}):
+        self.files = {}
+        for name, content in files.iteritems():
+            self.files[os.path.abspath(name)] = content
+
+    def __call__(self, name, mode = 'r'):
+        absname = os.path.abspath(name)
+        if 'w' in mode:
+            file = MockedFile(self, absname)
+        elif absname in self.files:
+            file = MockedFile(self, absname, self.files[absname])
+        elif 'a' in mode:
+            file = MockedFile(self, absname, self.open(name, 'r').read())
+        else:
+            file = self.open(name, mode)
+        if 'a' in mode:
+            file.seek(0, os.SEEK_END)
+        return file
+
+    def __enter__(self):
+        import __builtin__
+        self.open = __builtin__.open
+        __builtin__.open = self
+
+    def __exit__(self, type, value, traceback):
+        import __builtin__
+        __builtin__.open = self.open
+
+def main(*args):
+    unittest.main(testRunner=MozTestRunner(),*args)
--- a/config/tests/unit-Expression.py
+++ b/config/tests/unit-Expression.py
@@ -1,13 +1,13 @@
 import unittest
 
 import sys
 import os.path
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import mozunit
 
 from Expression import Expression, Context
 
 class TestContext(unittest.TestCase):
   """
   Unit tests for the Context class
   """
 
@@ -55,9 +55,9 @@ class TestExpression(unittest.TestCase):
     """ Test for the == operator"""
     self.assert_(Expression('FAIL == PASS').evaluate(self.c))
 
   def test_notequals(self):
     """ Test for the != operator"""
     self.assert_(Expression('FAIL != 1').evaluate(self.c))
 
 if __name__ == '__main__':
-  unittest.main()
+  mozunit.main()
--- a/config/tests/unit-JarMaker.py
+++ b/config/tests/unit-JarMaker.py
@@ -1,18 +1,16 @@
 import unittest
 
 import os, sys, os.path, time, inspect
 from filecmp import dircmp
 from tempfile import mkdtemp
 from shutil import rmtree, copy2
 from zipfile import ZipFile
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
-
-from mozunit import MozTestRunner
+import mozunit
 from JarMaker import JarMaker
 
 if sys.platform == "win32":
     import ctypes
     from ctypes import POINTER, WinError
     DWORD = ctypes.c_ulong
     LPDWORD = POINTER(DWORD)
     HANDLE = ctypes.c_void_p
@@ -275,9 +273,9 @@ class TestJarMaker(unittest.TestCase):
             open(os.path.join(ldir, relpath), 'w').write(relpath+" content\n")
         # call JarMaker
         difference = self._jar_and_compare(jars,
                                            (_mangle,),
                                            sourcedirs = [])
         self.assertTrue(not difference, difference)
 
 if __name__ == '__main__':
-    unittest.main(testRunner=MozTestRunner())
+    mozunit.main()
--- a/config/tests/unit-LineEndings.py
+++ b/config/tests/unit-LineEndings.py
@@ -1,15 +1,15 @@
 import unittest
 
 from StringIO import StringIO
 import os
 import sys
 import os.path
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import mozunit
 
 from Preprocessor import Preprocessor
 
 class TestLineEndings(unittest.TestCase):
   """
   Unit tests for the Context class
   """
 
@@ -38,9 +38,9 @@ class TestLineEndings(unittest.TestCase)
     self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
 
   def testWindows(self):
     self.createFile(['\x0D\x0A']*3)
     self.pp.do_include(self.tempnam)
     self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
 
 if __name__ == '__main__':
-  unittest.main()
+  mozunit.main()
--- a/config/tests/unit-Preprocessor.py
+++ b/config/tests/unit-Preprocessor.py
@@ -1,50 +1,23 @@
 from __future__ import with_statement
 import unittest
 
 from StringIO import StringIO
 import os
 import sys
 import os.path
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+from mozunit import main, MockedOpen
 
 from Preprocessor import Preprocessor
 
-class NamedIO(StringIO):
-  def __init__(self, name, content):
-    self.name = name
-    StringIO.__init__(self, content)
-
-class MockedOpen(object):
-  """
-  Context manager diverting the open builtin such that opening files
-  can open NamedIO instances given when creating a MockedOpen.
-
-  with MockedOpen(NamedIO('foo', 'foo'), NamedIO('bar', 'bar')):
-    f = open('foo', 'r')
-
-  will thus assign the NamedIO instance for the file 'foo' to f.
-  """
-  def __init__(self, *files):
-    self.files = {}
-    for f in files:
-      self.files[os.path.abspath(f.name)] = f
-  def __call__(self, name, args):
-    absname = os.path.abspath(name)
-    if absname in self.files:
-      return self.files[absname]
-    return self.open(name, args)
-  def __enter__(self):
-    import __builtin__
-    self.open = __builtin__.open
-    __builtin__.open = self
-  def __exit__(self, type, value, traceback):
-    import __builtin__
-    __builtin__.open = self.open
+def NamedIO(name, content):
+  with open(name, 'w') as f:
+    f.write(content)
+  return name
 
 class TestPreprocessor(unittest.TestCase):
   """
   Unit tests for the Context class
   """
 
   def setUp(self):
     self.pp = Preprocessor()
@@ -534,23 +507,23 @@ octal value is not equal
     try:
       self.pp.do_include(f)
     except Preprocessor.Error, exception:
       self.assertEqual(exception.key, 'UNDEFINED_VAR')
     else:
       self.fail("Expected a Preprocessor.Error")
 
   def test_include(self):
-    with MockedOpen(NamedIO("foo/test", """#define foo foobarbaz
+    with MockedOpen({"foo/test": """#define foo foobarbaz
 #include @inc@
 @bar@
-"""),
-                      NamedIO("bar", """#define bar barfoobaz
+""",
+                     "bar": """#define bar barfoobaz
 @foo@
-""")):
+"""}):
       f = NamedIO("include.in", """#filter substitution
 #define inc ../bar
 #include foo/test""")
       self.pp.do_include(f)
       self.assertEqual(self.pp.out.getvalue(), """foobarbaz
 barfoobaz
 """)
 
@@ -570,26 +543,26 @@ barfoobaz
     try:
       self.pp.do_include(f)
     except Preprocessor.Error, exception:
       self.assertEqual(exception.key, 'UNDEFINED_VAR')
     else:
       self.fail("Expected a Preprocessor.Error")
 
   def test_include_literal_at(self):
-    with MockedOpen(NamedIO("@foo@", "#define foo foobarbaz")):
+    with MockedOpen({"@foo@": "#define foo foobarbaz"}):
       f = NamedIO("include_literal_at.in", """#include @foo@
 #filter substitution
 @foo@
 """)
       self.pp.do_include(f)
       self.assertEqual(self.pp.out.getvalue(), """foobarbaz
 """)
 
   def test_command_line_literal_at(self):
-    with MockedOpen(NamedIO("@foo@.in", """@foo@
-""")):
+    with MockedOpen({"@foo@.in": """@foo@
+"""}):
       self.pp.handleCommandLine(['-Fsubstitution', '-Dfoo=foobarbaz', '@foo@.in'])
       self.assertEqual(self.pp.out.getvalue(), """foobarbaz
 """)
 
 if __name__ == '__main__':
-  unittest.main()
+  main()
--- a/config/tests/unit-buildlist.py
+++ b/config/tests/unit-buildlist.py
@@ -1,14 +1,14 @@
 import unittest
 
 import os, sys, os.path, time
 from tempfile import mkdtemp
 from shutil import rmtree
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import mozunit
 
 from buildlist import addEntriesToListFile
 
 class TestBuildList(unittest.TestCase):
   """
   Unit tests for buildlist.py
   """
   def setUp(self):
@@ -72,9 +72,9 @@ class TestBuildList(unittest.TestCase):
     only one entry being added."""
     testfile = os.path.join(self.tmpdir, "test.list")
     addEntriesToListFile(testfile, ["a","b","a","a","b"])
     self.assertFileContains(testfile, ["a","b"])
     addEntriesToListFile(testfile, ["c","a","c","b","c"])
     self.assertFileContains(testfile, ["a","b","c"])
 
 if __name__ == '__main__':
-  unittest.main()
+  mozunit.main()
--- a/config/tests/unit-expandlibs.py
+++ b/config/tests/unit-expandlibs.py
@@ -1,18 +1,17 @@
 from __future__ import with_statement
 import subprocess
 import unittest
 import sys
 import os
 import imp
 from tempfile import mkdtemp
 from shutil import rmtree
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
-from mozunit import MozTestRunner
+import mozunit
 
 from UserString import UserString
 # Create a controlled configuration for use by expandlibs
 config_win = {
     'AR_EXTRACT': '',
     'DLL_PREFIX': '',
     'LIB_PREFIX': '',
     'OBJ_SUFFIX': '.obj',
@@ -380,9 +379,9 @@ class TestSymbolOrder(unittest.TestCase)
         config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
         args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
         self.assertEqual(args._getOrderedSections(['hello', '_Z6barbazv']), ['.text.hi', '.text.hello', '.text.hot._Z6barbazv'])
         self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', 'hi', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hi', '.text.hello', '.text.hot._Z6barbazv'])
         subprocess.Popen = subprocess_popen
 
 
 if __name__ == '__main__':
-    unittest.main(testRunner=MozTestRunner())
+    mozunit.main()
new file mode 100644
--- /dev/null
+++ b/config/tests/unit-mozunit.py
@@ -0,0 +1,75 @@
+# 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/.
+
+from __future__ import with_statement
+import sys
+import os
+from mozunit import main, MockedOpen
+import unittest
+from tempfile import mkstemp
+
+class TestMozUnit(unittest.TestCase):
+    def test_mocked_open(self):
+        # Create a temporary file on the file system.
+        (fd, path) = mkstemp()
+        with os.fdopen(fd, 'w') as file:
+            file.write('foobar');
+
+        with MockedOpen({'file1': 'content1',
+                         'file2': 'content2'}):
+            # Check the contents of the files given at MockedOpen creation.
+            self.assertEqual(open('file1', 'r').read(), 'content1')
+            self.assertEqual(open('file2', 'r').read(), 'content2')
+
+            # Check that overwriting these files alters their content.
+            with open('file1', 'w') as file:
+                file.write('foo')
+            self.assertEqual(open('file1', 'r').read(), 'foo')
+
+            # ... but not until the file is closed.
+            file = open('file2', 'w')
+            file.write('bar')
+            self.assertEqual(open('file2', 'r').read(), 'content2')
+            file.close()
+            self.assertEqual(open('file2', 'r').read(), 'bar')
+
+            # Check that appending to a file does append
+            with open('file1', 'a') as file:
+                file.write('bar')
+            self.assertEqual(open('file1', 'r').read(), 'foobar')
+
+            # Opening a non-existing file ought to fail.
+            self.assertRaises(IOError, open, 'file3', 'r')
+
+            # Check that writing a new file does create the file.
+            with open('file3', 'w') as file:
+                file.write('baz')
+            self.assertEqual(open('file3', 'r').read(), 'baz')
+
+            # Check the content of the file created outside MockedOpen.
+            self.assertEqual(open(path, 'r').read(), 'foobar')
+
+            # Check that overwriting a file existing on the file system
+            # does modify its content.
+            with open(path, 'w') as file:
+                file.write('bazqux')
+            self.assertEqual(open(path, 'r').read(), 'bazqux')
+
+        with MockedOpen():
+            # Check that appending to a file existing on the file system
+            # does modify its content.
+            with open(path, 'a') as file:
+                file.write('bazqux')
+            self.assertEqual(open(path, 'r').read(), 'foobarbazqux')
+
+        # Check that the file was not actually modified on the file system.
+        self.assertEqual(open(path, 'r').read(), 'foobar')
+        os.remove(path)
+
+        # Check that the file created inside MockedOpen wasn't actually
+        # created.
+        self.assertRaises(IOError, open, 'file3', 'r')
+
+if __name__ == "__main__":
+    main()
--- a/config/tests/unit-nsinstall.py
+++ b/config/tests/unit-nsinstall.py
@@ -1,14 +1,14 @@
 import unittest
 
 import os, sys, os.path, time
 from tempfile import mkdtemp
 from shutil import rmtree
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import mozunit
 from mozprocess import processhandler
 
 from nsinstall import nsinstall
 import nsinstall as nsinstall_module
 NSINSTALL_PATH = nsinstall_module.__file__
 
 # Run the non-ASCII tests on (a) Windows, or (b) any platform with
 # sys.stdin.encoding set to UTF-8
@@ -165,9 +165,9 @@ class TestNsinstall(unittest.TestCase):
 
             self.assertEqual(rv, 0)
             destfile = os.path.join(testdir, filename)
             self.assert_(os.path.isfile(destfile))
 
     #TODO: implement -R, -l, -L and test them!
 
 if __name__ == '__main__':
-  unittest.main()
+  mozunit.main()
--- a/config/tests/unit-printprereleasesuffix.py
+++ b/config/tests/unit-printprereleasesuffix.py
@@ -1,13 +1,13 @@
 import unittest
 
 import sys
 import os.path
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import mozunit
 
 from printprereleasesuffix import get_prerelease_suffix
 
 class TestGetPreReleaseSuffix(unittest.TestCase):
   """
   Unit tests for the get_prerelease_suffix function
   """
 
@@ -72,9 +72,9 @@ class TestGetPreReleaseSuffix(unittest.T
     self.assertEqual(self.c, '')
 
   def test_plus(self):
     """test 1.2+ version string """
     self.c = get_prerelease_suffix('1.2+')
     self.assertEqual(self.c, '')
 
 if __name__ == '__main__':
-  unittest.main()
+  mozunit.main()
--- a/config/tests/unit-writemozinfo.py
+++ b/config/tests/unit-writemozinfo.py
@@ -1,15 +1,14 @@
 #!/usr/bin/env python
 from __future__ import with_statement
 import unittest
 import os, sys, time, tempfile
 from StringIO import StringIO
-
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import mozunit
 
 from writemozinfo import build_dict, write_json, JsonValue, jsonify
 
 class TestBuildDict(unittest.TestCase):
     def testMissing(self):
         """
         Test that missing required values raises.
         """
@@ -234,10 +233,9 @@ class TestWriteJson(unittest.TestCase):
                            'MOZ_WIDGET_TOOLKIT':'windows'})
         d = parse_json(s.getvalue())
         self.assertEqual('win', d['os'])
         self.assertEqual('x86', d['processor'])
         self.assertEqual('windows', d['toolkit'])
         self.assertEqual(32, d['bits'])
 
 if __name__ == '__main__':
-    unittest.main()
-  
+    mozunit.main()
--- a/configure.in
+++ b/configure.in
@@ -745,16 +745,19 @@ if test -n "$_WIN32_MSVC"; then
     SKIP_COMPILER_CHECKS=1
     SKIP_LIBRARY_CHECKS=1
 
     # Since we're skipping compiler and library checks, hard-code
     # some facts here.
     AC_DEFINE(HAVE_IO_H)
     AC_DEFINE(HAVE_SETBUF)
     AC_DEFINE(HAVE_ISATTY)
+    if test $_MSC_VER -ge 1600; then
+        AC_DEFINE(HAVE_NULLPTR)
+    fi
 fi
 
 fi # COMPILE_ENVIRONMENT
 
 AC_SUBST(MIDL_FLAGS)
 AC_SUBST(_MSC_VER)
 
 AC_SUBST(GNU_AS)
@@ -5585,17 +5588,17 @@ if test "$MOZ_GSTREAMER"; then
     # introduced
     GST_VERSION=0.10.33
     PKG_CHECK_MODULES(GSTREAMER,
                       gstreamer-$GST_API_VERSION >= $GST_VERSION
                       gstreamer-app-$GST_API_VERSION
                       gstreamer-plugins-base-$GST_API_VERSION)
     if test -n "$GSTREAMER_LIBS"; then
        _SAVE_LDFLAGS=$LDFLAGS
-       LDFLAGS="$LDFLAGS -lgstvideo-$GST_API_VERSION"
+       LDFLAGS="$LDFLAGS $GSTREAMER_LIBS -lgstvideo-$GST_API_VERSION"
        AC_TRY_LINK(,[return 0;],_HAVE_LIBGSTVIDEO=1,_HAVE_LIBGSTVIDEO=)
        if test -n "$_HAVE_LIBGSTVIDEO" ; then
           GSTREAMER_LIBS="$GSTREAMER_LIBS -lgstvideo-$GST_API_VERSION"
        else
           AC_MSG_ERROR([gstreamer video backend requires libgstvideo])
        fi
        LDFLAGS=$_SAVE_LDFLAGS
     else
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -36,16 +36,17 @@
 #include "nsIScriptChannel.h"
 #include "nsIBlocklistService.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIAppShell.h"
 
 #include "nsPluginError.h"
 
 // Util headers
+#include "prenv.h"
 #include "prlog.h"
 
 #include "nsAutoPtr.h"
 #include "nsCURILoader.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentUtils.h"
 #include "nsDocShellCID.h"
 #include "nsGkAtoms.h"
@@ -1215,19 +1216,26 @@ nsObjectLoadingContent::ObjectState() co
           state |= NS_EVENT_STATE_HANDLER_DISABLED;
           break;
         case ePluginBlocklisted:
           state |= NS_EVENT_STATE_HANDLER_BLOCKED;
           break;
         case ePluginCrashed:
           state |= NS_EVENT_STATE_HANDLER_CRASHED;
           break;
-        case ePluginUnsupported:
-          state |= NS_EVENT_STATE_TYPE_UNSUPPORTED;
+        case ePluginUnsupported: {
+          // Check to see if plugins are blocked on this platform.
+          char* pluginsBlocked = PR_GetEnv("MOZ_PLUGINS_BLOCKED");
+          if (pluginsBlocked && pluginsBlocked[0] == '1') {
+            state |= NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM;
+          } else {
+            state |= NS_EVENT_STATE_TYPE_UNSUPPORTED;
+          }
           break;
+        }
         case ePluginOutdated:
         case ePluginOtherState:
           // Do nothing, but avoid a compile warning
           break;
       }
       return state;
   };
   NS_NOTREACHED("unknown type?");
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1452,17 +1452,17 @@ nsXMLHttpRequest::GetAllResponseHeaders(
   nsCAutoString value;
   if (NS_SUCCEEDED(mChannel->GetContentType(value))) {
     aResponseHeaders.AppendLiteral("Content-Type: ");
     AppendASCIItoUTF16(value, aResponseHeaders);
     if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) && !value.IsEmpty()) {
       aResponseHeaders.AppendLiteral(";charset=");
       AppendASCIItoUTF16(value, aResponseHeaders);
     }
-    aResponseHeaders.Append('\n');
+    aResponseHeaders.AppendLiteral("\r\n");
   }
 }
 
 NS_IMETHODIMP
 nsXMLHttpRequest::GetResponseHeader(const nsACString& aHeader,
                                     nsACString& aResult)
 {
   ErrorResult rv;
@@ -3976,17 +3976,17 @@ nsHeaderVisitor::VisitHeader(const nsACS
     if (!chrome &&
          (header.LowerCaseEqualsASCII("set-cookie") ||
           header.LowerCaseEqualsASCII("set-cookie2"))) {
         NS_WARNING("blocked access to response header");
     } else {
         mHeaders.Append(header);
         mHeaders.Append(": ");
         mHeaders.Append(value);
-        mHeaders.Append('\n');
+        mHeaders.Append("\r\n");
     }
     return NS_OK;
 }
 
 // DOM event class to handle progress notifications
 nsXMLHttpProgressEvent::nsXMLHttpProgressEvent(nsIDOMProgressEvent* aInner,
                                                PRUint64 aCurrentProgress,
                                                PRUint64 aMaxProgress,
--- a/content/base/test/test_XHR.html
+++ b/content/base/test/test_XHR.html
@@ -43,17 +43,17 @@ for (i = 0; i < passFiles.length; ++i) {
   is(xhr.getResponseHeader("Content-Type"), null, "should be null");
   is(xhr.getAllResponseHeaders(), "", "should be empty string");
   is(xhr.responseType, "", "wrong initial responseType");
   xhr.open(passFiles[i][1], passFiles[i][0], false); 
   xhr.send(null);
   is(xhr.status, passFiles[i][2], "wrong status");
   is(xhr.getResponseHeader("Content-Type"), passFiles[i][3], "wrong content type");
   var headers = xhr.getAllResponseHeaders();
-  ok(/(?:^|\n)Content-Type:\s*([^\n]*)\n/i.test(headers) &&
+  ok(/(?:^|\n)Content-Type:\s*([^\r\n]*)\r\n/i.test(headers) &&
      RegExp.$1 === passFiles[i][3], "wrong response headers");
   if (xhr.responseXML) {
     is((new XMLSerializer()).serializeToString(xhr.responseXML.documentElement),
        passFiles[i][4] || "<res>hello</res>", "wrong responseXML");
     is(xhr.response, passFiles[i][4] || "<res>hello</res>\n", "wrong response");
   }
   else {
     is(xhr.responseText, passFiles[i][4] || "hello pass\n", "wrong responseText");
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -151,16 +151,17 @@ WebGLContext::WebGLContext()
     mAllowRestore = true;
     mContextLossTimerRunning = false;
     mDrawSinceContextLossTimerSet = false;
     mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
     mContextStatus = ContextStable;
     mContextLostErrorSet = false;
 
     mAlreadyGeneratedWarnings = 0;
+    mAlreadyWarnedAboutFakeVertexAttrib0 = false;
 }
 
 WebGLContext::~WebGLContext()
 {
     DestroyResourcesAndContext();
     WebGLMemoryMultiReporterWrapper::RemoveWebGLContext(this);
     TerminateContextLossTimer();
     mContextRestorer = nsnull;
@@ -928,19 +929,27 @@ WebGLContext::GetExtension(const nsAStri
             ext = OES_texture_float;
     }
     else if (aName.Equals(NS_LITERAL_STRING("OES_standard_derivatives"),
              nsCaseInsensitiveStringComparator()))
     {
         if (IsExtensionSupported(OES_standard_derivatives))
             ext = OES_standard_derivatives;
     }
+    else if (aName.Equals(NS_LITERAL_STRING("EXT_texture_filter_anisotropic"),
+             nsCaseInsensitiveStringComparator()))
+    {
+        if (IsExtensionSupported(EXT_texture_filter_anisotropic))
+            ext = EXT_texture_filter_anisotropic;
+    }
     else if (aName.Equals(NS_LITERAL_STRING("MOZ_EXT_texture_filter_anisotropic"),
              nsCaseInsensitiveStringComparator()))
     {
+        GenerateWarning("MOZ_EXT_texture_filter_anisotropic has been renamed to EXT_texture_filter_anisotropic. "
+                        "Support for the MOZ_-prefixed string will be removed very soon.");
         if (IsExtensionSupported(EXT_texture_filter_anisotropic))
             ext = EXT_texture_filter_anisotropic;
     }
     else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"),
              nsCaseInsensitiveStringComparator()))
     {
         if (IsExtensionSupported(WEBGL_lose_context))
             ext = WEBGL_lose_context;
@@ -1533,18 +1542,20 @@ WebGLContext::GetSupportedExtensions(Nul
     }
 
     nsTArray<nsString>& arr = retval.SetValue();
     
     if (IsExtensionSupported(OES_texture_float))
         arr.AppendElement(NS_LITERAL_STRING("OES_texture_float"));
     if (IsExtensionSupported(OES_standard_derivatives))
         arr.AppendElement(NS_LITERAL_STRING("OES_standard_derivatives"));
-    if (IsExtensionSupported(EXT_texture_filter_anisotropic))
+    if (IsExtensionSupported(EXT_texture_filter_anisotropic)) {
+        arr.AppendElement(NS_LITERAL_STRING("EXT_texture_filter_anisotropic"));
         arr.AppendElement(NS_LITERAL_STRING("MOZ_EXT_texture_filter_anisotropic"));
+    }
     if (IsExtensionSupported(WEBGL_lose_context))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
     if (IsExtensionSupported(WEBGL_compressed_texture_s3tc))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
 }
 
 NS_IMETHODIMP
 WebGLContext::IsContextLost(WebGLboolean *retval)
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -1354,16 +1354,17 @@ protected:
     nsCOMPtr<nsITimer> mContextRestorer;
     bool mAllowRestore;
     bool mContextLossTimerRunning;
     bool mDrawSinceContextLossTimerSet;
     ContextStatus mContextStatus;
     bool mContextLostErrorSet;
 
     int mAlreadyGeneratedWarnings;
+    bool mAlreadyWarnedAboutFakeVertexAttrib0;
 
     bool ShouldGenerateWarnings() const {
         return mAlreadyGeneratedWarnings < 32;
     }
 
 #ifdef XP_MACOSX
     // see bug 713305. This RAII helper guarantees that we're on the discrete GPU, during its lifetime
     // Debouncing note: we don't want to switch GPUs too frequently, so try to not create and destroy
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -437,16 +437,19 @@ GLenum WebGLContext::CheckedBufferData(G
         return LOCAL_GL_NO_ERROR;
     }
 }
 
 NS_IMETHODIMP
 WebGLContext::BufferData(WebGLenum target, const JS::Value& data, GLenum usage,
                          JSContext* cx)
 {
+    if (!IsContextStable())
+        return NS_OK;
+
     if (data.isNull()) {
         BufferData(target, static_cast<ArrayBuffer*>(nsnull), usage);
         return NS_OK;
     }
 
     if (data.isObject()) {
         JSObject& dataObj = data.toObject();
         if (JS_IsArrayBufferObject(&dataObj, cx)) {
@@ -1520,18 +1523,27 @@ WebGLContext::WhatDoesVertexAttrib0Need(
 bool
 WebGLContext::DoFakeVertexAttrib0(WebGLuint vertexCount)
 {
     int whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
 
     if (whatDoesAttrib0Need == VertexAttrib0Status::Default)
         return true;
 
+    if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
+        GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
+                        "to do expensive emulation work when running on desktop OpenGL "
+                        "platforms, for example on Mac. It is preferable to always draw "
+                        "with vertex attrib 0 array enabled, by using bindAttribLocation "
+                        "to bind some always-used attribute to location 0.");
+        mAlreadyWarnedAboutFakeVertexAttrib0 = true;
+    }
+
     CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(WebGLfloat);
-    
+
     if (!checked_dataSize.isValid()) {
         ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
                          "with %d vertices. Try reducing the number of vertices.", vertexCount);
         return false;
     }
     
     WebGLuint dataSize = checked_dataSize.value();
 
@@ -5017,19 +5029,23 @@ WebGLContext::CompileShader(WebGLShader 
                 shader->mUniforms.AppendElement(WebGLMappedIdentifier(
                                                     nsDependentCString(uniform_name),
                                                     nsDependentCString(mapped_name)));
             }
 
             // we always query uniform info, regardless of useShaderSourceTranslation,
             // as we need it to validate uniform setter calls, and it doesn't rely on
             // shader translation.
+            char mappedNameLength = strlen(mapped_name);
+            char mappedNameLastChar = mappedNameLength > 1
+                                      ? mapped_name[mappedNameLength - 1]
+                                      : 0;
             shader->mUniformInfos.AppendElement(WebGLUniformInfo(
                                                     size,
-                                                    length > 1 && mapped_name[length - 1] == ']',
+                                                    mappedNameLastChar == ']',
                                                     type));
         }
 
         if (useShaderSourceTranslation) {
 
             for (int i = 0; i < num_attributes; i++) {
                 int length, size;
                 ShDataType type;
--- a/content/events/public/nsEventStates.h
+++ b/content/events/public/nsEventStates.h
@@ -241,16 +241,18 @@ private:
 // Content is in the suboptimal region.
 #define NS_EVENT_STATE_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(38)
 // Content is in the sub-suboptimal region.
 #define NS_EVENT_STATE_SUB_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(39)
 // Handler for click to play plugin (vulnerable w/update)
 #define NS_EVENT_STATE_VULNERABLE_UPDATABLE NS_DEFINE_EVENT_STATE_MACRO(40)
 // Handler for click to play plugin (vulnerable w/no update)
 #define NS_EVENT_STATE_VULNERABLE_NO_UPDATE NS_DEFINE_EVENT_STATE_MACRO(41)
+// Platform does not support plugin content (some mobile platforms)
+#define NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM NS_DEFINE_EVENT_STATE_MACRO(42)
 
 /**
  * NOTE: do not go over 63 without updating nsEventStates::InternalType!
  */
 
 #define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS |     \
                             NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER |   \
                             NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -31,18 +31,16 @@ CPPSRCS		= \
 		nsDOMUIEvent.cpp \
 		nsDOMKeyboardEvent.cpp \
 		nsDOMTextEvent.cpp \
 		nsDOMMouseEvent.cpp \
 		nsDOMMouseScrollEvent.cpp \
 		nsDOMDragEvent.cpp \
 		nsDOMMutationEvent.cpp \
 		nsDOMPopupBlockedEvent.cpp \
-		nsDOMDeviceLightEvent.cpp \
-		nsDOMDeviceOrientationEvent.cpp \
 		nsDOMDeviceMotionEvent.cpp \
 		nsDOMBeforeUnloadEvent.cpp \
 		nsDOMXULCommandEvent.cpp \
 		nsDOMCommandEvent.cpp \
 		nsDOMMessageEvent.cpp \
 		nsPaintRequest.cpp \
 		nsPrivateTextRange.cpp \
 		nsXMLEventsManager.cpp \
@@ -60,17 +58,16 @@ CPPSRCS		= \
 		nsDOMMozTouchEvent.cpp \
 		nsDOMEventTargetHelper.cpp \
 		nsDOMScrollAreaEvent.cpp \
 		nsDOMTransitionEvent.cpp \
 		nsDOMAnimationEvent.cpp \
 		nsDOMSettingsEvent.cpp \
 		nsDOMTouchEvent.cpp \
 		nsDOMCompositionEvent.cpp \
-		nsDOMApplicationEvent.cpp \
 		$(NULL)
 
 ifdef MOZ_B2G_RIL
 CPPSRCS += \
     nsDOMWifiEvent.cpp \
     $(NULL)
 endif
 
deleted file mode 100644
--- a/content/events/src/nsDOMApplicationEvent.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
- 
-#include "nsDOMApplicationEvent.h"
-#include "nsContentUtils.h"
-#include "DictionaryHelpers.h"
-#include "nsDOMClassInfoID.h"
- 
-DOMCI_DATA(MozApplicationEvent, nsDOMMozApplicationEvent)
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMozApplicationEvent)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplication)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplication)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMMozApplicationEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMozApplicationEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozApplicationEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
- 
-NS_IMPL_ADDREF_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
- 
-NS_IMETHODIMP
-nsDOMMozApplicationEvent::GetApplication(mozIDOMApplication** aApplication)
-{
-  NS_IF_ADDREF(*aApplication = mApplication);
-  return NS_OK;
-}
- 
-NS_IMETHODIMP
-nsDOMMozApplicationEvent::InitMozApplicationEvent(const nsAString& aType,
-                                                  bool aCanBubble,
-                                                  bool aCancelable,
-                                                  mozIDOMApplication* aApplication)
-{
-  nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
-  NS_ENSURE_SUCCESS(rv, rv);
- 
-  mApplication = aApplication;
-
-  return NS_OK;
-}
- 
-nsresult
-nsDOMMozApplicationEvent::InitFromCtor(const nsAString& aType, JSContext* aCx, jsval* aVal)
-{
-  mozilla::dom::MozApplicationEventInit d;
-  nsresult rv = d.Init(aCx, aVal);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return InitMozApplicationEvent(aType, d.bubbles, d.cancelable, d.application);
-}
- 
-nsresult
-NS_NewDOMMozApplicationEvent(nsIDOMEvent** aInstancePtrResult,
-                             nsPresContext* aPresContext,
-                             nsEvent* aEvent)
-{
-  nsDOMMozApplicationEvent* e = new nsDOMMozApplicationEvent(aPresContext, aEvent);
-  return CallQueryInterface(e, aInstancePtrResult);
-}
deleted file mode 100644
--- a/content/events/src/nsDOMApplicationEvent.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
- 
-#ifndef nsDOMApplicationEvent_h__
-#define nsDOMApplicationEvent_h__
- 
-#include "nsIDOMApplicationRegistry.h"
-#include "nsDOMEvent.h"
- 
-class nsDOMMozApplicationEvent : public nsDOMEvent,
-                                 public nsIDOMMozApplicationEvent
-{
-public:
-  nsDOMMozApplicationEvent(nsPresContext* aPresContext, nsEvent* aEvent)
-    : nsDOMEvent(aPresContext, aEvent) {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
-  // Forward to base class
-  NS_FORWARD_TO_NSDOMEVENT
- 
-  NS_DECL_NSIDOMMOZAPPLICATIONEVENT
- 
-  virtual nsresult InitFromCtor(const nsAString& aType, JSContext* aCx, jsval* aVal);
-
-private:
-  nsCOMPtr<mozIDOMApplication> mApplication;
-};
- 
-#endif // nsDOMContactChangeEvent_h__
\ No newline at end of file
deleted file mode 100644
--- a/content/events/src/nsDOMDeviceLightEvent.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* 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/. */
-
-#include "nsDOMClassInfoID.h"
-#include "nsDOMDeviceLightEvent.h"
-#include "DictionaryHelpers.h"
-
-NS_IMPL_ADDREF_INHERITED(nsDOMDeviceLightEvent, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMDeviceLightEvent, nsDOMEvent)
-
-DOMCI_DATA(DeviceLightEvent, nsDOMDeviceLightEvent)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMDeviceLightEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceLightEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceLightEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
-
-NS_IMETHODIMP
-nsDOMDeviceLightEvent::InitDeviceLightEvent(const nsAString & aEventTypeArg,
-                                            bool aCanBubbleArg,
-                                            bool aCancelableArg,
-                                            double aValue)
-{
-  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mValue = aValue;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMDeviceLightEvent::GetValue(double *aValue)
-{
-  NS_ENSURE_ARG_POINTER(aValue);
-  *aValue = mValue;
-  return NS_OK;
-}
-
-nsresult
-nsDOMDeviceLightEvent::InitFromCtor(const nsAString& aType,
-                                    JSContext* aCx, jsval* aVal)
-{
-  mozilla::dom::DeviceLightEventInit d;
-  nsresult rv = d.Init(aCx, aVal);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return InitDeviceLightEvent(aType, d.bubbles, d.cancelable, d.value);
-}
-
-nsresult
-NS_NewDOMDeviceLightEvent(nsIDOMEvent** aInstancePtrResult,
-                          nsPresContext* aPresContext,
-                          nsEvent *aEvent) 
-{
-  NS_ENSURE_ARG_POINTER(aInstancePtrResult);
-  nsDOMDeviceLightEvent* it = new nsDOMDeviceLightEvent(aPresContext, aEvent);
-  return CallQueryInterface(it, aInstancePtrResult);
-}
deleted file mode 100644
--- a/content/events/src/nsDOMDeviceLightEvent.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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/. */
-
-#ifndef nsDOMDeviceLightEvent_h__
-#define nsDOMDeviceLightEvent_h__
-
-#include "nsIDOMDeviceLightEvent.h"
-#include "nsDOMEvent.h"
-
-class nsDOMDeviceLightEvent
- : public nsDOMEvent
- , public nsIDOMDeviceLightEvent
-{
-public:
-
-  nsDOMDeviceLightEvent(nsPresContext* aPresContext, nsEvent* aEvent)
-  : nsDOMEvent(aPresContext, aEvent),
-    mValue(0) {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // Forward to nsDOMEvent
-  NS_FORWARD_TO_NSDOMEVENT
-
-  // nsIDOMDeviceLightEvent Interface
-  NS_DECL_NSIDOMDEVICELIGHTEVENT
-
-  virtual nsresult InitFromCtor(const nsAString& aType,
-                                JSContext* aCx,
-                                jsval* aVal);
-protected:
-  double mValue;
-};
-
-#endif
deleted file mode 100644
--- a/content/events/src/nsDOMDeviceOrientationEvent.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/* 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/. */
-
-#include "nsDOMClassInfoID.h"
-#include "nsDOMDeviceOrientationEvent.h"
-
-NS_IMPL_ADDREF_INHERITED(nsDOMDeviceOrientationEvent, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMDeviceOrientationEvent, nsDOMEvent)
-
-DOMCI_DATA(DeviceOrientationEvent, nsDOMDeviceOrientationEvent)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMDeviceOrientationEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceOrientationEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceOrientationEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::InitDeviceOrientationEvent(const nsAString & aEventTypeArg,
-                                                                      bool aCanBubbleArg,
-                                                                      bool aCancelableArg,
-                                                                      double aAlpha,
-                                                                      double aBeta,
-                                                                      double aGamma,
-                                                                      bool aAbsolute)
-{
-  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mAlpha = aAlpha;
-  mBeta = aBeta;
-  mGamma = aGamma;
-  mAbsolute = aAbsolute;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetAlpha(double *aAlpha)
-{
-  NS_ENSURE_ARG_POINTER(aAlpha);
-
-  *aAlpha = mAlpha;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetBeta(double *aBeta)
-{
-  NS_ENSURE_ARG_POINTER(aBeta);
-
-  *aBeta = mBeta;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetGamma(double *aGamma)
-{
-  NS_ENSURE_ARG_POINTER(aGamma);
-
-  *aGamma = mGamma;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetAbsolute(bool *aAbsolute)
-{
-  NS_ENSURE_ARG_POINTER(aAbsolute);
-
-  *aAbsolute = mAbsolute;
-  return NS_OK;
-}
-
-nsresult NS_NewDOMDeviceOrientationEvent(nsIDOMEvent** aInstancePtrResult,
-                                         nsPresContext* aPresContext,
-                                         nsEvent *aEvent) 
-{
-  NS_ENSURE_ARG_POINTER(aInstancePtrResult);
-
-  nsDOMDeviceOrientationEvent* it = new nsDOMDeviceOrientationEvent(aPresContext, aEvent);
-  if (nsnull == it) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  return CallQueryInterface(it, aInstancePtrResult);
-}
deleted file mode 100644
--- a/content/events/src/nsDOMDeviceOrientationEvent.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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/. */
-
-#ifndef nsDOMDeviceOrientationEvent_h__
-#define nsDOMDeviceOrientationEvent_h__
-
-#include "nsIDOMDeviceOrientationEvent.h"
-#include "nsDOMEvent.h"
-
-class nsDOMDeviceOrientationEvent : public nsDOMEvent,
-                                    public nsIDOMDeviceOrientationEvent
-{
-public:
-
-  nsDOMDeviceOrientationEvent(nsPresContext* aPresContext, nsEvent* aEvent)
-  : nsDOMEvent(aPresContext, aEvent),
-    mAlpha(0),
-    mBeta(0),
-    mGamma(0),
-    mAbsolute(true) {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // Forward to nsDOMEvent
-  NS_FORWARD_TO_NSDOMEVENT
-
-  // nsIDOMDeviceOrientationEvent Interface
-  NS_DECL_NSIDOMDEVICEORIENTATIONEVENT
-
-protected:
-  double mAlpha, mBeta, mGamma;
-  bool mAbsolute;
-};
-
-#endif
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -420,16 +420,34 @@ is(receivedEvent, e, "Wrong event!");
 // DeviceLightEvent
 e = new DeviceLightEvent("hello", {value: 1} );
 ok(e.type, "hello", "Wrong event type!");
 ok(!e.isTrusted, "Event should not be trusted");
 is(e.value, 1, "value should be 1");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
+// DeviceOrientationEvent
+e = new DeviceOrientationEvent("hello");
+ok(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event should not be trusted");
+is(e.alpha, 0);
+is(e.beta, 0);
+is(e.gamma, 0);
+is(e.absolute, false);
+
+e = new DeviceOrientationEvent("hello", { alpha: 1, beta: 2, gamma: 3, absolute: true } );
+ok(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event should not be trusted");
+is(e.alpha, 1);
+is(e.beta, 2);
+is(e.gamma, 3);
+is(e.absolute, true);
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
 
 // MouseEvent
 
 try {
   e = new MouseEvent();
 } catch(exp) {
   ex = true;
 }
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -758,21 +758,32 @@ ChannelMediaResource::CacheClientSeek(PR
   CloseChannel();
 
   if (aResume) {
     NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
     // No need to mess with the channel, since we're making a new one
     --mSuspendCount;
   }
 
+  mOffset = aOffset;
+
+  if (mSuspendCount > 0) {
+    // Close the existing channel to force the channel to be recreated at
+    // the correct offset upon resume.
+    if (mChannel) {
+      mIgnoreClose = true;
+      CloseChannel();
+    }
+    return NS_OK;
+  }
+
   nsresult rv = RecreateChannel();
   if (NS_FAILED(rv))
     return rv;
 
-  mOffset = aOffset;
   return OpenChannel(nsnull);
 }
 
 nsresult
 ChannelMediaResource::CacheClientSuspend()
 {
   Suspend(false);
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -293,18 +293,16 @@
 #include "nsIDOMMozCSSKeyframesRule.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsDOMCSSValueList.h"
 #define MOZ_GENERATED_EVENTS_INCLUDES
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENTS_INCLUDES
-#include "nsIDOMDeviceLightEvent.h"
-#include "nsIDOMDeviceOrientationEvent.h"
 #include "nsIDOMDeviceMotionEvent.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMNodeIterator.h"
 #include "nsIDOMTreeWalker.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIDOMCrypto.h"
@@ -810,30 +808,24 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(DragEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(KeyboardEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CompositionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PopupBlockedEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  // Device Light
-  NS_DEFINE_CLASSINFO_DATA(DeviceLightEvent, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface)                \
   NS_DEFINE_CLASSINFO_DATA(_event_interface, nsDOMGenericSH, \
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
 
-  // Device Orientation
-  NS_DEFINE_CLASSINFO_DATA(DeviceOrientationEvent, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceMotionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceRotationRate, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // Misc HTML classes
@@ -1636,18 +1628,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(MediaQueryList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MutationObserver, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MutationRecord, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozSettingsEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(MozApplicationEvent, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 #ifdef MOZ_B2G_RIL
   NS_DEFINE_CLASSINFO_DATA(MozWifiStatusChangeEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozWifiConnectionInfoEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
@@ -1722,20 +1712,18 @@ static const nsContractIDMapData kConstr
     nsIDOMEvent* e = nsnull;                                \
     nsresult rv = NS_NewDOM##_class(&e, nsnull, nsnull);    \
     *aInstancePtrResult = e;                                \
     return rv;                                              \
   }
 
 NS_DEFINE_EVENT_CTOR(Event)
 NS_DEFINE_EVENT_CTOR(MozSettingsEvent)
-NS_DEFINE_EVENT_CTOR(MozApplicationEvent)
 NS_DEFINE_EVENT_CTOR(UIEvent)
 NS_DEFINE_EVENT_CTOR(MouseEvent)
-NS_DEFINE_EVENT_CTOR(DeviceLightEvent)
 #ifdef MOZ_B2G_RIL
 NS_DEFINE_EVENT_CTOR(MozWifiStatusChangeEvent)
 NS_DEFINE_EVENT_CTOR(MozWifiConnectionInfoEvent)
 #endif
 
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CTOR(_event_interface)
@@ -1770,20 +1758,18 @@ struct nsConstructorFuncMapData
 
 static const nsConstructorFuncMapData kConstructorFuncMap[] =
 {
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, nsDOMMultipartFile::NewBlob)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFileFile::NewFile)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozSettingsEvent)
-  NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozApplicationEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
-  NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(DeviceLightEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(StorageEvent)
 #ifdef MOZ_B2G_RIL
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozWifiStatusChangeEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozWifiConnectionInfoEvent)
 #endif
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(_event_interface)
@@ -2595,35 +2581,25 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(PopupBlockedEvent, nsIDOMPopupBlockedEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPopupBlockedEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(DeviceLightEvent, nsIDOMDeviceLightEvent)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceLightEvent)
-    DOM_CLASSINFO_EVENT_MAP_ENTRIES
-  DOM_CLASSINFO_MAP_END
-
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface)                         \
   DOM_CLASSINFO_MAP_BEGIN(_event_interface, nsIDOM##_event_interface) \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM##_event_interface)                 \
     DOM_CLASSINFO_EVENT_MAP_ENTRIES                                   \
   DOM_CLASSINFO_MAP_END
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
 
-  DOM_CLASSINFO_MAP_BEGIN(DeviceOrientationEvent, nsIDOMDeviceOrientationEvent)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceOrientationEvent)
-    DOM_CLASSINFO_EVENT_MAP_ENTRIES
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(DeviceMotionEvent, nsIDOMDeviceMotionEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceMotionEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DeviceAcceleration, nsIDOMDeviceAcceleration)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceAcceleration)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
@@ -4404,21 +4380,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMutationRecord)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozSettingsEvent, nsIDOMMozSettingsEvent)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSettingsEvent)
      DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(MozApplicationEvent, nsIDOMMozApplicationEvent)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozApplicationEvent)
-    DOM_CLASSINFO_EVENT_MAP_ENTRIES
-  DOM_CLASSINFO_MAP_END
-
 #ifdef MOZ_B2G_RIL
   DOM_CLASSINFO_MAP_BEGIN(MozWifiStatusChangeEvent, nsIDOMMozWifiStatusChangeEvent)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozWifiStatusChangeEvent)
      DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozWifiConnectionInfoEvent, nsIDOMMozWifiConnectionInfoEvent)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozWifiConnectionInfoEvent)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -38,22 +38,20 @@ DOMCI_CLASS(Event)
 DOMCI_CLASS(MutationEvent)
 DOMCI_CLASS(UIEvent)
 DOMCI_CLASS(MouseEvent)
 DOMCI_CLASS(MouseScrollEvent)
 DOMCI_CLASS(DragEvent)
 DOMCI_CLASS(KeyboardEvent)
 DOMCI_CLASS(CompositionEvent)
 DOMCI_CLASS(PopupBlockedEvent)
-DOMCI_CLASS(DeviceLightEvent)
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) DOMCI_CLASS(_event_interface)
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
-DOMCI_CLASS(DeviceOrientationEvent)
 DOMCI_CLASS(DeviceMotionEvent)
 DOMCI_CLASS(DeviceAcceleration)
 DOMCI_CLASS(DeviceRotationRate)
 
 // HTML classes
 DOMCI_CLASS(HTMLDocument)
 DOMCI_CLASS(HTMLOptionsCollection)
 DOMCI_CLASS(HTMLCollection)
@@ -504,18 +502,16 @@ DOMCI_CLASS(MozCSSKeyframesRule)
 
 DOMCI_CLASS(MediaQueryList)
 
 DOMCI_CLASS(MutationObserver)
 DOMCI_CLASS(MutationRecord)
 
 DOMCI_CLASS(MozSettingsEvent)
 
-DOMCI_CLASS(MozApplicationEvent)
-
 #ifdef MOZ_B2G_RIL
 DOMCI_CLASS(MozWifiStatusChangeEvent)
 DOMCI_CLASS(MozWifiConnectionInfoEvent)
 DOMCI_CLASS(Telephony)
 DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
 DOMCI_CLASS(MozVoicemail)
 DOMCI_CLASS(MozVoicemailEvent)
--- a/dom/contacts/fallback/ContactService.jsm
+++ b/dom/contacts/fallback/ContactService.jsm
@@ -62,16 +62,17 @@ let DOMContactManager = {
     this._messages = null;
     if (this._db)
       this._db.close();
     this._db = null;
   },
 
   receiveMessage: function(aMessage) {
     debug("Fallback DOMContactManager::receiveMessage " + aMessage.name);
+    let mm = aMessage.target.QueryInterface(Ci.nsIFrameMessageManager);
     let msg = aMessage.json;
 
     /*
      * Sorting the contacts by sortBy field. sortBy can either be familyName or givenName.
      * If 2 entries have the same sortyBy field or no sortBy field is present, we continue 
      * sorting with the other sortyBy field.
      */
     function sortfunction(a, b){
@@ -119,37 +120,37 @@ let DOMContactManager = {
             if (msg.findOptions.sortOrder !== 'undefined' && msg.findOptions.sortBy !== 'undefined') {
               debug('sortBy: ' + msg.findOptions.sortBy + ', sortOrder: ' + msg.findOptions.sortOrder );
               result.sort(sortfunction);
               if (msg.findOptions.filterLimit)
                 result = result.slice(0, msg.findOptions.filterLimit);
             }
 
             debug("result:" + JSON.stringify(result));
-            ppmm.sendAsyncMessage("Contacts:Find:Return:OK", {requestID: msg.requestID, contacts: result});
+            mm.sendAsyncMessage("Contacts:Find:Return:OK", {requestID: msg.requestID, contacts: result});
           }.bind(this),
-          function(aErrorMsg) { ppmm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }) }.bind(this),
+          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }) }.bind(this),
           msg.findOptions);
         break;
       case "Contact:Save":
         this._db.saveContact(
           msg.contact, 
-          function() { ppmm.sendAsyncMessage("Contact:Save:Return:OK", { requestID: msg.requestID, contactID: msg.contact.id }); }.bind(this),
-          function(aErrorMsg) { ppmm.sendAsyncMessage("Contact:Save:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
+          function() { mm.sendAsyncMessage("Contact:Save:Return:OK", { requestID: msg.requestID, contactID: msg.contact.id }); }.bind(this),
+          function(aErrorMsg) { mm.sendAsyncMessage("Contact:Save:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
         );
         break;
       case "Contact:Remove":
         this._db.removeContact(
           msg.id, 
-          function() { ppmm.sendAsyncMessage("Contact:Remove:Return:OK", { requestID: msg.requestID, contactID: msg.id }); }.bind(this),
-          function(aErrorMsg) { ppmm.sendAsyncMessage("Contact:Remove:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
+          function() { mm.sendAsyncMessage("Contact:Remove:Return:OK", { requestID: msg.requestID, contactID: msg.id }); }.bind(this),
+          function(aErrorMsg) { mm.sendAsyncMessage("Contact:Remove:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
         );
         break;
       case "Contacts:Clear":
         this._db.clear(
-          function() { ppmm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID }); }.bind(this),
-          function(aErrorMsg) { ppmm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
+          function() { mm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID }); }.bind(this),
+          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
         );
     }
   }
 }
 
 DOMContactManager.init();
--- a/dom/contacts/tests/Makefile.in
+++ b/dom/contacts/tests/Makefile.in
@@ -11,12 +11,13 @@ relativesrcdir   = dom/contacts/tests
 
 include $(DEPTH)/config/autoconf.mk
 
 DIRS = \
   $(NULL)
 
 MOCHITEST_FILES = \
   test_contacts_basics.html \
+  test_contacts_events.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
--- a/dom/interfaces/apps/Makefile.in
+++ b/dom/interfaces/apps/Makefile.in
@@ -12,11 +12,12 @@ include $(DEPTH)/config/autoconf.mk
 
 MODULE         = dom
 XPIDL_MODULE   = dom_apps
 GRE_MODULE     = 1
 
 XPIDLSRCS =                               \
             nsIDOMApplicationRegistry.idl \
             nsIAppsService.idl \
+            nsIDOMMozApplicationEvent.idl \
             $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl
+++ b/dom/interfaces/apps/nsIDOMApplicationRegistry.idl
@@ -1,14 +1,13 @@
 /* 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/. */
 
 #include "domstubs.idl"
-#include "nsIDOMEvent.idl"
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMDOMRequest;
 interface nsIArray;
 
 [scriptable, uuid(9583b825-46b1-4e8f-bb48-9fed660a95e6)]
 interface mozIDOMApplication  : nsISupports
 {
@@ -38,32 +37,16 @@ interface mozIDOMApplication  : nsISuppo
    */
   attribute nsIDOMEventListener onprogress;
 
   /* startPoint will be used when several launch_path exists for an app */
   nsIDOMDOMRequest launch([optional] in DOMString startPoint);
   nsIDOMDOMRequest uninstall();
 };
 
-[scriptable, builtinclass, uuid(8f2bfba8-f10e-4f63-a5e0-7a7056e1dbe6)]
-interface nsIDOMMozApplicationEvent : nsIDOMEvent
-{
-  readonly attribute mozIDOMApplication application;
-
-  [noscript] void initMozApplicationEvent(in DOMString aType,
-                                          in boolean aCanBubble,
-                                          in boolean aCancelable,
-                                          in mozIDOMApplication aApplication);
-};
-
-dictionary MozApplicationEventInit : EventInit
-{
-  mozIDOMApplication application;
-};
-
 [scriptable, uuid(bd304874-d532-4e13-8034-544211445583)]
 interface mozIDOMApplicationMgmt : nsISupports
 {
   /**
    * the request will return the all the applications installed. Only accessible
    * to privileged callers.
    */
   nsIDOMDOMRequest getAll();
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/apps/nsIDOMMozApplicationEvent.idl
@@ -0,0 +1,23 @@
+/* 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/. */
+
+#include "nsIDOMEvent.idl"
+
+interface mozIDOMApplication;
+
+[scriptable, builtinclass, uuid(8f2bfba8-f10e-4f63-a5e0-7a7056e1dbe6)]
+interface nsIDOMMozApplicationEvent : nsIDOMEvent
+{
+  readonly attribute mozIDOMApplication application;
+
+  [noscript] void initMozApplicationEvent(in DOMString aType,
+                                          in boolean aCanBubble,
+                                          in boolean aCancelable,
+                                          in mozIDOMApplication aApplication);
+};
+
+dictionary MozApplicationEventInit : EventInit
+{
+  mozIDOMApplication application;
+};
--- a/dom/interfaces/events/nsIDOMDeviceOrientationEvent.idl
+++ b/dom/interfaces/events/nsIDOMDeviceOrientationEvent.idl
@@ -36,8 +36,15 @@ interface nsIDOMDeviceOrientationEvent :
    */
 
   readonly attribute double alpha;
   readonly attribute double beta;
   readonly attribute double gamma;
   readonly attribute boolean absolute;
 };
 
+dictionary DeviceOrientationEventInit : EventInit
+{
+  double alpha;
+  double beta;
+  double gamma;
+  boolean absolute;
+};
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -199,20 +199,16 @@ nsresult
 NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsKeyEvent *aEvent);
 nsresult
 NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsCompositionEvent *aEvent);
 nsresult
 NS_NewDOMMutationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsMutationEvent* aEvent);
 nsresult
 NS_NewDOMPopupBlockedEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
-NS_NewDOMDeviceOrientationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
-nsresult
-NS_NewDOMDeviceLightEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
-nsresult
 NS_NewDOMDeviceMotionEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMTextEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsTextEvent* aEvent);
 nsresult
 NS_NewDOMBeforeUnloadEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMSVGEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEvent* aEvent);
 nsresult
--- a/dom/mms/src/ril/MmsPduHelper.jsm
+++ b/dom/mms/src/ril/MmsPduHelper.jsm
@@ -21,16 +21,23 @@ function translatePduErrorToStatus(error
   if ((error >= MMS_PDU_ERROR_TRANSIENT_FAILURE)
       && (error < MMS_PDU_ERROR_PERMANENT_FAILURE)) {
     return MMS_PDU_STATUS_DEFERRED;
   }
 
   return MMS_PDU_STATUS_UNRECOGNISED;
 }
 
+function defineLazyRegExp(obj, name, pattern) {
+  obj.__defineGetter__(name, function() {
+    delete obj[name];
+    return obj[name] = new RegExp(pattern);
+  });
+}
+
 /**
  * Internal decoding function for boolean values.
  *
  * Boolean-value = Yes | No
  * Yes = <Octet 128>
  * No = <Octet 129>
  */
 let BooleanValue = {
@@ -75,36 +82,111 @@ let Address = {
    *        A wrapped object to store encoded raw data.
    *
    * @return An object of two string-typed attributes: address and type.
    */
   decode: function decode(data) {
     let str = EncodedStringValue.decode(data);
 
     let result;
-    if (((result = str.match(/^(\+?[\d.-]+)\/TYPE=(PLMN)$/)) != null)
-        || ((result = str.match(/^(\d{1,3}(?:\.\d{1,3}){3})\/TYPE=(IPv4)$/)) != null)
-        || ((result = str.match(/^([\da-fA-F]{4}(?::[\da-fA-F]{4}){7})\/TYPE=(IPv6)$/)) != null)
-        || ((result = str.match(/^([\w\+\-.%]+)\/TYPE=(\w+)$/)) != null)) {
+    if (((result = str.match(this.REGEXP_DECODE_PLMN)) != null)
+        || ((result = str.match(this.REGEXP_DECODE_IPV4)) != null)
+        || ((result = str.match(this.REGEXP_DECODE_IPV6)) != null)
+        || ((result = str.match(this.REGEXP_DECODE_CUSTOM)) != null)) {
       return {address: result[1], type: result[2]};
     }
 
     let type;
-    if (str.match(/^[\+*#]\d+$/)) {
+    if (str.match(this.REGEXP_NUM)) {
       type = "num";
-    } else if (str.match(/^\w+$/)) {
+    } else if (str.match(this.REGEXP_ALPHANUM)) {
       type = "alphanum";
+    } else if (str.indexOf("@") > 0) {
+      // E-mail should match the definition of `mailbox` as described in section
+      // 3.4 of RFC2822, but excluding the obsolete definitions as indicated by
+      // the "obs-" prefix. Here we match only a `@` character.
+      type = "email";
     } else {
-      type = "unknown";
+      throw new WSP.CodeError("Address: invalid address");
     }
 
     return {address: str, type: type};
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An object of two string-typed attributes: address and type.
+   */
+  encode: function encode(data, value) {
+    if (!value || !value.type || !value.address) {
+      throw new WSP.CodeError("Address: invalid value");
+    }
+
+    let str;
+    switch (value.type) {
+      case "email":
+        if (value.address.indexOf("@") > 0) {
+          str = value.address;
+        }
+        break;
+      case "num":
+        if (value.address.match(this.REGEXP_NUM)) {
+          str = value.address;
+        }
+        break;
+      case "alphanum":
+        if (value.address.match(this.REGEXP_ALPHANUM)) {
+          str = value.address;
+        }
+        break;
+      case "IPv4":
+        if (value.address.match(this.REGEXP_ENCODE_IPV4)) {
+          str = value.address + "/TYPE=IPv4";
+        }
+        break;
+      case "IPv6":
+        if (value.address.match(this.REGEXP_ENCODE_IPV6)) {
+          str = value.address + "/TYPE=IPv6";
+        }
+        break;
+      case "PLMN":
+        if (value.address.match(this.REGEXP_ENCODE_PLMN)) {
+          str = value.address + "/TYPE=PLMN";
+        }
+        break;
+      default:
+        if (value.type.match(this.REGEXP_ENCODE_CUSTOM_TYPE)
+            && value.address.match(this.REGEXP_ENCODE_CUSTOM_ADDR)) {
+          str = value.address + "/TYPE=" + value.type;
+	}
+        break;
+    }
+
+    if (!str) {
+      throw new WSP.CodeError("Address: invalid value: " + JSON.stringify(value));
+    }
+
+    EncodedStringValue.encode(data, str);
+  },
 };
 
+defineLazyRegExp(Address, "REGEXP_DECODE_PLMN",        "^(\\+?[\\d.-]+)\\/TYPE=(PLMN)$");
+defineLazyRegExp(Address, "REGEXP_DECODE_IPV4",        "^(\\d{1,3}(?:\\.\\d{1,3}){3})\\/TYPE=(IPv4)$");
+defineLazyRegExp(Address, "REGEXP_DECODE_IPV6",        "^([\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7})\\/TYPE=(IPv6)$");
+defineLazyRegExp(Address, "REGEXP_DECODE_CUSTOM",      "^([\\w\\+\\-.%]+)\\/TYPE=(\\w+)$");
+defineLazyRegExp(Address, "REGEXP_ENCODE_PLMN",        "^\\+?[\\d.-]+$");
+defineLazyRegExp(Address, "REGEXP_ENCODE_IPV4",        "^\\d{1,3}(?:\\.\\d{1,3}){3}$");
+defineLazyRegExp(Address, "REGEXP_ENCODE_IPV6",        "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$");
+defineLazyRegExp(Address, "REGEXP_ENCODE_CUSTOM_TYPE", "^\\w+$");
+defineLazyRegExp(Address, "REGEXP_ENCODE_CUSTOM_ADDR", "^[\\w\\+\\-.%]+$");
+defineLazyRegExp(Address, "REGEXP_NUM",                "^[\\+*#]\\d+$");
+defineLazyRegExp(Address, "REGEXP_ALPHANUM",           "^\\w+$");
+
 /**
  * Header-field = MMS-header | Application-header
  *
  * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.2
  */
 let HeaderField = {
   /**
    * @param data
@@ -230,16 +312,30 @@ let ContentClassValue = {
   decode: function decode(data) {
     let value = WSP.Octet.decode(data);
     if ((value >= 128) && (value <= 135)) {
       return value;
     }
 
     throw new WSP.CodeError("Content-class-value: invalid class " + value);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        A numeric content class value to be encoded.
+   */
+  encode: function encode(data, value) {
+    if ((value < 128) || (value > 135)) {
+      throw new WSP.CodeError("Content-class-value: invalid class " + value);
+    }
+
+    WSP.Octet.encode(data, value);
+  },
 };
 
 /**
  * When used in a PDU other than M-Mbox-Delete.conf and M-Delete.conf:
  *
  *   Content-location-value = Uri-value
  *
  * When used in the M-Mbox-Delete.conf and M-Delete.conf PDU:
@@ -396,16 +492,40 @@ let Parameter = {
           params = {};
         }
         params[param.name] = param.value;
       }
     }
 
     return params;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param param
+   *        An object containing two attributes: `name` and `value`.
+   * @param options
+   *        Extra context for encoding.
+   */
+  encode: function encode(data, param, options) {
+    if (!param || !param.name) {
+      throw new WSP.CodeError("Parameter-name: empty param name");
+    }
+
+    let entry = MMS_WELL_KNOWN_PARAMS[param.name.toLowerCase()];
+    if (entry) {
+      WSP.ShortInteger.encode(data, entry.number);
+    } else {
+      WSP.TextString.encode(data, param.name);
+    }
+
+    WSP.encodeAlternatives(data, param.value, options,
+                           WSP.ConstrainedEncoding, WSP.TextString);
+  },
 };
 
 /**
  * The Char-set values are registered by IANA as MIBEnum value and SHALL be
  * encoded as Integer-value.
  *
  *   Encoded-string-value = Text-string | Value-length Char-set Text-string
  *
@@ -479,16 +599,73 @@ let EncodedStringValue = {
     let begin = data.offset;
     try {
       return WSP.TextString.decode(data);
     } catch (e) {
       data.offset = begin;
       return this.decodeCharsetEncodedString(data);
     }
   },
+
+  /**
+   * Always encode target string with UTF-8 encoding.
+   *
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param str
+   *        A string.
+   */
+  encodeCharsetEncodedString: function encodeCharsetEncodedString(data, str) {
+    let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+               .createInstance(Ci.nsIScriptableUnicodeConverter);
+    // `When the text string cannot be represented as us-ascii, the character
+    // set SHALL be encoded as utf-8(IANA MIBenum 106) which has unique byte
+    // ordering.` ~ OMA-TS-MMS_CONF-V1_3-20110913-A clause 10.2.1
+    conv.charset = "UTF-8";
+
+    let raw;
+    try {
+      raw = conv.convertToByteArray(str);
+    } catch (e) {
+      throw new WSP.CodeError("Charset-encoded-string: " + e.message);
+    }
+
+    let length = raw.length + 2; // Charset number and NUL character
+    // Prepend <Octet 127> if necessary.
+    if (raw[0] >= 128) {
+      ++length;
+    }
+
+    WSP.ValueLength.encode(data, length);
+
+    let entry = WSP.WSP_WELL_KNOWN_CHARSETS["utf-8"];
+    WSP.IntegerValue.encode(data, entry.number);
+
+    if (raw[0] >= 128) {
+      WSP.Octet.encode(data, 127);
+    }
+    WSP.Octet.encodeMultiple(data, raw);
+    WSP.Octet.encode(data, 0);
+  },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param str
+   *        A string.
+   */
+  encode: function encode(data, str) {
+    let begin = data.offset;
+    try {
+      WSP.TextString.encode(data, str);
+    } catch (e) {
+      data.offset = begin;
+      this.encodeCharsetEncodedString(data, str);
+    }
+  },
 };
 
 /**
  * Expiry-value = Value-length (Absolute-token Date-value | Relative-token Delta-seconds-value)
  * Absolute-token = <Octet 128>
  * Relative-token = <Octet 129>
  *
  * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.20
@@ -519,16 +696,49 @@ let ExpiryValue = {
     }
 
     if (data.offset != end) {
       data.offset = end;
     }
 
     return result;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        A Date object for absolute expiry or an integer for relative one.
+   */
+  encode: function encode(data, value) {
+    let isDate, begin = data.offset;
+    if (value instanceof Date) {
+      isDate = true;
+      WSP.DateValue.encode(data, value);
+    } else if (typeof value == "number") {
+      isDate = false;
+      WSP.DeltaSecondsValue.encode(data, value);
+    } else {
+      throw new CodeError("Expiry-value: invalid value type");
+    }
+
+    // Calculate how much octets will be written and seek back.
+    // TODO: use memmove, see bug 730873
+    let len = data.offset - begin;
+    data.offset = begin;
+
+    WSP.ValueLength.encode(data, len + 1);
+    if (isDate) {
+      WSP.Octet.encode(data, 128);
+      WSP.DateValue.encode(data, value);
+    } else {
+      WSP.Octet.encode(data, 129);
+      WSP.DeltaSecondsValue.encode(data, value);
+    }
+  },
 };
 
 /**
  * From-value = Value-length (Address-present-token Address | Insert-address-token)
  * Address-present-token = <Octet 128>
  * Insert-address-token = <Octet 129>
  *
  * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.21
@@ -558,16 +768,41 @@ let FromValue = {
     }
 
     if (data.offset != end) {
       data.offset = end;
     }
 
     return result;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        A Address-value or null for MMS Proxy-Relay Insert-Address mode.
+   */
+  encode: function encode(data, value) {
+    if (!value) {
+      WSP.ValueLength.encode(data, 1);
+      WSP.Octet.encode(data, 129);
+      return;
+    }
+
+    // Calculate how much octets will be written and seek back.
+    // TODO: use memmove, see bug 730873
+    let begin = data.offset;
+    Address.encode(data, value);
+    let len = data.offset - begin;
+    data.offset = begin;
+
+    WSP.ValueLength.encode(data, len + 1);
+    WSP.Octet.encode(data, 128);
+    Address.encode(data, value);
+  },
 };
 
 /**
  * Previously-sent-by-value = Value-length Forwarded-count-value Address
  * Forwarded-count-value = Integer-value
  *
  * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.23
  */
@@ -631,31 +866,30 @@ let PreviouslySentDateValue = {
  * Personal = <Octet 128>
  * Advertisement = <Octet 129>
  * Informational = <Octet 130>
  * Auto = <Octet 131>
  *
  * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.27
  */
 let MessageClassValue = {
+  WELL_KNOWN_CLASSES: ["personal", "advertisement", "informational", "auto"],
+
   /**
    * @param data
    *        A wrapped object containing raw PDU data.
    *
    * @return A decoded string.
    *
    * @throws CodeError if decoded value is not in the range 128..131.
    */
   decodeClassIdentifier: function decodeClassIdentifier(data) {
     let value = WSP.Octet.decode(data);
-    switch (value) {
-      case 128: return "personal";
-      case 129: return "advertisement";
-      case 130: return "informational";
-      case 131: return "auto";
+    if ((value >= 128) && (value < (128 + this.WELL_KNOWN_CLASSES.length))) {
+      return this.WELL_KNOWN_CLASSES[value - 128];
     }
 
     throw new WSP.CodeError("Class-identifier: invalid id " + value);
   },
 
   /**
    * @param data
    *        A wrapped object containing raw PDU data.
@@ -666,16 +900,30 @@ let MessageClassValue = {
     let begin = data.offset;
     try {
       return this.decodeClassIdentifier(data);
     } catch (e) {
       data.offset = begin;
       return WSP.TokenText.decode(data);
     }
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param klass
+   */
+  encode: function encode(data, klass) {
+    let index = this.WELL_KNOWN_CLASSES.indexOf(klass.toLowerCase());
+    if (index >= 0) {
+      WSP.Octet.encode(data, index + 128);
+    } else {
+      WSP.TokenText.encode(data, klass);
+    }
+  },
 };
 
  /**
  * Message-type-value = <Octet 128..151>
  *
  * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.30
  */
 let MessageTypeValue = {
@@ -743,16 +991,40 @@ let MmFlagsValue = {
     result.text = EncodedStringValue.decode(data);
 
     if (data.offset != end) {
       data.offset = end;
     }
 
     return result;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An object containing an integer `type` and an string-typed
+   *        `text` attributes.
+   */
+  encode: function encode(data, value) {
+    if ((value.type < 128) || (value.type > 130)) {
+      throw new WSP.CodeError("MM-flags-value: invalid type " + value.type);
+    }
+
+    // Calculate how much octets will be written and seek back.
+    // TODO: use memmove, see bug 730873
+    let begin = data.offset;
+    EncodedStringValue.encode(data, value.text);
+    let len = data.offset - begin;
+    data.offset = begin;
+
+    WSP.ValueLength.encode(data, len + 1);
+    WSP.Octet.encode(data, value.type);
+    EncodedStringValue.encode(data, value.text);
+  },
 };
 
 /**
  * MM-state-value = Draft | Sent | New | Retrieved | Forwarded
  * Draft = <Octet 128>
  * Sent = <Octet 129>
  * New = <Octet 130>
  * Retrieved = <Octet 131>
@@ -772,16 +1044,32 @@ let MmStateValue = {
   decode: function decode(data) {
     let state = WSP.Octet.decode(data);
     if ((state >= 128) && (state <= 132)) {
       return state;
     }
 
     throw new WSP.CodeError("MM-state-value: invalid state " + state);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param state
+   *        A numeric state value to be encoded.
+   *
+   * @throws CodeError if state is not in the range 128..132.
+   */
+  encode: function encode(data, state) {
+    if ((state < 128) || (state > 132)) {
+      throw new WSP.CodeError("MM-state-value: invalid state " + state);
+    }
+
+    WSP.Octet.encode(data, state);
+  },
 };
 
 /**
  * Priority-value = Low | Normal | High
  * Low = <Octet 128>
  * Normal = <Octet 129>
  * High = <Octet 130>
  *
@@ -799,16 +1087,30 @@ let PriorityValue = {
   decode: function decode(data) {
     let priority = WSP.Octet.decode(data);
     if ((priority >= 128) && (priority <= 130)) {
       return priority;
     }
 
     throw new WSP.CodeError("Priority-value: invalid priority " + priority);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param priority
+   *        A numeric priority value to be encoded.
+   */
+  encode: function encode(data, priority) {
+    if ((priority < 128) || (priority > 130)) {
+      throw new WSP.CodeError("Priority-value: invalid priority " + priority);
+    }
+
+    WSP.Octet.encode(data, priority);
+  },
 };
 
 /**
  * Recommended-Retrieval-Mode-value = Manual
  * Manual = <Octet 128>
  *
  * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.39
  */
@@ -846,16 +1148,74 @@ let ReplyChargingValue = {
   decode: function decode(data) {
     let value = WSP.Octet.decode(data);
     if ((value >= 128) && (value <= 131)) {
       return value;
     }
 
     throw new WSP.CodeError("Reply-charging-value: invalid value " + value);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An integer value within thr range 128..131.
+   */
+  encode: function encode(data, value) {
+    if ((value < 128) || (value > 131)) {
+      throw new WSP.CodeError("Reply-charging-value: invalid value " + value);
+    }
+
+    WSP.Octet.encode(data, value);
+  },
+};
+
+/**
+ * When used in a PDU other than M-Mbox-Delete.conf and M-Delete.conf:
+ *
+ *   Response-text-value = Encoded-string-value
+ *
+ * When used in the M-Mbox-Delete.conf and M-Delete.conf PDUs:
+ *
+ *   Response-text-Del-value = Value-length Status-count-value Response-text-value
+ *
+ * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.49
+ */
+let ResponseText = {
+  /**
+   * @param data
+   *        A wrapped object containing raw PDU data.
+   * @param options
+   *        Extra context for decoding.
+   *
+   * @return An object containing a string-typed `text` attribute and a
+   *         integer-typed `statusCount` one.
+   */
+  decode: function decode(data, options) {
+    let type = WSP.ensureHeader(options, "x-mms-message-type");
+
+    let result = {};
+    if ((type == MMS_PDU_TYPE_MBOX_DELETE_CONF)
+        || (type == MMS_PDU_TYPE_DELETE_CONF)) {
+      let length = WSP.ValueLength.decode(data);
+      let end = data.offset + length;
+
+      result.statusCount = WSP.IntegerValue.decode(data);
+      result.text = EncodedStringValue.decode(data);
+
+      if (data.offset != end) {
+        data.offset = end;
+      }
+    } else {
+      result.text = EncodedStringValue.decode(data);
+    }
+
+    return result;
+  },
 };
 
 /**
  * Retrieve-status-value = Ok | Error-transient-failure |
  *                         Error-transient-message-not-found |
  *                         Error-transient-network-problem |
  *                         Error-permanent-failure |
  *                         Error-permanent-service-denied |
@@ -1068,82 +1428,81 @@ let PduHelper = {
       debug("Failed to parse MMS message, error message: " + e.message);
       return null;
     }
 
     return msg;
   },
 
   /**
-   * Convert javascript Array to an nsIInputStream.
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param headers
+   *        A dictionary object containing multiple name/value mapping.
+   * @param name
+   *        Name of the header field to be encoded.
    */
-  convertArrayToInputStream: function convertDataToInputStream(array) {
-    let storageStream = Cc["@mozilla.org/storagestream;1"]
-                        .createInstance(Ci.nsIStorageStream);
-    storageStream.init(4096, array.length, null);
+  encodeHeader: function encodeHeader(data, headers, name) {
+    let value = headers[name];
+    if (Array.isArray(value)) {
+      for (let i = 0; i < value.length; i++) {
+        HeaderField.encode(data, {name: name, value: value[i]}, headers);
+      }
+    } else {
+      HeaderField.encode(data, {name: name, value: value}, headers);
+    }
+  },
 
-    let boStream = Cc["@mozilla.org/binaryoutputstream;1"]
-                   .createInstance(Ci.nsIBinaryOutputStream);
-    boStream.setOutputStream(storageStream.getOutputStream(0));
-    boStream.writeByteArray(array, array.length)
-    boStream.close();
-
-    return storageStream.newInputStream(0);
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param headers
+   *        A dictionary object containing multiple name/value mapping.
+   */
+  encodeHeaderIfExists: function encodeHeaderIfExists(data, headers, name) {
+    // Header value could be zero or null.
+    if (headers[name] !== undefined) {
+      this.encodeHeader(data, headers, name);
+    }
   },
 
   /**
    * @param data [optional]
    *        A wrapped object to store encoded raw data. Created if undefined.
    * @param headers
    *        A dictionary object containing multiple name/value mapping.
    *
    * @return the passed data parameter or a created one.
    */
   encodeHeaders: function encodeHeaders(data, headers) {
     if (!data) {
       data = {array: [], offset: 0};
     }
 
-    function encodeHeader(name) {
-      HeaderField.encode(data, {name: name, value: headers[name]});
-    }
-
-    function encodeHeaderIfExists(name) {
-      // Header value could be zero or null.
-      if (headers[name] !== undefined) {
-        encodeHeader(name);
-      }
-    }
-
     // `In the encoding of the header fields, the order of the fields is not
     // significant, except that X-Mms-Message-Type, X-Mms-Transaction-ID (when
     // present) and X-Mms-MMS-Version MUST be at the beginning of the message
     // headers, in that order, and if the PDU contains a message body the
     // Content Type MUST be the last header field, followed by message body.`
     // ~ OMA-TS-MMS_ENC-V1_3-20110913-A section 7
-    encodeHeader("x-mms-message-type");
-    encodeHeaderIfExists("x-mms-transaction-id");
-    encodeHeaderIfExists("x-mms-mms-version");
+    this.encodeHeader(data, headers, "x-mms-message-type");
+    this.encodeHeaderIfExists(data, headers, "x-mms-transaction-id");
+    this.encodeHeaderIfExists(data, headers, "x-mms-mms-version");
 
     for (let key in headers) {
       if ((key == "x-mms-message-type")
           || (key == "x-mms-transaction-id")
           || (key == "x-mms-mms-version")
           || (key == "content-type")) {
         continue;
       }
-      encodeHeader(key);
+      this.encodeHeader(data, headers, key);
     }
 
-    encodeHeaderIfExists("content-type");
-
-    // Remove extra space consumed during encoding.
-    while (data.array.length > data.offset) {
-      data.array.pop();
-    }
+    this.encodeHeaderIfExists(data, headers, "content-type");
 
     return data;
   },
 
   /**
    * @param multiStream
    *        An exsiting nsIMultiplexInputStream.
    * @param msg
@@ -1158,18 +1517,25 @@ let PduHelper = {
     }
 
     try {
       // Validity checks
       let typeinfo = this.checkMandatoryFields(msg);
 
       let data = this.encodeHeaders(null, msg.headers);
       debug("Composed PDU Header: " + JSON.stringify(data.array));
-      let headerStream = this.convertArrayToInputStream(data.array);
-      multiStream.appendStream(headerStream);
+      WSP.PduHelper.appendArrayToMultiStream(multiStream, data.array, data.offset);
+
+      if (msg.content) {
+        WSP.PduHelper.appendArrayToMultiStream(multiStream, msg.content, msg.content.length);
+      } else if (msg.parts) {
+        WSP.PduHelper.composeMultiPart(multiStream, msg.parts);
+      } else if (typeinfo.hasContent) {
+        throw new WSP.CodeError("Missing message content");
+      }
 
       return multiStream;
     } catch (e) {
       debug("Failed to compose MMS message, error message: " + e.message);
       return null;
     }
   },
 };
@@ -1179,39 +1545,54 @@ const MMS_PDU_TYPES = (function () {
   function add(number, hasContent, mandatoryFields) {
     pdus[number] = {
       number: number,
       hasContent: hasContent,
       mandatoryFields: mandatoryFields,
     };
   }
 
+  add(MMS_PDU_TYPE_SEND_REQ, true, ["x-mms-message-type",
+                                    "x-mms-transaction-id",
+                                    "x-mms-mms-version",
+                                    "from",
+                                    "content-type"]);
+  add(MMS_PDU_TYPE_SEND_CONF, false, ["x-mms-message-type",
+                                      "x-mms-transaction-id",
+                                      "x-mms-mms-version",
+                                      "x-mms-response-status"]);
   add(MMS_PDU_TYPE_NOTIFICATION_IND, false, ["x-mms-message-type",
                                              "x-mms-transaction-id",
                                              "x-mms-mms-version",
                                              "x-mms-message-class",
                                              "x-mms-message-size",
                                              "x-mms-expiry",
                                              "x-mms-content-location"]);
   add(MMS_PDU_TYPE_RETRIEVE_CONF, true, ["x-mms-message-type",
                                          "x-mms-mms-version",
                                          "date",
                                          "content-type"]);
   add(MMS_PDU_TYPE_NOTIFYRESP_IND, false, ["x-mms-message-type",
                                            "x-mms-transaction-id",
                                            "x-mms-mms-version",
                                            "x-mms-status"]);
+  add(MMS_PDU_TYPE_DELIVERY_IND, false, ["x-mms-message-type",
+                                         "x-mms-mms-version",
+                                         "message-id",
+                                         "to",
+                                         "date",
+                                         "x-mms-status"]);
 
   return pdus;
 })();
 
 /**
  * Header field names and assigned numbers.
  *
- * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.4
+ * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.4
  */
 const MMS_HEADER_FIELDS = (function () {
   let names = {};
   function add(name, number, coder) {
     let entry = {
       name: name,
       number: number,
       coder: coder,
@@ -1220,48 +1601,48 @@ const MMS_HEADER_FIELDS = (function () {
   }
 
   add("bcc",                                     0x01, Address);
   add("cc",                                      0x02, Address);
   add("x-mms-content-location",                  0x03, ContentLocationValue);
   add("content-type",                            0x04, WSP.ContentTypeValue);
   add("date",                                    0x05, WSP.DateValue);
   add("x-mms-delivery-report",                   0x06, BooleanValue);
-  //add("x-mms-delivery-time", 0x07);
+  add("x-mms-delivery-time",                     0x07, ExpiryValue);
   add("x-mms-expiry",                            0x08, ExpiryValue);
   add("from",                                    0x09, FromValue);
   add("x-mms-message-class",                     0x0A, MessageClassValue);
   add("message-id",                              0x0B, WSP.TextString);
   add("x-mms-message-type",                      0x0C, MessageTypeValue);
   add("x-mms-mms-version",                       0x0D, WSP.ShortInteger);
   add("x-mms-message-size",                      0x0E, WSP.LongInteger);
   add("x-mms-priority",                          0x0F, PriorityValue);
   add("x-mms-read-report",                       0x10, BooleanValue);
   add("x-mms-report-allowed",                    0x11, BooleanValue);
-  //add("x-mms-response-status", 0x12);
-  //add("x-mms-response-text", 0x13);
-  //add("x-mms-sender-visibility", 0x14);
+  add("x-mms-response-status",                   0x12, RetrieveStatusValue);
+  add("x-mms-response-text",                     0x13, ResponseText);
+  add("x-mms-sender-visibility",                 0x14, BooleanValue);
   add("x-mms-status",                            0x15, StatusValue);
   add("subject",                                 0x16, EncodedStringValue);
   add("to",                                      0x17, Address);
   add("x-mms-transaction-id",                    0x18, WSP.TextString);
   add("x-mms-retrieve-status",                   0x19, RetrieveStatusValue);
   add("x-mms-retrieve-text",                     0x1A, EncodedStringValue);
   //add("x-mms-read-status", 0x1B);
   add("x-mms-reply-charging",                    0x1C, ReplyChargingValue);
   add("x-mms-reply-charging-deadline",           0x1D, ExpiryValue);
   add("x-mms-reply-charging-id",                 0x1E, WSP.TextString);
   add("x-mms-reply-charging-size",               0x1F, WSP.LongInteger);
   add("x-mms-previously-sent-by",                0x20, PreviouslySentByValue);
   add("x-mms-previously-sent-date",              0x21, PreviouslySentDateValue);
   add("x-mms-store",                             0x22, BooleanValue);
   add("x-mms-mm-state",                          0x23, MmStateValue);
   add("x-mms-mm-flags",                          0x24, MmFlagsValue);
-  //add("x-mms-store-status", 0x25);
-  //add("x-mms-store-status-text", 0x26);
+  add("x-mms-store-status",                      0x25, RetrieveStatusValue);
+  add("x-mms-store-status-text",                 0x26, EncodedStringValue);
   add("x-mms-stored",                            0x27, BooleanValue);
   //add("x-mms-attributes", 0x28);
   add("x-mms-totals",                            0x29, BooleanValue);
   //add("x-mms-mbox-totals", 0x2A);
   add("x-mms-quotas",                            0x2B, BooleanValue);
   //add("x-mms-mbox-quotas", 0x2C);
   add("x-mms-message-count",                     0x2D, WSP.IntegerValue);
   //add("content", 0x2E);
@@ -1294,16 +1675,17 @@ const MMS_WELL_KNOWN_PARAMS = (function 
     let entry = {
       name: name,
       number: number,
       coder: coder,
     };
     params[name] = params[number] = entry;
   }
 
+  // Encoding Version: 1.2
   add("type", 0x02, WSP.TypeValue);
 
   return params;
 })();
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
@@ -1333,15 +1715,16 @@ const EXPORTED_SYMBOLS = ALL_CONST_SYMBO
   "PreviouslySentDateValue",
   "MessageClassValue",
   "MessageTypeValue",
   "MmFlagsValue",
   "MmStateValue",
   "PriorityValue",
   "RecommendedRetrievalModeValue",
   "ReplyChargingValue",
+  "ResponseText",
   "RetrieveStatusValue",
   "StatusValue",
 
   // Parser
   "PduHelper",
 ]);
 
--- a/dom/mms/src/ril/MmsService.js
+++ b/dom/mms/src/ril/MmsService.js
@@ -36,16 +36,20 @@ const CONFIG_SEND_REPORT_NEVER       = 0
 const CONFIG_SEND_REPORT_DEFAULT_NO  = 1;
 const CONFIG_SEND_REPORT_DEFAULT_YES = 2;
 const CONFIG_SEND_REPORT_ALWAYS      = 3;
 
 XPCOMUtils.defineLazyServiceGetter(this, "gpps",
                                    "@mozilla.org/network/protocol-proxy-service;1",
                                    "nsIProtocolProxyService");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
+                                   "@mozilla.org/uuid-generator;1",
+                                   "nsIUUIDGenerator");
+
 XPCOMUtils.defineLazyGetter(this, "MMS", function () {
   let MMS = {};
   Cu.import("resource://gre/modules/MmsPduHelper.jsm", MMS);
   return MMS;
 });
 
 /**
  * MmsService
@@ -223,16 +227,94 @@ MmsService.prototype = {
     // Optional fields
     headers["x-mms-report-allowed"] = ra;
 
     let istream = MMS.PduHelper.compose(null, {headers: headers});
     this.sendMmsRequest("POST", this.MMSC, istream);
   },
 
   /**
+   * Send M-Send.req to MMSC
+   */
+  sendSendRequest: function sendSendRequest(msg, callback) {
+    msg.headers["x-mms-message-type"] = MMS.MMS_PDU_TYPE_SEND_REQ;
+    if (!msg.headers["x-mms-transaction-id"]) {
+      // Create an unique transaction id
+      let tid = gUUIDGenerator.generateUUID().toString();
+      msg.headers["x-mms-transaction-id"] = tid;
+    }
+    msg.headers["x-mms-mms-version"] = MMS.MMS_VERSION;
+
+    // Let MMS Proxy Relay insert from address automatically for us
+    msg.headers["from"] = null;
+
+    msg.headers["date"] = new Date();
+    msg.headers["x-mms-message-class"] = "personal";
+    msg.headers["x-mms-expiry"] = 7 * 24 * 60 * 60;
+    msg.headers["x-mms-priority"] = 129;
+    msg.headers["x-mms-read-report"] = true;
+    msg.headers["x-mms-delivery-report"] = true;
+
+    let messageSize = 0;
+
+    if (msg.content) {
+      messageSize = msg.content.length;
+    } else if (msg.parts) {
+      for (let i = 0; i < msg.parts.length; i++) {
+        messageSize += msg.parts[i].content.length;
+      }
+
+      let contentType = {
+        params: {
+          // `The type parameter must be specified and its value is the MIME
+          // media type of the "root" body part.` ~ RFC 2387 clause 3.1
+          type: msg.parts[0].headers["content-type"].media,
+        },
+      };
+
+      // `The Content-Type in M-Send.req and M-Retrieve.conf SHALL be
+      // application/vnd.wap.multipart.mixed when there is no presentation, and
+      // application/vnd.wap.multipart.related SHALL be used when there is SMIL
+      // presentation available.` ~ OMA-TS-MMS_CONF-V1_3-20110913-A clause 10.2.1
+      if (contentType.params.type === "application/smil") {
+        contentType.media = "application/vnd.wap.multipart.related";
+
+        // `The start parameter, if given, is the content-ID of the compound
+        // object's "root".` ~ RFC 2387 clause 3.2
+        contentType.params.start = msg.parts[0].headers["content-id"];
+      } else {
+        contentType.media = "application/vnd.wap.multipart.mixed";
+      }
+
+      // Assign to Content-Type
+      msg.headers["content-type"] = contentType;
+    }
+
+    // Assign to X-Mms-Message-Size
+    msg.headers["x-mms-message-size"] = messageSize;
+
+    debug("msg: " + JSON.stringify(msg));
+
+    let istream = MMS.PduHelper.compose(null, msg);
+    if (!istream) {
+      debug("sendSendRequest: failed to compose M-Send.ind PDU");
+      callback(MMS.MMS_PDU_ERROR_PERMANENT_FAILURE, null);
+      return;
+    }
+
+    this.sendMmsRequest("POST", this.MMSC, istream, (function (status, data) {
+      if (!data) {
+        callback(MMS.MMS_PDU_ERROR_PERMANENT_FAILURE, null);
+      } else if (!this.parseStreamAndDispatch(data, {msg: msg, callback: callback})) {
+        callback(MMS.MMS_PDU_RESPONSE_ERROR_UNSUPPORTED_MESSAGE, null);
+      }
+    }).bind(this));
+  },
+
+  /**
    * @param file
    *        A nsIFile object indicating where to save the data.
    * @param data
    *        An array of raw octets.
    * @param callback
    *        Callback function when I/O is done.
    *
    * @return An nsIRequest representing the copy operation returned by
@@ -312,31 +394,65 @@ MmsService.prototype = {
   parseStreamAndDispatch: function parseStreamAndDispatch(data, options) {
     let msg = MMS.PduHelper.parse(data, null);
     if (!msg) {
       return false;
     }
     debug("parseStreamAndDispatch: msg = " + JSON.stringify(msg));
 
     switch (msg.type) {
+      case MMS.MMS_PDU_TYPE_SEND_CONF:
+        this.handleSendConfirmation(msg, options);
+        break;
       case MMS.MMS_PDU_TYPE_NOTIFICATION_IND:
         this.handleNotificationIndication(msg, options);
         break;
       case MMS.MMS_PDU_TYPE_RETRIEVE_CONF:
         this.handleRetrieveConfirmation(msg, options);
         break;
+      case MMS.MMS_PDU_TYPE_DELIVERY_IND:
+        this.handleDeliveryIndication(msg, options);
+        break;
       default:
         debug("Unsupported X-MMS-Message-Type: " + msg.type);
         return false;
     }
 
     return true;
   },
 
   /**
+   * Handle incoming M-Send.conf PDU.
+   *
+   * @param msg
+   *        The M-Send.conf message object.
+   */
+  handleSendConfirmation: function handleSendConfirmation(msg, options) {
+    let status = msg.headers["x-mms-response-status"];
+    if (status == null) {
+      return;
+    }
+
+    if (status == MMS.MMS_PDU_ERROR_OK) {
+      // `This ID SHALL always be present after the MMS Proxy-Relay accepted
+      // the corresponding M-Send.req PDU. The ID enables a MMS Client to match
+      // delivery reports or read-report PDUs with previously sent MM.`
+      let messageId = msg.headers["message-id"];
+      options.msg.headers["message-id"] = messageId;
+    } else if ((status >= MMS.MMS_PDU_ERROR_TRANSIENT_FAILURE)
+               && (status < MMS.MMS_PDU_ERROR_PERMANENT_FAILURE)) {
+      return;
+    }
+
+    if (options.callback) {
+      options.callback(status, msg);
+    }
+  },
+
+  /**
    * Handle incoming M-Notification.ind PDU.
    *
    * @param msg
    *        The MMS message object.
    */
   handleNotificationIndication: function handleNotificationIndication(msg) {
     function callback(status, retr) {
       let tid = msg.headers["x-mms-transaction-id"];
@@ -392,16 +508,24 @@ MmsService.prototype = {
       callbackIfValid(status, msg);
       return;
     }
 
     this.saveMessageContent(msg, callbackIfValid.bind(null, MMS.MMS_PDU_ERROR_OK));
   },
 
   /**
+   * Handle incoming M-Delivery.ind PDU.
+   */
+  handleDeliveryIndication: function handleDeliveryIndication(msg) {
+    let messageId = msg.headers["message-id"];
+    debug("handleDeliveryIndication: got delivery report for " + messageId);
+  },
+
+  /**
    * Update proxyInfo & MMSC from preferences.
    *
    * @param enabled
    *        Enable or disable MMS proxy.
    */
   updateProxyInfo: function updateProxyInfo(enabled) {
     try {
       if (enabled) {
--- a/dom/mms/src/ril/WspPduHelper.jsm
+++ b/dom/mms/src/ril/WspPduHelper.jsm
@@ -284,16 +284,28 @@ let Octet = {
   encode: function encode(data, octet) {
     if (data.offset >= data.array.length) {
       data.array.push(octet);
       data.offset++;
     } else {
       data.array[data.offset++] = octet;
     }
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param octet
+   *        An octet array object.
+   */
+  encodeMultiple: function encodeMultiple(data, array) {
+    for (let i = 0; i < array.length; i++) {
+      this.encode(data, array[i]);
+    }
+  },
 };
 
 /**
  * TEXT = <any OCTET except CTLs, but including LWS>
  * CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
  * LWS = [CRLF] 1*(SP|HT)
  * CRLF = CR LF
  * CR = <US-ASCII CR, carriage return (13)>
@@ -654,16 +666,27 @@ let QuotedString = {
   decode: function decode(data) {
     let value = Octet.decode(data);
     if (value != 34) {
       throw new CodeError("Quoted-string: not quote " + value);
     }
 
     return NullTerminatedTexts.decode(data);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param str
+   *        A String to be encoded.
+   */
+  encode: function encode(data, str) {
+    Octet.encode(data, 34);
+    NullTerminatedTexts.encode(data, str);
+  },
 };
 
 /**
  * Integers in range 0-127 shall be encoded as a one octet value with the
  * most significant bit set to one (1xxx xxxx) and with the value in the
  * remaining least significant bits.
  *
  *   Short-integer = OCTET
@@ -752,16 +775,52 @@ let LongInteger = {
   decode: function decode(data) {
     let length = Octet.decode(data);
     if ((length < 1) || (length > 30)) {
       throw new CodeError("Long-integer: invalid length " + length);
     }
 
     return this.decodeMultiOctetInteger(data, length);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param numOrArray
+   *        An octet array of less-equal than 30 elements or an integer
+   *        greater-equal than 128.
+   */
+  encode: function encode(data, numOrArray) {
+    if (typeof numOrArray === "number") {
+      let num = numOrArray;
+      if (num >= 0x1000000000000) {
+        throw new CodeError("Long-integer: number too large " + num);
+      }
+
+      let stack = [];
+      do {
+        stack.push(Math.floor(num % 256));
+        num = Math.floor(num / 256);
+      } while (num);
+
+      Octet.encode(data, stack.length);
+      while (stack.length) {
+        Octet.encode(data, stack.pop());
+      }
+      return;
+    }
+
+    let array = numOrArray;
+    if ((array.length < 1) || (array.length > 30)) {
+      throw new CodeError("Long-integer: invalid length " + array.length);
+    }
+
+    Octet.encode(data, array.length);
+    Octet.encodeMultiple(data, array);
+  },
 };
 
 /**
  * @see WAP-230-WSP-20010705-a clause 8.4.2.1
  */
 let UintVar = {
   /**
    * @param data
@@ -774,16 +833,40 @@ let UintVar = {
     let result = value & 0x7F;
     while (value & 0x80) {
       value = Octet.decode(data);
       result = result * 128 + (value & 0x7F);
     }
 
     return result;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An integer value.
+   */
+  encode: function encode(data, value) {
+    if (value < 0) {
+      throw new CodeError("UintVar: invalid value " + value);
+    }
+
+    let stack = [];
+    while (value >= 128) {
+      stack.push(Math.floor(value % 128));
+      value = Math.floor(value / 128);
+    }
+
+    while (stack.length) {
+      Octet.encode(data, value | 0x80);
+      value = stack.pop();
+    }
+    Octet.encode(data, value);
+  },
 };
 
 /**
  * This encoding is used for token values, which have no well-known binary
  * encoding, or when the assigned number of the well-known encoding is small
  * enough to fit into Short-Integer.
  *
  *   Constrained-encoding = Extension-Media | Short-integer
@@ -796,16 +879,30 @@ let ConstrainedEncoding = {
    * @param data
    *        A wrapped object containing raw PDU data.
    *
    * @return Decode integer value or string.
    */
   decode: function decode(data) {
     return decodeAlternatives(data, null, NullTerminatedTexts, ShortInteger);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An integer or a string value.
+   */
+  encode: function encode(data, value) {
+    if (typeof value == "number") {
+      ShortInteger.encode(data, value);
+    } else {
+      NullTerminatedTexts.encode(data, value);
+    }
+  },
 };
 
 /**
  * Value-length = Short-length | (Length-quote Length)
  * Short-length = <Any octet 0-30>
  * Length-quote = <Octet 31>
  * Length = Uintvar-integer
  *
@@ -827,16 +924,30 @@ let ValueLength = {
     }
 
     if (value == 31) {
       return UintVar.decode(data);
     }
 
     throw new CodeError("Value-length: invalid value " + value);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   */
+  encode: function encode(data, value) {
+    if (value <= 30) {
+      Octet.encode(data, value);
+    } else {
+      Octet.encode(data, 31);
+      UintVar.encode(data, value);
+    }
+  },
 };
 
 /**
  * No-value = <Octet 0>
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.3
  */
 let NoValue = {
@@ -845,16 +956,29 @@ let NoValue = {
    *        A wrapped object containing raw PDU data.
    *
    * @return Always returns null.
    */
   decode: function decode(data) {
     Octet.decodeEqualTo(data, 0);
     return null;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        A null or undefined value.
+   */
+  encode: function encode(data, value) {
+    if (value != null) {
+      throw new CodeError("No-value: invalid value " + value);
+    }
+    Octet.encode(data, 0);
+  },
 };
 
 /**
  * Text-value = No-value | Token-text | Quoted-string
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.3
  */
 let TextValue = {
@@ -862,16 +986,26 @@ let TextValue = {
    * @param data
    *        A wrapped object containing raw PDU data.
    *
    * @return Decoded string or null for No-value.
    */
   decode: function decode(data) {
     return decodeAlternatives(data, null, NoValue, TokenText, QuotedString);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param text
+   *        A null or undefined or text string.
+   */
+  encode: function encode(data, text) {
+    encodeAlternatives(data, text, null, NoValue, TokenText, QuotedString);
+  },
 };
 
 /**
  * Integer-Value = Short-integer | Long-integer
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.3
  */
 let IntegerValue = {
@@ -879,16 +1013,32 @@ let IntegerValue = {
    * @param data
    *        A wrapped object containing raw PDU data.
    *
    * @return Decoded integer value or array of octets.
    */
   decode: function decode(data) {
     return decodeAlternatives(data, null, ShortInteger, LongInteger);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An integer value or an octet array of less-equal than 31 elements.
+   */
+  encode: function encode(data, value) {
+    if (typeof value === "number") {
+      encodeAlternatives(data, value, null, ShortInteger, LongInteger);
+    } else if (Array.isArray(value) || (value instanceof Uint8Array)) {
+      LongInteger.encode(data, value);
+    } else {
+      throw new CodeError("Integer-Value: invalid value type");
+    }
+  },
 };
 
 /**
  * The encoding of dates shall be done in number of seconds from
  * 1970-01-01, 00:00:00 GMT.
  *
  *   Date-value = Long-integer
  *
@@ -910,16 +1060,31 @@ let DateValue = {
       seconds = 0;
       for (let i = 0; i < numOrArray.length; i++) {
         seconds = seconds * 256 + numOrArray[i];
       }
     }
 
     return new Date(seconds * 1000);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param date
+   *        A Date object.
+   */
+  encode: function encode(data, date) {
+    let seconds = date.getTime() / 1000;
+    if (seconds < 0) {
+      throw new CodeError("Date-value: negative seconds " + seconds);
+    }
+
+    LongInteger.encode(data, seconds);
+  },
 };
 
 /**
  * Delta-seconds-value = Integer-value
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.3
  */
 let DeltaSecondsValue = IntegerValue;
@@ -949,16 +1114,37 @@ let QValue = {
       }
       if (value <= 1099) {
         return (value - 100) / 1000.0;
       }
     }
 
     throw new CodeError("Q-value: invalid value " + value);
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An integer within the range 1..1099.
+   */
+  encode: function encode(data, value) {
+    if ((value < 0) || (value >= 1)) {
+      throw new CodeError("Q-value: invalid value " + value);
+    }
+
+    value *= 1000;
+    if ((value % 10) == 0) {
+      // Two digits only.
+      UintVar.encode(data, Math.floor(value / 10 + 1));
+    } else {
+      // Three digits.
+      UintVar.encode(data, Math.floor(value + 100));
+    }
+  },
 };
 
 /**
  * The three most significant bits of the Short-integer value are interpreted
  * to encode a major version number in the range 1-7, and the four least
  * significant bits contain a minor version number in the range 0-14. If
  * there is only a major version number, this is encoded by placing the value
  * 15 in the four least significant bits.
@@ -1002,16 +1188,30 @@ let VersionValue = {
         if (minor > 14) {
           throw new CodeError("Version-value: invalid minor " + minor);
         }
       }
     }
 
     return major << 4 | minor;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param version
+   *        A binary encoded version number.
+   */
+  encode: function encode(data, version) {
+    if ((version < 0x10) || (version >= 0x80)) {
+      throw new CodeError("Version-value: invalid version " + version);
+    }
+
+    ShortInteger.encode(data, version);
+  },
 };
 
 /**
  * URI value should be encoded per [RFC2616], but service user may use a
  * different format.
  *
  *   Uri-value = Text-string
  *
@@ -1062,16 +1262,31 @@ let TypeValue = {
     let entry = WSP_WELL_KNOWN_CONTENT_TYPES[number];
     if (!entry) {
       throw new NotWellKnownEncodingError(
         "Constrained-media: not well known media " + number);
     }
 
     return entry.type;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param type
+   *        A content type string.
+   */
+  encode: function encode(data, type) {
+    let entry = WSP_WELL_KNOWN_CONTENT_TYPES[type.toLowerCase()];
+    if (entry) {
+      ShortInteger.encode(data, entry.number);
+    } else {
+      NullTerminatedTexts.encode(data, type);
+    }
+  },
 };
 
 /**
  * Parameter = Typed-parameter | Untyped-parameter
  *
  * For Typed-parameters, the actual expected type of the value is implied by
  * the well-known parameter. In addition to the expected type, there may be no
  * value. If the value cannot be encoded using expected type, it shall be
@@ -1215,16 +1430,73 @@ let Parameter = {
           params = {};
         }
         params[param.name] = param.value;
       }
     }
 
     return params;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param param
+   *        An object containing `name` and `value` properties.
+   */
+  encodeTypedParameter: function decodeTypedParameter(data, param) {
+    let entry = WSP_WELL_KNOWN_PARAMS[param.name.toLowerCase()];
+    if (!entry) {
+      throw new NotWellKnownEncodingError(
+        "Typed-parameter: not well known parameter " + param.name);
+    }
+
+    IntegerValue.encode(data, entry.number);
+    encodeAlternatives(data, param.value, null,
+                       entry.coder, TextValue, TextString);
+  },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param param
+   *        An object containing `name` and `value` properties.
+   */
+  encodeUntypedParameter: function encodeUntypedParameter(data, param) {
+    TokenText.encode(data, param.name);
+    encodeAlternatives(data, param.value, null, IntegerValue, TextValue);
+  },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param param
+   *        An array of parameter objects.
+   */
+  encodeMultiple: function encodeMultiple(data, params) {
+    for (let name in params) {
+      this.encode(data, {name: name, value: params[name]});
+    }
+  },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param param
+   *        An object containing `name` and `value` properties.
+   */
+  encode: function encode(data, param) {
+    let begin = data.offset;
+    try {
+      this.encodeTypedParameter(data, param);
+    } catch (e) {
+      data.offset = begin;
+      this.encodeUntypedParameter(data, param);
+    }
+  },
 };
 
 /**
  * Header = Message-header | Shift-sequence
  * Message-header = Well-known-header | Application-header
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.6
  */
@@ -1250,16 +1522,32 @@ let Header = {
    *         in case of a failed parsing. The `name` property must be a string,
    *         but the `value` property can be many different types depending on
    *         `name`.
    */
   decode: function decode(data) {
     // TODO: support header code page shift-sequence
     return this.decodeMessageHeader(data);
   },
+
+  encodeMessageHeader: function encodeMessageHeader(data, header) {
+    encodeAlternatives(data, header, null, WellKnownHeader, ApplicationHeader);
+  },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param header
+   *        An object containing two attributes: a string-typed `name` and a
+   *        `value` of arbitrary type.
+   */
+  encode: function encode(data, header) {
+    // TODO: support header code page shift-sequence
+    this.encodeMessageHeader(data, header);
+  },
 };
 
 /**
  * Well-known-header = Well-known-field-name Wap-value
  * Well-known-field-name = Short-integer
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.6
  */
@@ -1298,16 +1586,34 @@ let WellKnownHeader = {
       return null;
     }
 
     return {
       name: entry.name,
       value: value,
     };
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param header
+   *        An object containing two attributes: a string-typed `name` and a
+   *        `value` of arbitrary type.
+   */
+  encode: function encode(data, header) {
+    let entry = WSP_HEADER_FIELDS[header.name.toLowerCase()];
+    if (!entry) {
+      throw new NotWellKnownEncodingError(
+        "Well-known-header: not well known header " + header.name);
+    }
+
+    ShortInteger.encode(data, entry.number);
+    encodeAlternatives(data, header.value, null, entry.coder, TextValue);
+  },
 };
 
 /**
  * Application-header = Token-text Application-specific-value
  * Application-specific-value = Text-string
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.6
  */
@@ -1390,16 +1696,31 @@ let FieldName = {
     let entry = WSP_HEADER_FIELDS[number];
     if (!entry) {
       throw new NotWellKnownEncodingError(
         "Field-name: not well known encoding " + number);
     }
 
     return entry.name;
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param name
+   *        A field name string.
+   */
+  encode: function encode(data, name) {
+    let entry = WSP_HEADER_FIELDS[name.toLowerCase()];
+    if (entry) {
+      ShortInteger.encode(data, entry.number);
+    } else {
+      TokenText.encode(data, name);
+    }
+  },
 };
 
 /**
  * Accept-charset-value = Constrained-charset | Accept-charset-general-form
  * Constrained-charset = Any-charset | Constrained-encoding
  * Any-charset = <Octet 128>
  * Accept-charset-general-form = Value-length (Well-known-charset | Token-text) [Q-value]
  *
@@ -1493,16 +1814,31 @@ let AcceptCharsetValue = {
     let begin = data.offset;
     try {
       return this.decodeConstrainedCharset(data);
     } catch (e) {
       data.offset = begin;
       return this.decodeAcceptCharsetGeneralForm(data);
     }
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An object with a string property `charset`.
+   */
+  encodeAnyCharset: function encodeAnyCharset(data, value) {
+    if (!value || !value.charset || (value.charset === "*")) {
+      Octet.encode(data, 128);
+      return;
+    }
+
+    throw new CodeError("Any-charset: invalid value " + value);
+  },
 };
 
 /**
  * Well-known-charset = Any-charset | Integer-value
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.8
  */
 let WellKnownCharset = {
@@ -1535,16 +1871,38 @@ let WellKnownCharset = {
     let entry = WSP_WELL_KNOWN_CHARSETS[charset];
     if (!entry) {
       throw new NotWellKnownEncodingError(
         "Well-known-charset: not well known charset " + charset);
     }
 
     return {charset: entry.name};
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   */
+  encode: function encode(data, value) {
+    let begin = data.offset;
+    try {
+      AcceptCharsetValue.encodeAnyCharset(data, value);
+      return;
+    } catch (e) {}
+
+    data.offset = begin;
+    let entry = WSP_WELL_KNOWN_CHARSETS[value.charset.toLowerCase()];
+    if (!entry) {
+      throw new NotWellKnownEncodingError(
+        "Well-known-charset: not well known charset " + value.charset);
+    }
+
+    IntegerValue.encode(data, entry.number);
+  },
 };
 
 /**
  * The short form of the Content-type-value MUST only be used when the
  * well-known media is in the range of 0-127 or a text string. In all other
  * cases the general form MUST be used.
  *
  *   Content-type-value = Constrained-media | Content-general-form
@@ -1665,16 +2023,83 @@ let ContentTypeValue = {
 
     try {
       return this.decodeConstrainedMedia(data);
     } catch (e) {
       data.offset = begin;
       return this.decodeContentGeneralForm(data);
     }
   },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An object containing `media` and `params` properties.
+   */
+  encodeConstrainedMedia: function encodeConstrainedMedia(data, value) {
+    if (value.params) {
+      throw new CodeError("Constrained-media: should use general form instread");
+    }
+
+    TypeValue.encode(data, value.media);
+  },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An object containing `media` and `params` properties.
+   */
+  encodeMediaType: function encodeMediaType(data, value) {
+    let entry = WSP_WELL_KNOWN_CONTENT_TYPES[value.media.toLowerCase()];
+    if (entry) {
+      IntegerValue.encode(data, entry.number);
+    } else {
+      NullTerminatedTexts.encode(data, value.media);
+    }
+
+    Parameter.encodeMultiple(data, value.params);
+  },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An object containing `media` and `params` properties.
+   */
+  encodeContentGeneralForm: function encodeContentGeneralForm(data, value) {
+    let begin = data.offset;
+    this.encodeMediaType(data, value);
+
+    // Calculate how much octets will be written and seek back.
+    // TODO: use memmove, see bug 730873
+    let len = data.offset - begin;
+    data.offset = begin;
+
+    ValueLength.encode(data, len);
+    this.encodeMediaType(data, value);
+  },
+
+  /**
+   * @param data
+   *        A wrapped object to store encoded raw data.
+   * @param value
+   *        An object containing `media` and `params` properties.
+   */
+  encode: function encode(data, value) {
+    let begin = data.offset;
+
+    try {
+      this.encodeConstrainedMedia(data, value);
+    } catch (e) {
+      data.offset = begin;
+      this.encodeContentGeneralForm(data, value);
+    }
+  },
 };
 
 /**
  * Application-id-value = Uri-value | App-assigned-code
  * App-assigned-code = Integer-value
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.54
  */
@@ -1864,16 +2289,95 @@ let PduHelper = {
       }
     } catch (e) {
       debug("Parse error. Message: " + e.message);
       msg = null;
     }
 
     return msg;
   },
+
+  /**
+   * @param multiStream
+   *        An exsiting nsIMultiplexInputStream.
+   * @param array
+   *        An octet array.
+   * @param length
+   *        Max number of octets to be coverted into an input stream.
+   */
+  appendArrayToMultiStream: function appendArrayToMultiStream(multiStream, array, length) {
+    let storageStream = Cc["@mozilla.org/storagestream;1"]
+                        .createInstance(Ci.nsIStorageStream);
+    storageStream.init(4096, length, null);
+
+    let boStream = Cc["@mozilla.org/binaryoutputstream;1"]
+                   .createInstance(Ci.nsIBinaryOutputStream);
+    boStream.setOutputStream(storageStream.getOutputStream(0));
+    boStream.writeByteArray(array, length);
+    boStream.close();
+
+    multiStream.appendStream(storageStream.newInputStream(0));
+  },
+
+  /**
+   * @param multiStream
+   *        An exsiting nsIMultiplexInputStream.
+   * @param parts
+   *        An array of objects representing multipart entries.
+   *
+   * @see WAP-230-WSP-20010705-a section 8.5
+   */
+  composeMultiPart: function composeMultiPart(multiStream, parts) {
+    // Encode multipart header
+    {
+      let data = {array: [], offset: 0};
+      UintVar.encode(data, parts.length);
+      debug("Encoded multipart header: " + JSON.stringify(data.array));
+      this.appendArrayToMultiStream(multiStream, data.array, data.offset);
+    }
+
+    // Encode each part
+    for (let i = 0; i < parts.length; i++) {
+      let part = parts[i];
+      let data = {array: [], offset: 0};
+
+      // Encode Content-Type
+      let contentType = part.headers["content-type"];
+      ContentTypeValue.encode(data, contentType);
+
+      // Encode other headers
+      if (Object.keys(part).length > 1) {
+        // Remove Content-Type temporarily
+        delete part.headers["content-type"];
+
+        for (let name in part.headers) {
+          Header.encode(data, {name: name, value: part.headers[name]});
+        }
+
+        // Restore Content-Type back
+        part.headers["content-type"] = contentType;
+      }
+
+      // Encode headersLen, DataLen
+      let headersLen = data.offset;
+      UintVar.encode(data, headersLen);
+      UintVar.encode(data, part.content.length);
+
+      // Move them to the beginning of encoded octet array.
+      let slice1 = data.array.slice(headersLen);
+      let slice2 = data.array.slice(0, headersLen);
+      data.array = slice1.concat(slice2);
+      debug("Encoded per-part header: " + JSON.stringify(data.array));
+
+      // Append per-part header
+      this.appendArrayToMultiStream(multiStream, data.array, data.offset);
+      // Append part content
+      this.appendArrayToMultiStream(multiStream, part.content, part.content.length);
+    }
+  },
 };
 
 // WSP Header Field Name Assignments
 // Note: Items commented out are either deprecated or not implemented.
 //       Deprecated items should only be supported for backward compatibility
 //       purpose.
 // @see WAP-230-WSP-20010705-a Appendix A. Assigned Numbers.
 const WSP_HEADER_FIELDS = (function () {
@@ -1882,16 +2386,17 @@ const WSP_HEADER_FIELDS = (function () {
     let entry = {
       name: name,
       number: number,
       coder: coder,
     };
     names[name] = names[number] = entry;
   }
 
+  // Encoding Version: 1.1
   //add("accept",               0x00);
   //add("accept-charset",       0x01); Deprecated
   //add("accept-encoding",      0x02); Deprecated
   //add("accept-language",      0x03);
   //add("accept-ranges",        0x04);
   add("age",                    0x05, DeltaSecondsValue);
   //add("allow",                0x06);
   //add("authorization",        0x07);
@@ -1929,37 +2434,43 @@ const WSP_HEADER_FIELDS = (function () {
   //add("transfer-encoding",    0x27);
   add("upgrade",                0x28, TextString);
   add("user-agent",             0x29, TextString);
   //add("vary",                 0x2A);
   add("via",                    0x2B, TextString);
   //add("warning",              0x2C);
   //add("www-authenticate",     0x2D);
   //add("content-disposition",  0x2E); Deprecated
+
+  // Encoding Version: 1.2
   add("x-wap-application-id",   0x2F, ApplicationIdValue);
   add("x-wap-content-uri",      0x30, UriValue);
   add("x-wap-initiator-uri",    0x31, UriValue);
   //add("accept-application",   0x32);
   add("bearer-indication",      0x33, IntegerValue);
   add("push-flag",              0x34, ShortInteger);
   add("profile",                0x35, UriValue);
   //add("profile-diff",         0x36);
   //add("profile-warning",      0x37); Deprecated
+
+  // Encoding Version: 1.3
   //add("expect",               0x38);
   //add("te",                   0x39);
   //add("trailer",              0x3A);
   add("accept-charset",         0x3B, AcceptCharsetValue);
   //add("accept-encoding",      0x3C);
   //add("cache-control",        0x3D); Deprecated
   //add("content-range",        0x3E);
   add("x-wap-tod",              0x3F, DateValue);
   add("content-id",             0x40, QuotedString);
   //add("set-cookie",           0x41);
   //add("cookie",               0x42);
   //add("encoding-version",     0x43);
+
+  // Encoding Version: 1.4
   //add("profile-warning",      0x44);
   //add("content-disposition",  0x45);
   //add("x-wap-security",       0x46);
   //add("cache-control",        0x47);
 
   return names;
 })();
 
@@ -1972,17 +2483,23 @@ const WSP_WELL_KNOWN_CONTENT_TYPES = (fu
     let entry = {
       type: type,
       number: number,
     };
     types[type] = types[number] = entry;
   }
 
   // Well Known Values
+  // Encoding Version: 1.1
+  add("application/vnd.wap.multipart.mixed", 0x23);
+
+  // Encoding Version: 1.2
   add("application/vnd.wap.multipart.related", 0x33);
+
+  // Encoding Version: 1.4
   add("application/vnd.wap.mms-message", 0x3E);
 
   return types;
 })();
 
 // WSP Well-Known Parameter Assignments
 // Note: Items commented out are either deprecated or not implemented.
 //       Deprecated items should not be used.
@@ -1994,41 +2511,48 @@ const WSP_WELL_KNOWN_PARAMS = (function 
     let entry = {
       name: name,
       number: number,
       coder: coder,
     };
     params[name] = params[number] = entry;
   }
 
+  // Encoding Version: 1.1
   add("q",                 0x00, QValue);
   add("charset",           0x01, WellKnownCharset);
   add("level",             0x02, VersionValue);
   add("type",              0x03, IntegerValue);
   add("name",              0x05, TextValue); // Deprecated, but used in some carriers, eg. Hinet.
   //add("filename",        0x06); Deprecated
   add("differences",       0x07, FieldName);
   add("padding",           0x08, ShortInteger);
+
+  // Encoding Version: 1.2
   add("type",              0x09, TypeValue);
   add("start",             0x0A, TextValue); // Deprecated, but used in some carriers, eg. T-Mobile.
   //add("start-info",      0x0B); Deprecated
+
+  // Encoding Version: 1.3
   //add("comment",         0x0C); Deprecated
   //add("domain",          0x0D); Deprecated
   add("max-age",           0x0E, DeltaSecondsValue);
   //add("path",            0x0F); Deprecated
   add("secure",            0x10, NoValue);
+
+  // Encoding Version: 1.4
   add("sec",               0x11, ShortInteger);
   add("mac",               0x12, TextValue);
   add("creation-date",     0x13, DateValue);
   add("modification-date", 0x14, DateValue);
   add("read-date",         0x15, DateValue);
   add("size",              0x16, IntegerValue);
-  add("name",              0x17, TextValue);
+  //add("name",            0x17, TextValue); // Not supported in some carriers, eg. Hinet.
   add("filename",          0x18, TextValue);
-  add("start",             0x19, TextValue);
+  //add("start",           0x19, TextValue); // Not supported in some carriers, eg. Hinet.
   add("start-info",        0x1A, TextValue);
   add("comment",           0x1B, TextValue);
   add("domain",            0x1C, TextValue);
   add("path",              0x1D, TextValue);
 
   return params;
 })();
 
--- a/dom/mms/src/ril/mms_consts.js
+++ b/dom/mms/src/ril/mms_consts.js
@@ -33,24 +33,61 @@ const MMS_PDU_TYPE_CANCEL_CONF = 151;
 // @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.34
 const MMS_VERSION = (0x01 << 4) | 0x03;
 
 // Common Status Values
 const MMS_PDU_ERROR_OK                = 128;
 const MMS_PDU_ERROR_TRANSIENT_FAILURE = 192;
 const MMS_PDU_ERROR_PERMANENT_FAILURE = 224;
 
+// X-Mms-Response-Status values
+// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.48
+// @see OMA-TS-MMS_ENC-V1_3-20110913-A Table 28, 29, 30
+//const MMS_PDU_RESPONSE_ERROR_UNSPECIFIED                                 = 129; (obsolete)
+//const MMS_PDU_RESPONSE_ERROR_SERVICE_DENIED                              = 130; (obsolete)
+//const MMS_PDU_RESPONSE_ERROR_MESSAGE_FORMAT_CORRUPT                      = 131; (obsolete)
+//const MMS_PDU_RESPONSE_ERROR_SENDING_ADDRESS_UNRESOLVED                  = 132; (obsolete)
+//const MMS_PDU_RESPONSE_ERROR_MESSAGE_NOT_FOUND                           = 133; (obsolete)
+//const MMS_PDU_RESPONSE_ERROR_NETWORK_PROBLEM                             = 134; (obsolete)
+//const MMS_PDU_RESPONSE_ERROR_CONTENT_NOT_ACCEPTED                        = 135; (obsolete)
+const MMS_PDU_RESPONSE_ERROR_UNSUPPORTED_MESSAGE                           = 136;
+const MMS_PDU_RESPONSE_ERROR_TRANSIENT_SENDING_ADDRESS_UNRESOLVED          = 193;
+const MMS_PDU_RESPONSE_ERROR_TRANSIENT_MESSAGE_NOT_FOUND                   = 194;
+const MMS_PDU_RESPONSE_ERROR_TRANSIENT_NETWORK_PROBLEM                     = 195;
+const MMS_PDU_RESPONSE_ERROR_TRANSIENT_PARTIAL_SUCCESS                     = 196;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_SERVICE_DENIED                      = 225;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT              = 226;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_SENDING_ADDRESS_UNRESOLVED          = 227;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_MESSAGE_NOT_FOUND                   = 228;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_CONTENT_NOT_ACCEPTED                = 229;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_REPLY_CHARGING_LIMITATIONS_NOT_MET  = 230;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_REPLY_CHARGING_REQUEST_NOT_ACCEPTED = 231;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_REPLY_CHARGING_FORWARDING_DENIED    = 232;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_REPLY_CHARGING_NOT_SUPPORTED        = 233;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_ADDRESS_HIDING_NOT_SUPPORTED        = 234;
+const MMS_PDU_RESPONSE_ERROR_PERMANENT_LACK_OF_PREPAID                     = 235;
+
 // X-Mms-Retrieve-Status values
 // @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.50
+// @see OMA-TS-MMS_ENC-V1_3-20110913-A Table 31
 const MMS_PDU_RETRIEVE_ERROR_TRANSIENT_MESSAGE_NOT_FOUND   = 193;
 const MMS_PDU_RETRIEVE_ERROR_TRANSIENT_NETWORK_PROBLEM     = 194;
 const MMS_PDU_RETRIEVE_ERROR_PERMANENT_SERVICE_DENIED      = 225;
 const MMS_PDU_RETRIEVE_ERROR_PERMANENT_MESSAGE_NOT_FOUND   = 226;
 const MMS_PDU_RETRIEVE_ERROR_PERMANENT_CONTENT_UNSUPPORTED = 227;
 
+// X-Mms-Store-Status values
+// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.58
+// @see OMA-TS-MMS_ENC-V1_3-20110913-A Table 35
+const MMS_PDU_STORE_ERROR_TRANSIENT_NETWORK_PROBLEM        = 193;
+const MMS_PDU_STORE_ERROR_PERMANENT_SERVICE_DENIED         = 225;
+const MMS_PDU_STORE_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT = 226;
+const MMS_PDU_STORE_ERROR_PERMANENT_MESSAGE_NOT_FOUND      = 227;
+const MMS_PDU_STORE_ERROR_PERMANENT_MMBOX_FULL             = 228;
+
 // X-Mms-Status values
 // @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.54
 const MMS_PDU_STATUS_EXPIRED       = 128;
 const MMS_PDU_STATUS_RETRIEVED     = 129;
 const MMS_PDU_STATUS_REJECTED      = 130;
 const MMS_PDU_STATUS_DEFERRED      = 131;
 const MMS_PDU_STATUS_UNRECOGNISED  = 132;
 const MMS_PDU_STATUS_INDETERMINATE = 133;
--- a/dom/mms/tests/test_mms_pdu_helper.js
+++ b/dom/mms/tests/test_mms_pdu_helper.js
@@ -66,19 +66,58 @@ add_test(function test_Address_decode() 
                       {address: "+123", type: "num"});
   wsp_decode_test(MMS.Address, strToCharCodeArray("*123"),
                       {address: "*123", type: "num"});
   wsp_decode_test(MMS.Address, strToCharCodeArray("#123"),
                       {address: "#123", type: "num"});
   // Test for alphanum-shortcode
   wsp_decode_test(MMS.Address, strToCharCodeArray("H0wD0Y0uTurnTh1s0n"),
                       {address: "H0wD0Y0uTurnTh1s0n", type: "alphanum"});
-  // Test for other unknown typed sequence
+  // Test for email address
   wsp_decode_test(MMS.Address, strToCharCodeArray("Joe User <joe@user.org>"),
-                      {address: "Joe User <joe@user.org>", type: "unknown"});
+                      {address: "Joe User <joe@user.org>", type: "email"});
+  // Test for invalid address
+  wsp_decode_test(MMS.Address, strToCharCodeArray("@@@@@"),
+                  null, "CodeError");
+
+  run_next_test();
+});
+
+//// Address.encode ////
+
+add_test(function test_Address_encode() {
+  // Test for PLMN address
+  wsp_encode_test(MMS.Address, {address: "+123.456-789", type: "PLMN"},
+                  strToCharCodeArray("+123.456-789/TYPE=PLMN"));
+  wsp_encode_test(MMS.Address, {address: "123456789", type: "PLMN"},
+                  strToCharCodeArray("123456789/TYPE=PLMN"));
+  // Test for IPv4
+  wsp_encode_test(MMS.Address, {address: "1.2.3.4", type: "IPv4"},
+                  strToCharCodeArray("1.2.3.4/TYPE=IPv4"));
+  // Test for IPv6
+  wsp_encode_test(MMS.Address,
+    {address: "1111:AAAA:bbbb:CdEf:1ABC:2cde:3Def:0000", type: "IPv6"},
+    strToCharCodeArray("1111:AAAA:bbbb:CdEf:1ABC:2cde:3Def:0000/TYPE=IPv6")
+  );
+  // Test for other device-address
+  wsp_encode_test(MMS.Address, {address: "+H-e.l%l_o", type: "W0r1d_"},
+                  strToCharCodeArray("+H-e.l%l_o/TYPE=W0r1d_"));
+  // Test for num-shortcode
+  wsp_encode_test(MMS.Address, {address: "+123", type: "num"},
+                  strToCharCodeArray("+123"));
+  wsp_encode_test(MMS.Address, {address: "*123", type: "num"},
+                  strToCharCodeArray("*123"));
+  wsp_encode_test(MMS.Address, {address: "#123", type: "num"},
+                  strToCharCodeArray("#123"));
+  // Test for alphanum-shortcode
+  wsp_encode_test(MMS.Address, {address: "H0wD0Y0uTurnTh1s0n", type: "alphanum"},
+                  strToCharCodeArray("H0wD0Y0uTurnTh1s0n"));
+  // Test for email address
+  wsp_encode_test(MMS.Address, {address: "Joe User <joe@user.org>", type: "email"},
+                  strToCharCodeArray("Joe User <joe@user.org>"));
 
   run_next_test();
 });
 
 //
 // Test target: HeaderField
 //
 
@@ -151,16 +190,30 @@ add_test(function test_ContentClassValue
     } else {
       wsp_decode_test(MMS.ContentClassValue, [i], null, "CodeError");
     }
   }
 
   run_next_test();
 });
 
+//// ContentClassValue.encode ////
+
+add_test(function test_ContentClassValue_encode() {
+  for (let i = 0; i < 256; i++) {
+    if ((i >= 128) && (i <= 135)) {
+      wsp_encode_test(MMS.ContentClassValue, i, [i]);
+    } else {
+      wsp_encode_test(MMS.ContentClassValue, i, null, "CodeError");
+    }
+  }
+
+  run_next_test();
+});
+
 //
 // Test target: ContentLocationValue
 //
 
 //// ContentLocationValue.decode ////
 
 add_test(function test_ContentLocationValue_decode() {
   // Test for MMS_PDU_TYPE_MBOX_DELETE_CONF & MMS_PDU_TYPE_DELETE_CONF
@@ -258,16 +311,34 @@ add_test(function test_Parameter_decodeM
   //    return MMS.Parameter.decodeMultiple(data, data.array.length);
   //  }, [0x80 | 0x02, 0x80 | 0x00].concat(strToCharCodeArray("good")).concat([0x80 | 0x01]),
   //  {type: 0, good: 1}
   //);
 
   run_next_test();
 });
 
+//// Parameter.encode ////
+
+add_test(function test_Parameter_encode() {
+  // Test for invalid parameter value
+  wsp_encode_test(MMS.Parameter, null, null, "CodeError");
+  wsp_encode_test(MMS.Parameter, undefined, null, "CodeError");
+  wsp_encode_test(MMS.Parameter, {}, null, "CodeError");
+  // Test for case-insensitive parameter name
+  wsp_encode_test(MMS.Parameter, {name: "TYPE", value: 0}, [130, 128]);
+  wsp_encode_test(MMS.Parameter, {name: "type", value: 0}, [130, 128]);
+  // Test for non-well-known parameter name
+  wsp_encode_test(MMS.Parameter, {name: "name", value: 0}, [110, 97, 109, 101, 0, 128]);
+  // Test for constrained encoding value
+  wsp_encode_test(MMS.Parameter, {name: "type", value: "0"}, [130, 48, 0]);
+
+  run_next_test();
+});
+
 //
 // Test target: EncodedStringValue
 //
 
 //// EncodedStringValue.decode ////
 
 add_test(function test_EncodedStringValue_decode() {
   // Test for normal TextString
@@ -286,31 +357,64 @@ add_test(function test_EncodedStringValu
     let raw = conv.convertToByteArray(str).concat([0]);
     wsp_decode_test(MMS.EncodedStringValue,
                     [raw.length + 2, 0x80 | entry.number, 127].concat(raw), str);
   }
 
   run_next_test();
 });
 
+//// EncodedStringValue.encode ////
+
+add_test(function test_EncodedStringValue_encode() {
+  // Test for normal TextString
+  wsp_encode_test(MMS.EncodedStringValue, "Hello", strToCharCodeArray("Hello"));
+  // Test for utf-8
+  let (entry = MMS.WSP.WSP_WELL_KNOWN_CHARSETS["utf-8"]) {
+    // "Mozilla" in full width.
+    let str = "\uff2d\uff4f\uff5a\uff49\uff4c\uff4c\uff41";
+
+    let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+               .createInstance(Ci.nsIScriptableUnicodeConverter);
+    conv.charset = entry.converter;
+
+    let raw = conv.convertToByteArray(str).concat([0]);
+    wsp_encode_test(MMS.EncodedStringValue, str,
+                    [raw.length + 2, 0x80 | entry.number, 127].concat(raw));
+  }
+
+  run_next_test();
+});
+
 //
 // Test target: ExpiryValue
 //
 
 //// ExpiryValue.decode ////
 
 add_test(function test_ExpiryValue_decode() {
   // Test for Absolute-token Date-value
   wsp_decode_test(MMS.ExpiryValue, [3, 128, 1, 0x80], new Date(0x80 * 1000));
   // Test for Relative-token Delta-seconds-value
   wsp_decode_test(MMS.ExpiryValue, [2, 129, 0x80], 0);
 
   run_next_test();
 });
 
+//// ExpiryValue.encode ////
+
+add_test(function test_ExpiryValue_encode() {
+  // Test for Absolute-token Date-value
+  wsp_encode_test(MMS.ExpiryValue, new Date(0x80 * 1000), [3, 128, 1, 0x80]);
+  // Test for Relative-token Delta-seconds-value
+  wsp_encode_test(MMS.ExpiryValue, 0, [2, 129, 0x80]);
+
+  run_next_test();
+});
+
 //
 // Test target: PreviouslySentByValue
 //
 
 //// PreviouslySentByValue.decode ////
 
 add_test(function test_PreviouslySentByValue_decode() {
   wsp_decode_test(MMS.PreviouslySentByValue, [3, 0x80 | 0x03, 65, 0],
@@ -346,16 +450,30 @@ add_test(function test_FromValue_decode(
   let (addr = strToCharCodeArray("+123/TYPE=PLMN")) {
     wsp_decode_test(MMS.FromValue, [addr.length + 1, 128].concat(addr),
                         {address: "+123", type: "PLMN"});
   }
 
   run_next_test();
 });
 
+//// FromValue.encode ////
+
+add_test(function test_FromValue_encode() {
+  // Test for Insert-address-token:
+  wsp_encode_test(MMS.FromValue, null, [1, 129]);
+  // Test for Address-present-token:
+  let (addr = strToCharCodeArray("+123/TYPE=PLMN")) {
+    wsp_encode_test(MMS.FromValue, {address: "+123", type: "PLMN"},
+                    [addr.length + 1, 128].concat(addr));
+  }
+
+  run_next_test();
+});
+
 //
 // Test target: MessageClassValue
 //
 
 //// MessageClassValue.decodeClassIdentifier ////
 
 add_test(function test_MessageClassValue_decodeClassIdentifier() {
   let (IDs = ["personal", "advertisement", "informational", "auto"]) {
@@ -381,16 +499,28 @@ add_test(function test_MessageClassValue
 
 add_test(function test_MessageClassValue_decode() {
   wsp_decode_test(MMS.MessageClassValue, [65, 0], "A");
   wsp_decode_test(MMS.MessageClassValue, [128], "personal");
 
   run_next_test();
 });
 
+//// MessageClassValue.encode ////
+
+add_test(function test_MessageClassValue_encode() {
+  wsp_encode_test(MMS.MessageClassValue, "personal", [128]);
+  wsp_encode_test(MMS.MessageClassValue, "advertisement", [129]);
+  wsp_encode_test(MMS.MessageClassValue, "informational", [130]);
+  wsp_encode_test(MMS.MessageClassValue, "auto", [131]);
+  wsp_encode_test(MMS.MessageClassValue, "A", [65, 0]);
+
+  run_next_test();
+});
+
 //
 // Test target: MessageTypeValue
 //
 
 //// MessageTypeValue.decode ////
 
 add_test(function test_MessageTypeValue_decode() {
   for (let i = 0; i < 256; i++) {
@@ -431,16 +561,30 @@ add_test(function test_MmFlagsValue_deco
     } else {
       wsp_decode_test(MMS.MmFlagsValue, [3, i, 65, 0], null, "CodeError");
     }
   }
 
   run_next_test();
 });
 
+//// MmFlagsValue.encode ////
+
+add_test(function test_MmFlagsValue_encode() {
+  for (let i = 0; i < 256; i++) {
+    if ((i >= 128) && (i <= 130)) {
+      wsp_encode_test(MMS.MmFlagsValue, {type: i, text: "A"}, [3, i, 65, 0]);
+    } else {
+      wsp_encode_test(MMS.MmFlagsValue, {type: i, text: "A"}, null, "CodeError");
+    }
+  }
+
+  run_next_test();
+});
+
 //
 // Test target: MmStateValue
 //
 
 //// MmStateValue.decode ////
 
 add_test(function test_MmStateValue_decode() {
   for (let i = 0; i < 256; i++) {
@@ -449,16 +593,30 @@ add_test(function test_MmStateValue_deco
     } else {
       wsp_decode_test(MMS.MmStateValue, [i], null, "CodeError");
     }
   }
 
   run_next_test();
 });
 
+//// MmStateValue.encode ////
+
+add_test(function test_MmStateValue_encode() {
+  for (let i = 0; i < 256; i++) {
+    if ((i >= 128) && (i <= 132)) {
+      wsp_encode_test(MMS.MmStateValue, i, [i]);
+    } else {
+      wsp_encode_test(MMS.MmStateValue, i, null, "CodeError");
+    }
+  }
+
+  run_next_test();
+});
+
 //
 // Test target: PriorityValue
 //
 
 //// PriorityValue.decode ////
 
 add_test(function test_PriorityValue_decode() {
   for (let i = 0; i < 256; i++) {
@@ -467,16 +625,30 @@ add_test(function test_PriorityValue_dec
     } else {
       wsp_decode_test(MMS.PriorityValue, [i], null, "CodeError");
     }
   }
 
   run_next_test();
 });
 
+//// PriorityValue.encode ////
+
+add_test(function test_PriorityValue_encode() {
+  for (let i = 0; i < 256; i++) {
+    if ((i >= 128) && (i <= 130)) {
+      wsp_encode_test(MMS.PriorityValue, i, [i]);
+    } else {
+      wsp_encode_test(MMS.PriorityValue, i, null, "CodeError");
+    }
+  }
+
+  run_next_test();
+});
+
 //
 // Test target: RecommendedRetrievalModeValue
 //
 
 //// RecommendedRetrievalModeValue.decode ////
 
 add_test(function test_RecommendedRetrievalModeValue_decode() {
   for (let i = 0; i < 256; i++) {
@@ -503,16 +675,68 @@ add_test(function test_ReplyChargingValu
     } else {
       wsp_decode_test(MMS.ReplyChargingValue, [i], null, "CodeError");
     }
   }
 
   run_next_test();
 });
 
+//// ReplyChargingValue.encode ////
+
+add_test(function test_ReplyChargingValue_encode() {
+  for (let i = 0; i < 256; i++) {
+    if ((i >= 128) && (i <= 131)) {
+      wsp_encode_test(MMS.ReplyChargingValue, i, [i]);
+    } else {
+      wsp_encode_test(MMS.ReplyChargingValue, i, null, "CodeError");
+    }
+  }
+
+  run_next_test();
+});
+
+//
+// Test target: ResponseText
+//
+
+//// ResponseText.decode ////
+
+add_test(function test_ResponseText_decode() {
+  // Test for MMS_PDU_TYPE_MBOX_DELETE_CONF & MMS_PDU_TYPE_DELETE_CONF
+  wsp_decode_test_ex(function (data) {
+      data.array[0] = data.array.length - 1;
+
+      let options = {};
+      options["x-mms-message-type"] = MMS_PDU_TYPE_MBOX_DELETE_CONF;
+      return MMS.ResponseText.decode(data, options);
+    }, [0, 0x80 | 0x00].concat(strToCharCodeArray("http://no.such.com/path")),
+    {statusCount: 0, text: "http://no.such.com/path"}
+  );
+  wsp_decode_test_ex(function (data) {
+      data.array[0] = data.array.length - 1;
+
+      let options = {};
+      options["x-mms-message-type"] = MMS_PDU_TYPE_DELETE_CONF;
+      return MMS.ResponseText.decode(data, options);
+    }, [0, 0x80 | 0x00].concat(strToCharCodeArray("http://no.such.com/path")),
+    {statusCount: 0, text: "http://no.such.com/path"}
+  );
+  // Test for other situations
+  wsp_decode_test_ex(function (data) {
+      let options = {};
+      options["x-mms-message-type"] = MMS_PDU_TYPE_SEND_REQ;
+      return MMS.ResponseText.decode(data, options);
+    }, strToCharCodeArray("http://no.such.com/path"),
+    {text: "http://no.such.com/path"}
+  );
+
+  run_next_test();
+});
+
 //
 // Test target: RetrieveStatusValue
 //
 
 //// RetrieveStatusValue.decode ////
 
 add_test(function test_RetrieveStatusValue_decode() {
   for (let i = 0; i < 256; i++) {
@@ -577,17 +801,17 @@ add_test(function test_PduHelper_parseHe
   let expect = {};
   expect["x-mms-mms-version"] = MMS_VERSION;
   expect["content-type"] = {
     media: "application/vnd.wap.multipart.related",
     params: null,
   };
   parse([0x80 | 0x0D, 0x80 | MMS_VERSION,   // X-Mms-Mms-Version: 1.3
          0x80 | 0x04, 0x80 | 0x33,          // Content-Type: application/vnd.wap.multipart.related
-	 0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ // X-Mms-Message-Type: M-Send.req
+         0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ // X-Mms-Message-Type: M-Send.req
         ], expect);
 
   // Parse header fields with multiple entries
   expect = {
     to: [
       { address: "+123", type: "PLMN" },
       { address: "+456", type: "num" },
     ],
@@ -598,8 +822,88 @@ add_test(function test_PduHelper_parseHe
   };
   parse(Array.concat([0x80 | 0x17]).concat(strToCharCodeArray("+123/TYPE=PLMN"))
              .concat([0x80 | 0x17]).concat(strToCharCodeArray("+456"))
              .concat([0x80 | 0x04, 0x80 | 0x33]),
         expect);
 
   run_next_test();
 });
+
+//// PduHelper.encodeHeader ////
+
+add_test(function test_PduHelper_encodeHeader() {
+  function func(name, data, headers) {
+    MMS.PduHelper.encodeHeader(data, headers, name);
+
+    // Remove extra space consumed during encoding.
+    while (data.array.length > data.offset) {
+      data.array.pop();
+    }
+
+    return data.array;
+  }
+
+  // Encode header fields with multiple entries
+  let headers = {
+    to: [
+      { address: "+123", type: "PLMN" },
+      { address: "+456", type: "num" },
+    ],
+  };
+  wsp_encode_test_ex(func.bind(null, "to"), headers,
+                     Array.concat([0x80 | 0x17]).concat(strToCharCodeArray("+123/TYPE=PLMN"))
+                          .concat([0x80 | 0x17]).concat(strToCharCodeArray("+456")));
+
+  run_next_test();
+});
+
+//// PduHelper.encodeHeaderIfExists ////
+
+add_test(function test_PduHelper_encodeHeaderIfExists() {
+  function func(name, data, headers) {
+    MMS.PduHelper.encodeHeaderIfExists(data, headers, name);
+
+    // Remove extra space consumed during encoding.
+    while (data.array.length > data.offset) {
+      data.array.pop();
+    }
+
+    return data.array;
+  }
+
+  wsp_encode_test_ex(func.bind(null, "to"), {}, []);
+
+  run_next_test();
+});
+
+//// PduHelper.encodeHeaders ////
+
+add_test(function test_PduHelper_encodeHeaders() {
+  function func(data, headers) {
+    MMS.PduHelper.encodeHeaders(data, headers);
+
+    // Remove extra space consumed during encoding.
+    while (data.array.length > data.offset) {
+      data.array.pop();
+    }
+
+    return data.array;
+  }
+
+  let headers = {};
+  headers["x-mms-message-type"] = MMS_PDU_TYPE_SEND_REQ;
+  headers["x-mms-mms-version"] = MMS_VERSION;
+  headers["x-mms-transaction-id"] = "asdf";
+  headers["to"] = { address: "+123", type: "PLMN" };
+  headers["content-type"] = {
+    media: "application/vnd.wap.multipart.related",
+  };
+  wsp_encode_test_ex(func, headers,
+                     Array.concat([0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ])
+                          .concat([0x80 | 0x18]).concat(strToCharCodeArray(headers["x-mms-transaction-id"]))
+                          .concat([0x80 | 0x0D, 0x80 | MMS_VERSION])
+                          .concat([0x80 | 0x17]).concat(strToCharCodeArray("+123/TYPE=PLMN"))
+                          .concat([0x80 | 0x04, 0x80 | 0x33]));
+
+  run_next_test();
+});
+
--- a/dom/mms/tests/test_wsp_pdu_helper.js
+++ b/dom/mms/tests/test_wsp_pdu_helper.js
@@ -102,16 +102,27 @@ add_test(function test_Octet_decodeEqual
 add_test(function test_Octet_encode() {
   for (let i = 0; i < 256; i++) {
     wsp_encode_test(WSP.Octet, i, [i]);
   }
 
   run_next_test();
 });
 
+//// Octet.encodeMultiple ////
+
+add_test(function test_Octet_encodeMultiple() {
+  wsp_encode_test_ex(function (data, input) {
+    WSP.Octet.encodeMultiple(data, input);
+    return data.array;
+  }, [0, 1, 2, 3], [0, 1, 2, 3]);
+
+  run_next_test();
+});
+
 //
 // Test target: Text
 //
 
 //// Text.decode ////
 
 add_test(function test_Text_decode() {
   for (let i = 0; i < 256; i++) {
@@ -298,16 +309,24 @@ add_test(function test_QuotedString_deco
   wsp_decode_test(WSP.QuotedString, [32, 0], null, "CodeError");
   // Test incompleted string
   wsp_decode_test(WSP.QuotedString, [34, 32], null, "RangeError");
   wsp_decode_test(WSP.QuotedString, [34, 32, 0], " ");
 
   run_next_test();
 });
 
+//// QuotedString.encode ////
+
+add_test(function test_QuotedString_encode() {
+  wsp_encode_test(WSP.QuotedString, "B2G", [34].concat(strToCharCodeArray("B2G")));
+
+  run_next_test();
+});
+
 //
 // Test target: ShortInteger
 //
 
 //// ShortInteger.decode ////
 
 add_test(function test_ShortInteger_decode() {
   for (let i = 0; i < 256; i++) {
@@ -336,32 +355,63 @@ add_test(function test_ShortInteger_enco
 });
 
 //
 // Test target: LongInteger
 //
 
 //// LongInteger.decode ////
 
-function LongInteger_testcases(target) {
+function LongInteger_decode_testcases(target) {
   // Test LongInteger of zero octet
   wsp_decode_test(target, [0, 0], null, "CodeError");
   wsp_decode_test(target, [1, 0x80], 0x80);
   wsp_decode_test(target, [2, 0x80, 2], 0x8002);
   wsp_decode_test(target, [3, 0x80, 2, 3], 0x800203);
   wsp_decode_test(target, [4, 0x80, 2, 3, 4], 0x80020304);
   wsp_decode_test(target, [5, 0x80, 2, 3, 4, 5], 0x8002030405);
   wsp_decode_test(target, [6, 0x80, 2, 3, 4, 5, 6], 0x800203040506);
   // Test LongInteger of more than 6 octets
   wsp_decode_test(target, [7, 0x80, 2, 3, 4, 5, 6, 7], [0x80, 2, 3, 4, 5, 6, 7]);
   // Test LongInteger of more than 30 octets
   wsp_decode_test(target, [31], null, "CodeError");
 }
 add_test(function test_LongInteger_decode() {
-  LongInteger_testcases(WSP.LongInteger);
+  LongInteger_decode_testcases(WSP.LongInteger);
+
+  run_next_test();
+});
+
+//// LongInteger.encode ////
+
+function LongInteger_encode_testcases(target) {
+  wsp_encode_test(target, 0x80,           [1, 0x80]);
+  wsp_encode_test(target, 0x8002,         [2, 0x80, 2]);
+  wsp_encode_test(target, 0x800203,       [3, 0x80, 2, 3]);
+  wsp_encode_test(target, 0x80020304,     [4, 0x80, 2, 3, 4]);
+  wsp_encode_test(target, 0x8002030405,   [5, 0x80, 2, 3, 4, 5]);
+  wsp_encode_test(target, 0x800203040506, [6, 0x80, 2, 3, 4, 5, 6]);
+  // Test LongInteger of more than 6 octets
+  wsp_encode_test(target, 0x1000000000000, null, "CodeError");
+  // Test input empty array
+  wsp_encode_test(target, [], null, "CodeError");
+  // Test input octets array of length 1..30
+  let array = [];
+  for (let i = 1; i <= 30; i++) {
+    array.push(i);
+    wsp_encode_test(target, array, [i].concat(array));
+  }
+  // Test input octets array of 31 elements.
+  array.push(31);
+  wsp_encode_test(target, array, null, "CodeError");
+}
+add_test(function test_LongInteger_encode() {
+  wsp_encode_test(WSP.LongInteger, 0, [1, 0]);
+
+  LongInteger_encode_testcases(WSP.LongInteger);
 
   run_next_test();
 });
 
 //
 // Test target: UintVar
 //
 
@@ -380,29 +430,55 @@ add_test(function test_UintVar_decode() 
   wsp_decode_test(WSP.UintVar, [0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F], 0x1FFFFFFFFFFFFF);
   wsp_decode_test(WSP.UintVar, [0x01, 0x02], 1);
   wsp_decode_test(WSP.UintVar, [0x80, 0x01, 0x02], 1);
   wsp_decode_test(WSP.UintVar, [0x80, 0x80, 0x80, 0x01, 0x2], 1);
 
   run_next_test();
 });
 
+//// UintVar.encode ////
+
+add_test(function test_UintVar_encode() {
+  // Test up to max 53 bits integer
+  wsp_encode_test(WSP.UintVar, 0, [0]);
+  wsp_encode_test(WSP.UintVar, 0x7F, [0x7F]);
+  wsp_encode_test(WSP.UintVar, 0x3FFF, [0xFF, 0x7F]);
+  wsp_encode_test(WSP.UintVar, 0x1FFFFF, [0xFF, 0xFF, 0x7F]);
+  wsp_encode_test(WSP.UintVar, 0xFFFFFFF, [0xFF, 0xFF, 0xFF, 0x7F]);
+  wsp_encode_test(WSP.UintVar, 0x7FFFFFFFF, [0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
+  wsp_encode_test(WSP.UintVar, 0x3FFFFFFFFFF, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
+  wsp_encode_test(WSP.UintVar, 0x1FFFFFFFFFFFF, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
+  wsp_encode_test(WSP.UintVar, 0x1FFFFFFFFFFFFF, [0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
+
+  run_next_test();
+});
+
 //
-// Test target: ConstrainedEncoding (decodeAlternatives)
+// Test target: ConstrainedEncoding
 //
 
 //// ConstrainedEncoding.decode ////
 
 add_test(function test_ConstrainedEncoding_decode() {
   wsp_decode_test(WSP.ConstrainedEncoding, [0x80], 0);
   wsp_decode_test(WSP.ConstrainedEncoding, [32, 0], " ");
 
   run_next_test();
 });
 
+//// ConstrainedEncoding.encode ////
+
+add_test(function test_ConstrainedEncoding_encode() {
+  wsp_encode_test(WSP.ConstrainedEncoding, 0, [0x80 | 0]);
+  wsp_encode_test(WSP.ConstrainedEncoding, "A", [65, 0]);
+
+  run_next_test();
+});
+
 //
 // Test target: ValueLength
 //
 
 //// ValueLength.decode ////
 
 add_test(function test_ValueLength_decode() {
   for (let i = 0; i < 256; i++) {
@@ -413,58 +489,111 @@ add_test(function test_ValueLength_decod
     } else {
       wsp_decode_test(WSP.ValueLength, [i, 0x8F, 0x7F], null, "CodeError");
     }
   }
 
   run_next_test();
 });
 
+//// ValueLength.encode ////
+
+add_test(function test_ValueLength_encode() {
+  for (let i = 0; i < 256; i++) {
+    if (i < 31) {
+      wsp_encode_test(WSP.ValueLength, i, [i]);
+    } else if (i < 128) {
+      wsp_encode_test(WSP.ValueLength, i, [31, i]);
+    } else {
+      wsp_encode_test(WSP.ValueLength, i, [31, (0x80 | (i / 128)), i % 128]);
+    }
+  }
+
+  run_next_test();
+});
+
 //
 // Test target: NoValue
 //
 
 //// NoValue.decode ////
 
 add_test(function test_NoValue_decode() {
   wsp_decode_test(WSP.NoValue, [0], null);
   for (let i = 1; i < 256; i++) {
     wsp_decode_test(WSP.NoValue, [i], null, "CodeError");
   }
 
   run_next_test();
 });
 
+//// NoValue.encode ////
+
+add_test(function test_NoValue_encode() {
+  wsp_encode_test(WSP.NoValue, undefined, [0]);
+  wsp_encode_test(WSP.NoValue, null, [0]);
+  wsp_encode_test(WSP.NoValue, 0, null, "CodeError");
+  wsp_encode_test(WSP.NoValue, "", null, "CodeError");
+  wsp_encode_test(WSP.NoValue, [], null, "CodeError");
+  wsp_encode_test(WSP.NoValue, {}, null, "CodeError");
+
+  run_next_test();
+});
+
 //
 // Test target: TextValue
 //
 
 //// TextValue.decode ////
 
 add_test(function test_TextValue_decode() {
   wsp_decode_test(WSP.TextValue, [0], null);
   wsp_decode_test(WSP.TextValue, [65, 0], "A");
   wsp_decode_test(WSP.TextValue, [32, 0], null, "CodeError");
   wsp_decode_test(WSP.TextValue, [34, 32, 0], " ");
 
   run_next_test();
 });
 
+//// TextValue.encode ////
+
+add_test(function test_TextValue_encode() {
+  wsp_encode_test(WSP.TextValue, undefined, [0]);
+  wsp_encode_test(WSP.TextValue, null, [0]);
+  wsp_encode_test(WSP.TextValue, "", [0]);
+  wsp_encode_test(WSP.TextValue, "A", [65, 0]);
+  wsp_encode_test(WSP.TextValue, "\x80", [34, 128, 0]);
+
+  run_next_test();
+});
+
 //
 // Test target: IntegerValue
 //
 
 //// IntegerValue.decode ////
 
 add_test(function test_IntegerValue_decode() {
   for (let i = 128; i < 256; i++) {
     wsp_decode_test(WSP.IntegerValue, [i], i & 0x7F);
   }
 
-  LongInteger_testcases(WSP.IntegerValue);
+  LongInteger_decode_testcases(WSP.IntegerValue);
+
+  run_next_test();
+});
+
+//// IntegerValue.decode ////
+
+add_test(function test_IntegerValue_encode() {
+  for (let i = 0; i < 128; i++) {
+    wsp_encode_test(WSP.IntegerValue, i, [0x80 | i]);
+  }
+
+  LongInteger_encode_testcases(WSP.IntegerValue);
 
   run_next_test();
 });
 
 //
 // Test target: DateValue
 //
 
@@ -473,16 +602,24 @@ add_test(function test_IntegerValue_deco
 add_test(function test_DateValue_decode() {
   wsp_decode_test(WSP.DateValue, [0, 0], null, "CodeError");
   wsp_decode_test(WSP.DateValue, [1, 0x80], new Date(0x80 * 1000));
   wsp_decode_test(WSP.DateValue, [31], null, "CodeError");
 
   run_next_test();
 });
 
+//// DateValue.encode ////
+
+add_test(function test_DateValue_encode() {
+  wsp_encode_test(WSP.DateValue, new Date(0x80 * 1000), [1, 0x80]);
+
+  run_next_test();
+});
+
 //
 // Test target: DeltaSecondsValue
 //
 // DeltaSecondsValue is only an alias of IntegerValue.
 
 //
 // Test target: QValue
 //
@@ -495,16 +632,28 @@ add_test(function test_QValue_decode() {
   wsp_decode_test(WSP.QValue, [100], 0.99);
   wsp_decode_test(WSP.QValue, [101], 0.001);
   wsp_decode_test(WSP.QValue, [0x88, 0x4B], 0.999);
   wsp_decode_test(WSP.QValue, [0x88, 0x4C], null, "CodeError");
 
   run_next_test();
 });
 
+//// QValue.encode ////
+
+add_test(function test_QValue_encode() {
+  wsp_encode_test(WSP.QValue, 0, [1]);
+  wsp_encode_test(WSP.QValue, 0.99, [100]);
+  wsp_encode_test(WSP.QValue, 0.001, [101]);
+  wsp_encode_test(WSP.QValue, 0.999, [0x88, 0x4B]);
+  wsp_encode_test(WSP.QValue, 1, null, "CodeError");
+
+  run_next_test();
+});
+
 //
 // Test target: VersionValue
 //
 
 //// VersionValue.decode ////
 
 add_test(function test_VersionValue_decode() {
   for (let major = 1; major < 8; major++) {
@@ -521,16 +670,32 @@ add_test(function test_VersionValue_deco
         wsp_decode_test(WSP.VersionValue, [major + 0x30, 0x2E, minor + 0x30, 0], version);
       }
     }
   }
 
   run_next_test();
 });
 
+//// VersionValue.encode ////
+
+add_test(function test_VersionValue_encode() {
+  for (let major = 1; major < 8; major++) {
+    let version = (major << 4) | 0x0F;
+    wsp_encode_test(WSP.VersionValue, version, [0x80 | version]);
+
+    for (let minor = 0; minor < 15; minor++) {
+      version = (major << 4) | minor;
+      wsp_encode_test(WSP.VersionValue, version, [0x80 | version]);
+    }
+  }
+
+  run_next_test();
+});
+
 //
 // Test target: UriValue
 //
 
 //// UriValue.decode ////
 
 add_test(function test_UriValue_decode() {
   wsp_decode_test(WSP.UriValue, [97], null, "RangeError");
@@ -553,16 +718,27 @@ add_test(function test_TypeValue_decode(
   wsp_decode_test(WSP.TypeValue, [0x33 | 0x80],
                   "application/vnd.wap.multipart.related");
   // Test for NotWellKnownEncodingError
   wsp_decode_test(WSP.TypeValue, [0x80], null, "NotWellKnownEncodingError");
 
   run_next_test();
 });
 
+//// TypeValue.encode ////
+
+add_test(function test_TypeValue_encode() {
+  wsp_encode_test(WSP.TypeValue, "no/such.type",
+                  [110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
+  wsp_encode_test(WSP.TypeValue, "application/vnd.wap.multipart.related",
+                  [0x33 | 0x80]);
+
+  run_next_test();
+});
+
 //
 // Test target: Parameter
 //
 
 //// Parameter.decodeTypedParameter ////
 
 add_test(function test_Parameter_decodeTypedParameter() {
   function func(data) {
@@ -576,20 +752,20 @@ add_test(function test_Parameter_decodeT
   // Test for NotWellKnownEncodingError
   wsp_decode_test_ex(func, [1, 0xFF], null, "NotWellKnownEncodingError");
   // Test for parameter specific decoder
   wsp_decode_test_ex(func, [1, 0, 100], {name: "q", value: 0.99});
   // Test for TextValue
   wsp_decode_test_ex(func, [1, 0x10, 48, 46, 57, 57, 0],
                      {name: "secure", value: "0.99"});
   // Test for TextString
-  wsp_decode_test_ex(func, [1, 0x19, 60, 115, 109, 105, 108, 62, 0],
+  wsp_decode_test_ex(func, [1, 0x0A, 60, 115, 109, 105, 108, 62, 0],
                      {name: "start", value: "<smil>"});
   // Test for skipValue
-  wsp_decode_test_ex(func, [1, 0x19, 128], null);
+  wsp_decode_test_ex(func, [1, 0x0A, 128], null);
 
   run_next_test();
 });
 
 //// Parameter.decodeUntypedParameter ////
 
 add_test(function test_Parameter_decodeUntypedParameter() {
   function func (data) {
@@ -604,34 +780,87 @@ add_test(function test_Parameter_decodeU
   wsp_decode_test_ex(func, [65, 0, 66, 0], {name: "a", value: "B"});
 
   run_next_test();
 });
 
 //// Parameter.decode ////
 
 add_test(function test_Parameter_decode() {
-  wsp_decode_test(WSP.Parameter, [1, 0x19, 60, 115, 109, 105, 108, 62, 0],
+  wsp_decode_test(WSP.Parameter, [1, 0x0A, 60, 115, 109, 105, 108, 62, 0],
                   {name: "start", value: "<smil>"});
   wsp_decode_test(WSP.Parameter, [65, 0, 66, 0], {name: "a", value: "B"});
 
   run_next_test();
 });
 
 //// Parameter.decodeMultiple ////
 
 add_test(function test_Parameter_decodeMultiple() {
   wsp_decode_test_ex(function (data) {
       return WSP.Parameter.decodeMultiple(data, 13);
-    }, [1, 0x19, 60, 115, 109, 105, 108, 62, 0, 65, 0, 66, 0], {start: "<smil>", a: "B"}
+    }, [1, 0x0A, 60, 115, 109, 105, 108, 62, 0, 65, 0, 66, 0], {start: "<smil>", a: "B"}
   );
 
   run_next_test();
 });
 
+//// Parameter.encodeTypedParameter ////
+
+add_test(function test_Parameter_encodeTypedParameter() {
+  function func(data, input) {
+    WSP.Parameter.encodeTypedParameter(data, input);
+    return data.array;
+  }
+
+  // Test for NotWellKnownEncodingError
+  wsp_encode_test_ex(func, {name: "xxx", value: 0}, null, "NotWellKnownEncodingError");
+  wsp_encode_test_ex(func, {name: "q", value: 0}, [0x80, 1]);
+  wsp_encode_test_ex(func, {name: "name", value: "A"}, [0x85, 65, 0]);
+
+  run_next_test();
+});
+
+//// Parameter.encodeUntypedParameter ////
+
+add_test(function test_Parameter_encodeUntypedParameter() {
+  function func(data, input) {
+    WSP.Parameter.encodeUntypedParameter(data, input);
+    return data.array;
+  }
+
+  wsp_encode_test_ex(func, {name: "q", value: 0}, [113, 0, 0x80]);
+  wsp_encode_test_ex(func, {name: "name", value: "A"}, [110, 97, 109, 101, 0, 65, 0]);
+
+  run_next_test();
+});
+
+//// Parameter.encodeMultiple ////
+
+add_test(function test_Parameter_encodeMultiple() {
+  function func(data, input) {
+    WSP.Parameter.encodeMultiple(data, input);
+    return data.array;
+  }
+
+  wsp_encode_test_ex(func, {q: 0, n: "A"}, [0x80, 1, 110, 0, 65, 0]);
+
+  run_next_test();
+});
+
+//// Parameter.encode ////
+
+add_test(function test_Parameter_encode() {
+
+  wsp_encode_test(WSP.Parameter, {name: "q", value: 0}, [0x80, 1]);
+  wsp_encode_test(WSP.Parameter, {name: "n", value: "A"}, [110, 0, 65, 0]);
+
+  run_next_test();
+});
+
 //
 // Test target: Header
 //
 
 //// Header.decode ////
 
 add_test(function test_Header_decode() {
   wsp_decode_test(WSP.Header, [0x34 | 0x80, 0x80], {name: "push-flag", value: 0});
@@ -717,16 +946,25 @@ add_test(function test_FieldName_decode(
   let (entry = WSP.WSP_HEADER_FIELDS["content-length"]) {
     wsp_decode_test(WSP.FieldName, [entry.number | 0x80], entry.name);
   }
   wsp_decode_test(WSP.FieldName, [0xFF], null, "NotWellKnownEncodingError");
 
   run_next_test();
 });
 
+//// FieldName.encode ////
+
+add_test(function test_FieldName_encode() {
+  wsp_encode_test(WSP.FieldName, "", [0]);
+  wsp_encode_test(WSP.FieldName, "date", [0x92]);
+
+  run_next_test();
+});
+
 //
 // Test target: AcceptCharsetValue
 //
 
 //// AcceptCharsetValue.decode ////
 
 add_test(function test_AcceptCharsetValue_decode() {
   wsp_decode_test(WSP.AcceptCharsetValue, [0xFF], null, "CodeError");
@@ -743,16 +981,34 @@ add_test(function test_AcceptCharsetValu
     wsp_decode_test(WSP.AcceptCharsetValue, [2, 1, entry.number], {charset: entry.name});
     wsp_decode_test(WSP.AcceptCharsetValue, [1, entry.number | 0x80], {charset: entry.name});
   }
   wsp_decode_test(WSP.AcceptCharsetValue, [3, 65, 0, 100], {charset: "A", q: 0.99});
 
   run_next_test();
 });
 
+//// AcceptCharsetValue.encodeAnyCharset ////
+
+add_test(function test_AcceptCharsetValue_encodeAnyCharset() {
+  function func(data, input) {
+    WSP.AcceptCharsetValue.encodeAnyCharset(data, input);
+    return data.array;
+  }
+
+  wsp_encode_test_ex(func, null, [0x80]);
+  wsp_encode_test_ex(func, undefined, [0x80]);
+  wsp_encode_test_ex(func, {}, [0x80]);
+  wsp_encode_test_ex(func, {charset: null}, [0x80]);
+  wsp_encode_test_ex(func, {charset: "*"}, [0x80]);
+  wsp_encode_test_ex(func, {charset: "en"}, null, "CodeError");
+
+  run_next_test();
+});
+
 //
 // Test target: WellKnownCharset
 //
 
 //// WellKnownCharset.decode ////
 
 add_test(function test_WellKnownCharset_decode() {
   wsp_decode_test(WSP.WellKnownCharset, [0xFF], null, "NotWellKnownEncodingError");
@@ -761,16 +1017,26 @@ add_test(function test_WellKnownCharset_
   // Test for number-typed return value from IntegerValue
   wsp_decode_test(WSP.WellKnownCharset, [1, 3], {charset: "ansi_x3.4-1968"});
   // Test for array-typed return value from IntegerValue
   wsp_decode_test(WSP.WellKnownCharset, [7, 0, 0, 0, 0, 0, 0, 0, 3], null, "CodeError");
 
   run_next_test();
 });
 
+//// WellKnownCharset.encode ////
+
+add_test(function test_WellKnownCharset_encode() {
+  // Test for Any-charset
+  wsp_encode_test(WSP.WellKnownCharset, {charset: "*"}, [0x80]);
+  wsp_encode_test(WSP.WellKnownCharset, {charset: "UTF-8"}, [128 + 106]);
+
+  run_next_test();
+});
+
 //
 // Test target: ContentTypeValue
 //
 
 //// ContentTypeValue.decodeConstrainedMedia ////
 
 add_test(function test_ContentTypeValue_decodeConstrainedMedia() {
   function func(data) {
@@ -809,50 +1075,114 @@ add_test(function test_ContentTypeValue_
 add_test(function test_ContentTypeValue_decodeMediaType() {
   wsp_decode_test_ex(function (data) {
       return WSP.ContentTypeValue.decodeMediaType(data, 1);
     }, [0x3E | 0x80],
     {media: "application/vnd.wap.mms-message", params: null}
   );
   wsp_decode_test_ex(function (data) {
       return WSP.ContentTypeValue.decodeMediaType(data, 14);
-    }, [0x3E | 0x80, 1, 0x19, 60, 115, 109, 105, 108, 62, 0, 65, 0, 66, 0],
+    }, [0x3E | 0x80, 1, 0x0A, 60, 115, 109, 105, 108, 62, 0, 65, 0, 66, 0],
     {media: "application/vnd.wap.mms-message", params: {start: "<smil>", a: "B"}}
   );
 
   run_next_test();
 });
 
 //// ContentTypeValue.decodeContentGeneralForm ////
 
 add_test(function test_ContentTypeValue_decodeContentGeneralForm() {
   wsp_decode_test_ex(function (data) {
       return WSP.ContentTypeValue.decodeContentGeneralForm(data);
-    }, [14, 0x3E | 0x80, 1, 0x19, 60, 115, 109, 105, 108, 62, 0, 65, 0, 66, 0],
+    }, [14, 0x3E | 0x80, 1, 0x0A, 60, 115, 109, 105, 108, 62, 0, 65, 0, 66, 0],
     {media: "application/vnd.wap.mms-message", params: {start: "<smil>", a: "B"}}
   );
 
   run_next_test();
 });
 
 //// ContentTypeValue.decode ////
 
 add_test(function test_ContentTypeValue_decode() {
   wsp_decode_test(WSP.ContentTypeValue,
-    [14, 0x3E | 0x80, 1, 0x19, 60, 115, 109, 105, 108, 62, 0, 65, 0, 66, 0],
+    [14, 0x3E | 0x80, 1, 0x0A, 60, 115, 109, 105, 108, 62, 0, 65, 0, 66, 0],
     {media: "application/vnd.wap.mms-message", params: {start: "<smil>", a: "B"}}
   );
 
   wsp_decode_test(WSP.ContentTypeValue, [0x33 | 0x80],
     {media: "application/vnd.wap.multipart.related", params: null}
   );
 
   run_next_test();
 });
 
+//// ContentTypeValue.encodeConstrainedMedia ////
+
+add_test(function test_ContentTypeValue_encodeConstrainedMedia() {
+  function func(data, input) {
+    WSP.ContentTypeValue.encodeConstrainedMedia(data, input);
+    return data.array;
+  }
+
+  // Test media type with additional parameters.
+  wsp_encode_test_ex(func, {media: "a", params: [{a: "b"}]}, null, "CodeError");
+  wsp_encode_test_ex(func, {media: "no/such.type"},
+                     [110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
+  wsp_encode_test_ex(func, {media: "application/vnd.wap.multipart.related"},
+                     [0x33 | 0x80]);
+
+  run_next_test();
+});
+
+//// ContentTypeValue.encodeMediaType ////
+
+add_test(function test_ContentTypeValue_encodeMediaType() {
+  function func(data, input) {
+    WSP.ContentTypeValue.encodeMediaType(data, input);
+    return data.array;
+  }
+
+  wsp_encode_test_ex(func, {media: "no/such.type"},
+                     [110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
+  wsp_encode_test_ex(func, {media: "application/vnd.wap.multipart.related"},
+                     [0x33 | 0x80]);
+  wsp_encode_test_ex(func, {media: "a", params: {b: "c", q: 0}},
+                     [97, 0, 98, 0, 99, 0, 128, 1]);
+
+  run_next_test();
+});
+
+//// ContentTypeValue.encodeContentGeneralForm ////
+
+add_test(function test_ContentTypeValue_encodeContentGeneralForm() {
+  function func(data, input) {
+    WSP.ContentTypeValue.encodeContentGeneralForm(data, input);
+    return data.array;
+  }
+
+  wsp_encode_test_ex(func, {media: "a", params: {b: "c", q: 0}},
+                     [8, 97, 0, 98, 0, 99, 0, 128, 1]);
+
+  run_next_test();
+});
+
+//// ContentTypeValue.encode ////
+
+add_test(function test_ContentTypeValue_encode() {
+  wsp_encode_test(WSP.ContentTypeValue, {media: "no/such.type"},
+                  [110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
+  wsp_encode_test(WSP.ContentTypeValue,
+                  {media: "application/vnd.wap.multipart.related"},
+                  [0x33 | 0x80]);
+  wsp_encode_test(WSP.ContentTypeValue, {media: "a", params: {b: "c", q: 0}},
+                  [8, 97, 0, 98, 0, 99, 0, 128, 1]);
+
+  run_next_test();
+});
+
 //
 // Test target: ApplicationIdValue
 //
 
 //// ApplicationIdValue.decode ////
 
 add_test(function test_ApplicationIdValue_decode() {
   wsp_decode_test(WSP.ApplicationIdValue, [0], "");
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -88,16 +88,17 @@ using mozilla::PluginPRLibrary;
 using mozilla::plugins::PluginModuleParent;
 
 #ifdef MOZ_X11
 #include "mozilla/X11Util.h"
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
+#include "nsWindowsHelpers.h"
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 #include <android/log.h>
 #include "android_npapi.h"
 #include "ANPBase.h"
 #include "AndroidBridge.h"
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
@@ -276,30 +277,16 @@ static bool GMA9XXGraphics()
       }
     }
     ::CGLDestroyRendererInfo(renderer);
   }
   return hasIntelGMA9XX;
 }
 #endif
 
-#ifdef XP_WIN
-static bool
-IsVistaOrLater()
-{
-  OSVERSIONINFO info;
-
-  ZeroMemory(&info, sizeof(OSVERSIONINFO));
-  info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-  GetVersionEx(&info);
-
-  return info.dwMajorVersion >= 6;
-}
-#endif
-
 bool
 nsNPAPIPlugin::RunPluginOOP(const nsPluginTag *aPluginTag)
 {
   if (PR_GetEnv("MOZ_DISABLE_OOP_PLUGINS")) {
     return false;
   }
 
   if (!aPluginTag) {
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -213,21 +213,25 @@ nsNPAPIPluginInstance::~nsNPAPIPluginIns
 
 void
 nsNPAPIPluginInstance::Destroy()
 {
   Stop();
   mPlugin = nsnull;
 
 #if MOZ_WIDGET_ANDROID
+  if (mContentSurface)
+    mContentSurface->SetFrameAvailableCallback(nsnull);
+  
   mContentTexture = nsnull;
   mContentSurface = nsnull;
 
   std::map<void*, VideoInfo*>::iterator it;
   for (it = mVideos.begin(); it != mVideos.end(); it++) {
+    it->second->mSurfaceTexture->SetFrameAvailableCallback(nsnull);
     delete it->second;
   }
   mVideos.clear();
   SetWakeLock(false);
 #endif
 }
 
 TimeStamp
@@ -983,21 +987,27 @@ nsSurfaceTexture* nsNPAPIPluginInstance:
   GLuint texture = TexturePoolOGL::AcquireTexture();
   if (!texture)
     return nsnull;
 
   nsSurfaceTexture* surface = nsSurfaceTexture::Create(texture);
   if (!surface)
     return nsnull;
 
-  nsCOMPtr<nsIRunnable> frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::RedrawPlugin);
+  nsCOMPtr<nsIRunnable> frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable);
   surface->SetFrameAvailableCallback(frameCallback);
   return surface;
 }
 
+void nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable()
+{
+  if (mRunning == RUNNING && mOwner)
+    RedrawPlugin();
+}
+
 void* nsNPAPIPluginInstance::AcquireContentWindow()
 {
   if (!mContentSurface) {
     mContentSurface = CreateSurfaceTexture();
 
     if (!mContentSurface)
       return nsnull;
   }
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -281,16 +281,17 @@ protected:
 
 #ifdef MOZ_WIDGET_ANDROID
   PRUint32 mANPDrawingModel;
 
   friend class PluginEventRunnable;
 
   nsTArray<nsCOMPtr<PluginEventRunnable>> mPostedEvents;
   void PopPostedEvent(PluginEventRunnable* r);
+  void OnSurfaceTextureFrameAvailable();
 
   PRUint32 mFullScreenOrientation;
   bool mWakeLocked;
   bool mFullScreen;
   bool mInverted;
 
   nsRefPtr<SharedPluginTexture> mContentTexture;
   nsRefPtr<nsSurfaceTexture> mContentSurface;
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -1917,17 +1917,17 @@ PluginInstanceParent::SharedSurfaceRelea
 {
     mSharedSurfaceDib.Close();
 }
 
 bool
 PluginInstanceParent::SharedSurfaceSetWindow(const NPWindow* aWindow,
                                              NPRemoteWindow& aRemoteWindow)
 {
-    aRemoteWindow.window = nsnull;
+    aRemoteWindow.window = 0;
     aRemoteWindow.x      = aWindow->x;
     aRemoteWindow.y      = aWindow->y;
     aRemoteWindow.width  = aWindow->width;
     aRemoteWindow.height = aWindow->height;
     aRemoteWindow.type   = aWindow->type;
 
     nsIntRect newPort(aWindow->x, aWindow->y, aWindow->width, aWindow->height);
 
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -94,18 +94,16 @@ NS_IMPL_ISUPPORTS1(AutoMounterSetting, n
 NS_IMETHODIMP
 AutoMounterSetting::Observe(nsISupports *aSubject,
                             const char *aTopic,
                             const PRUnichar *aData)
 {
   if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) {
     return NS_OK;
   }
-  LOG("%s: detected %s data = '%s'", __FUNCTION__, aTopic,
-      NS_LossyConvertUTF16toASCII(aData).get());
 
   // Note that this function gets called for any and all settings changes,
   // so we need to carefully check if we have the one we're interested in.
   //
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"ums.autoMount","value":true}
 
   nsCOMPtr<nsIThreadJSContextStack> stack =
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -455,16 +455,17 @@ const MSISDN_MAX_NUMBER_SIZE_BYTES = 10;
 const READ_RECORD_ABSOLUTE_MODE = 4;
 
 // GET_RESPONSE mandatory response size for EF, see TS 51.011 clause 9, 
 // 'Response data in case of an EF.'
 const GET_RESPONSE_EF_SIZE_BYTES = 15;
 
 // EF path
 const EF_PATH_MF_SIM = "3f00";
+const EF_PATH_DF_PHONEBOOK = "5f3a";
 const EF_PATH_DF_TELECOM = "7f10";
 const EF_PATH_DF_GSM = "7f20";
 
 // Status code of sw1 for ICC I/O,
 // see GSM11.11 and TS 51.011 clause 9.4, and ISO 7816-4
 const ICC_STATUS_NORMAL_ENDING = 0x90;
 const ICC_STATUS_NORMAL_ENDING_WITH_EXTRA = 0x91;
 const ICC_STATUS_WITH_SIM_DATA = 0x9e;
--- a/dom/telephony/test/marionette/pdu_builder.js
+++ b/dom/telephony/test/marionette/pdu_builder.js
@@ -1,12 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
+let Cu = SpecialPowers.wrap(Components).utils;
+let RIL = {};
+
+Cu.import("resource://gre/modules/ril_consts.js", RIL);
+
 // Only bring in what we need from ril_worker/RadioInterfaceLayer here. Reusing
 // that code turns out to be a nightmare, so there is some code duplication.
 let PDUBuilder = {
   toHexString: function toHexString(n, length) {
     let str = n.toString(16);
     if (str.length < length) {
       for (let i = 0; i < length - str.length; i++) {
         str = "0" + str;
@@ -41,42 +46,42 @@ let PDUBuilder = {
     }
   },
 
   writeStringAsSeptets: function writeStringAsSeptets(message,
                                                       paddingBits,
                                                       langIndex,
                                                       langShiftIndex)
   {
-    const langTable = PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
-    const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
+    const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
+    const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
 
     let dataBits = paddingBits;
     let data = 0;
     for (let i = 0; i < message.length; i++) {
       let septet = langTable.indexOf(message[i]);
-      if (septet == PDU_NL_EXTENDED_ESCAPE) {
+      if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
         continue;
       }
 
       if (septet >= 0) {
         data |= septet << dataBits;
         dataBits += 7;
       } else {
         septet = langShiftTable.indexOf(message[i]);
         if (septet == -1) {
           throw new Error(message[i] + " not in 7 bit alphabet "
                           + langIndex + ":" + langShiftIndex + "!");
         }
 
-        if (septet == PDU_NL_RESERVED_CONTROL) {
+        if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
           continue;
         }
 
-        data |= PDU_NL_EXTENDED_ESCAPE << dataBits;
+        data |= RIL.PDU_NL_EXTENDED_ESCAPE << dataBits;
         dataBits += 7;
         data |= septet << dataBits;
         dataBits += 7;
       }
 
       for (; dataBits >= 8; dataBits -= 8) {
         this.writeHexOctet(data & 0xFF);
         data >>>= 8;
@@ -84,19 +89,19 @@ let PDUBuilder = {
     }
 
     if (dataBits != 0) {
       this.writeHexOctet(data & 0xFF);
     }
   },
 
   buildAddress: function buildAddress(address) {
-    let addressFormat = PDU_TOA_ISDN; // 81
+    let addressFormat = RIL.PDU_TOA_ISDN; // 81
     if (address[0] == '+') {
-      addressFormat = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91
+      addressFormat = RIL.PDU_TOA_INTERNATIONAL | RIL.PDU_TOA_ISDN; // 91
       address = address.substring(1);
     }
 
     this.buf = "";
     this.writeHexOctet(address.length);
     this.writeHexOctet(addressFormat);
     this.writeSwappedNibbleBCD(address);
 
@@ -137,13 +142,13 @@ let PDUBuilder = {
           for each (let octet in header.octets) {
             this.writeHexOctet(octet);
           }
         }
       }
     }
 
     this.writeStringAsSeptets(options.body, paddingBits,
-                              PDU_NL_IDENTIFIER_DEFAULT,
-                              PDU_NL_IDENTIFIER_DEFAULT);
+                              RIL.PDU_NL_IDENTIFIER_DEFAULT,
+                              RIL.PDU_NL_IDENTIFIER_DEFAULT);
     return this.buf;
   }
 };
--- a/dom/telephony/test/marionette/test_voicemail_statuschanged.js
+++ b/dom/telephony/test/marionette/test_voicemail_statuschanged.js
@@ -9,17 +9,17 @@ let voicemail = window.navigator.mozVoic
 ok(voicemail instanceof MozVoicemail);
 is(voicemail.status, null);
 
 function sendIndicatorPDU(pdu, listener, nextTest) {
   let smsCommand = "sms pdu " + pdu;
   let commandCompleted = false;
   let sawEvent = false;
 
- voicemail.addEventListener("statuschanged", function statusChanged(event) {
+  voicemail.addEventListener("statuschanged", function statusChanged(event) {
     voicemail.removeEventListener("statuschanged", statusChanged);
 
     try {
       listener(event);
     } catch (e) {
       ok(false, String(e));
     }
 
@@ -146,20 +146,20 @@ function testLevel2DiscardInactive() {
 // Tests for Level 3 MWI with a message count in the User Data Header
 const MWI_LEVEL3_SENDER = "+15125551236";
 const MWI_LEVEL3_PDU_ADDRESS = PDUBuilder.buildAddress(MWI_LEVEL3_SENDER);
 
 const MWI_LEVEL3_ACTIVE_UDH_MSG_COUNT = 3;
 const MWI_LEVEL3_ACTIVE_BODY = "3 new voicemails";
 const MWI_LEVEL3_ACTIVE_UD = PDUBuilder.buildUserData({
   headers: [{
-    id: PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
+    id: RIL.PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
     length: 2,
     octets: [
-      PDU_MWI_STORE_TYPE_DISCARD,
+      RIL.PDU_MWI_STORE_TYPE_DISCARD,
       MWI_LEVEL3_ACTIVE_UDH_MSG_COUNT
     ]
   }],
   body: MWI_LEVEL3_ACTIVE_BODY
 });
 
 const MWI_LEVEL3_DISCARD_ACTIVE_PDU =
   MWI_PDU_UDH_PREFIX +
@@ -184,20 +184,20 @@ function testLevel3DiscardActive() {
   sendIndicatorPDU(MWI_LEVEL3_DISCARD_ACTIVE_PDU,
                    onLevel3Active,
                    testLevel3DiscardInactive);
 }
 
 const MWI_LEVEL3_INACTIVE_BODY = "No unread voicemails";
 const MWI_LEVEL3_INACTIVE_UD = PDUBuilder.buildUserData({
   headers: [{
-    id: PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
+    id: RIL.PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
     length: 2,
     octets: [
-      PDU_MWI_STORE_TYPE_DISCARD,
+      RIL.PDU_MWI_STORE_TYPE_DISCARD,
       0 // messageCount
     ]
   }],
   body: MWI_LEVEL3_INACTIVE_BODY
 });
 
 const MWI_LEVEL3_DISCARD_INACTIVE_PDU =
   MWI_PDU_UDH_PREFIX +
--- a/dom/telephony/test/marionette/test_voicemail_statuschanged.py
+++ b/dom/telephony/test/marionette/test_voicemail_statuschanged.py
@@ -1,20 +1,14 @@
 from marionette_test import MarionetteTestCase
 import os
 
 class TestVoicemailStatusChanged(MarionetteTestCase):
 
     def testStatusChanged(self):
         this_dir = os.path.abspath(os.path.dirname(__file__))
-        system_gonk_dir = os.path.abspath(os.path.join(this_dir,
-            os.path.pardir, os.path.pardir, os.path.pardir, "system", "gonk"))
-
-        ril_consts_path = os.path.join(system_gonk_dir, "ril_consts.js")
-        self.marionette.import_script(ril_consts_path)
-
         pdu_builder_path = os.path.join(this_dir, "pdu_builder.js")
         self.marionette.import_script(pdu_builder_path)
 
         test_path = os.path.join(this_dir, "test_voicemail_statuschanged.js")
         test = open(test_path, "r").read()
         self.marionette.set_script_timeout(30000)
         self.marionette.execute_async_script(test)
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -1599,20 +1599,24 @@ XMLHttpRequest::MaybeDispatchPrematureAb
 
 void
 XMLHttpRequest::DispatchPrematureAbortEvent(JSObject* aTarget,
                                             uint8_t aEventType,
                                             bool aUploadTarget,
                                             ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
-  MOZ_ASSERT(mProxy);
   MOZ_ASSERT(aTarget);
   MOZ_ASSERT(aEventType <= STRING_COUNT);
 
+  if (!mProxy) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
   JSContext* cx = GetJSContext();
 
   JSString* type = JS_NewStringCopyZ(cx, sEventStrings[aEventType]);
   if (!type) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
--- a/dom/workers/test/test_xhrAbort.html
+++ b/dom/workers/test/test_xhrAbort.html
@@ -30,21 +30,15 @@ Tests of DOM Worker Threads XHR(Bug 4504
     worker.onmessage = function(event) {
       is (data.toString(), event.data.toString(), "Got different results!");
       SimpleTest.finish();
     };
 
     worker.postMessage("start");
   }
 
-  SimpleTest.waitForExplicitFinish();
+  runTest();
 
-  const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
-  if (isWinXP){
-    todo(false, "Test disabled on WinXP due to bug 718260 crashes");
-    SimpleTest.finish();
-  } else {
-    runTest();
-  }
+  SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 </body>
 </html>
--- a/editor/composer/src/Makefile.in
+++ b/editor/composer/src/Makefile.in
@@ -27,17 +27,18 @@ CPPSRCS  = \
            nsComposerRegistration.cpp     \
            nsEditingSession.cpp	          \
            nsComposerCommandsUpdater.cpp  \
            nsEditorSpellCheck.cpp         \
            $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
-INCLUDES        += -I../../libeditor/base/src
+INCLUDES        += \
+	$(NULL)
 
 _FILES = \
 	$(srcdir)/res/EditorOverride.css \
 	$(srcdir)/res/grabber.gif \
 	$(srcdir)/res/table-add-column-after-active.gif \
 	$(srcdir)/res/table-add-column-after-hover.gif \
 	$(srcdir)/res/table-add-column-after.gif \
 	$(srcdir)/res/table-add-column-before-active.gif \
--- a/extensions/auth/nsAuthGSSAPI.cpp
+++ b/extensions/auth/nsAuthGSSAPI.cpp
@@ -562,8 +562,14 @@ nsAuthGSSAPI::Wrap(const void *inToken,
 
     /* it is not possible for output_token.length to be zero */
     *outToken = nsMemory::Clone(output_token.value, output_token.length);
     gss_release_buffer_ptr(&minor_status, &output_token);
 
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsAuthGSSAPI::GetModuleProperties(PRUint32 *flags)
+{
+    *flags = 0;
+    return NS_OK;
+}
--- a/extensions/auth/nsAuthSASL.cpp
+++ b/extensions/auth/nsAuthSASL.cpp
@@ -144,8 +144,15 @@ NS_IMETHODIMP
 nsAuthSASL::Wrap(const void *inToken,
                  PRUint32    inTokenLen,
                  bool        confidential,
                  void      **outToken,
                  PRUint32   *outTokenLen)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
+
+NS_IMETHODIMP
+nsAuthSASL::GetModuleProperties(PRUint32 *flags)
+{
+    *flags = 0;
+    return NS_OK;
+}
--- a/extensions/auth/nsAuthSSPI.cpp
+++ b/extensions/auth/nsAuthSSPI.cpp
@@ -86,60 +86,16 @@ InitSSPI()
         return NS_ERROR_UNEXPECTED;
     }
 
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 
-static nsresult
-MakeSN(const char *principal, nsCString &result)
-{
-    nsresult rv;
-
-    nsCAutoString buf(principal);
-
-    // The service name looks like "protocol@hostname", we need to map
-    // this to a value that SSPI expects.  To be consistent with IE, we
-    // need to map '@' to '/' and canonicalize the hostname.
-    PRInt32 index = buf.FindChar('@');
-    if (index == kNotFound)
-        return NS_ERROR_UNEXPECTED;
-    
-    nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
-    if (NS_FAILED(rv))
-        return rv;
-
-    // This could be expensive if our DNS cache cannot satisfy the request.
-    // However, we should have at least hit the OS resolver once prior to
-    // reaching this code, so provided the OS resolver has this information
-    // cached, we should not have to worry about blocking on this function call
-    // for very long.  NOTE: because we ask for the canonical hostname, we
-    // might end up requiring extra network activity in cases where the OS
-    // resolver might not have enough information to satisfy the request from
-    // its cache.  This is not an issue in versions of Windows up to WinXP.
-    nsCOMPtr<nsIDNSRecord> record;
-    rv = dns->Resolve(Substring(buf, index + 1),
-                      nsIDNSService::RESOLVE_CANONICAL_NAME,
-                      getter_AddRefs(record));
-    if (NS_FAILED(rv))
-        return rv;
-
-    nsCAutoString cname;
-    rv = record->GetCanonicalName(cname);
-    if (NS_SUCCEEDED(rv)) {
-        result = StringHead(buf, index) + NS_LITERAL_CSTRING("/") + cname;
-        LOG(("Using SPN of [%s]\n", result.get()));
-    }
-    return rv;
-}
-
-//-----------------------------------------------------------------------------
-
 nsAuthSSPI::nsAuthSSPI(pType package)
     : mServiceFlags(REQ_DEFAULT)
     , mMaxTokenLen(0)
     , mPackage(package)
     , mCertDERData(nsnull)
     , mCertDERLength(0)
 {
     memset(&mCred, 0, sizeof(mCred));
@@ -203,33 +159,23 @@ nsAuthSSPI::Init(const char *serviceName
         rv = InitSSPI();
         if (NS_FAILED(rv))
             return rv;
     }
     SEC_WCHAR *package;
 
     package = (SEC_WCHAR *) pTypeName[(int)mPackage];
 
-    if (mPackage == PACKAGE_TYPE_NTLM) {
-        // (bug 535193) For NTLM, just use the uri host, do not do canonical host lookups.
-        // The incoming serviceName is in the format: "protocol@hostname", SSPI expects
-        // "<service class>/<hostname>", so swap the '@' for a '/'.
-        mServiceName.Assign(serviceName);
-        PRInt32 index = mServiceName.FindChar('@');
-        if (index == kNotFound)
-            return NS_ERROR_UNEXPECTED;
-        mServiceName.Replace(index, 1, '/');
-    }
-    else {
-        // Kerberos requires the canonical host, MakeSN takes care of this through a
-        // DNS lookup.
-        rv = MakeSN(serviceName, mServiceName);
-        if (NS_FAILED(rv))
-            return rv;
-    }
+    // The incoming serviceName is in the format: "protocol@hostname", SSPI expects
+    // "<service class>/<hostname>", so swap the '@' for a '/'.
+    mServiceName.Assign(serviceName);
+    PRInt32 index = mServiceName.FindChar('@');
+    if (index == kNotFound)
+        return NS_ERROR_UNEXPECTED;
+    mServiceName.Replace(index, 1, '/');
 
     mServiceFlags = serviceFlags;
 
     SECURITY_STATUS rc;
 
     PSecPkgInfoW pinfo;
     rc = (sspi->QuerySecurityPackageInfoW)(package, &pinfo);
     if (rc != SEC_E_OK) {
@@ -648,8 +594,21 @@ nsAuthSSPI::Wrap(const void *inToken,
 
         memcpy(p,bufs.ib[2].pvBuffer, bufs.ib[2].cbBuffer);
         
         return NS_OK;
     }
 
     return NS_ERROR_FAILURE;
 }
+
+NS_IMETHODIMP
+nsAuthSSPI::GetModuleProperties(PRUint32 *flags)
+{
+    *flags = 0;
+
+    // (bug 535193) For NTLM, just use the uri host, do not do canonical host
+    // lookups. But Kerberos requires the canonical host.
+    if (mPackage != PACKAGE_TYPE_NTLM)
+        *flags |= CANONICAL_NAME_REQUIRED;
+
+    return NS_OK;
+}
--- a/extensions/auth/nsAuthSambaNTLM.cpp
+++ b/extensions/auth/nsAuthSambaNTLM.cpp
@@ -277,8 +277,15 @@ NS_IMETHODIMP
 nsAuthSambaNTLM::Wrap(const void *inToken,
                       PRUint32    inTokenLen,
                       bool        confidential,
                       void      **outToken,
                       PRUint32   *outTokenLen)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
+
+NS_IMETHODIMP
+nsAuthSambaNTLM::GetModuleProperties(PRUint32 *flags)
+{
+    *flags = 0;
+    return NS_OK;
+}
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -201,20 +201,24 @@ void SetPaintPattern(SkPaint& aPaint, co
         points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y));
         points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y));
 
         SkShader* shader = SkGradientShader::CreateLinear(points, 
                                                           &stops->mColors.front(), 
                                                           &stops->mPositions.front(), 
                                                           stops->mCount, 
                                                           mode);
-        SkMatrix mat;
-        GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
-        shader->setLocalMatrix(mat);
-        SkSafeUnref(aPaint.setShader(shader));
+
+        if (shader) {
+            SkMatrix mat;
+            GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
+            shader->setLocalMatrix(mat);
+            SkSafeUnref(aPaint.setShader(shader));
+        }
+
       } else {
         aPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
       }
       break;
     }
     case PATTERN_RADIAL_GRADIENT: {
       const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern);
       GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
@@ -228,20 +232,23 @@ void SetPaintPattern(SkPaint& aPaint, co
         SkShader* shader = SkGradientShader::CreateTwoPointRadial(points[0], 
                                                                   SkFloatToScalar(pat.mRadius1),
                                                                   points[1], 
                                                                   SkFloatToScalar(pat.mRadius2),
                                                                   &stops->mColors.front(), 
                                                                   &stops->mPositions.front(), 
                                                                   stops->mCount, 
                                                                   mode);
-        SkMatrix mat;
-        GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
-        shader->setLocalMatrix(mat);
-        SkSafeUnref(aPaint.setShader(shader));
+        if (shader) {
+            SkMatrix mat;
+            GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
+            shader->setLocalMatrix(mat);
+            SkSafeUnref(aPaint.setShader(shader));
+        }
+
       } else {
         aPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
       }
       break;
     }
     case PATTERN_SURFACE: {
       const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
       const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(pat.mSurface.get())->GetBitmap();
--- a/gfx/angle/AUTHORS
+++ b/gfx/angle/AUTHORS
@@ -8,8 +8,10 @@
 # The email address is not required for organizations.
 
 TransGaming Inc.
 
 Google Inc.
 
 3DLabs Inc. Ltd.
 
+Cloud Party, Inc.
+
--- a/gfx/angle/CONTRIBUTORS
+++ b/gfx/angle/CONTRIBUTORS
@@ -12,16 +12,17 @@ TransGaming Inc.
  Andrew Lewycky
  Gavriel State
  Shannon Woods
 
 Google Inc.
  Brent Austin
  Michael Bai
  John Bauman
+ Steve Block
  Henry Bridge
  Nat Duca
  Vangelis Kokkevis
  Zhenyao Mo
  Daniel Nicoara
  Alastair Patrick
  Alok Priyadarshi
  Kenneth Russell
@@ -34,18 +35,26 @@ Mozilla Corp.
  Mike Hommey
  Benoit Jacob
  Makoto Kato
  Vladimir Vukicevic
 
 Apple Inc.
  David Kilzer
 
+Adobe Systems Inc.
+ Alexandru Chiculita
+ Max Vujovic
+
+Cloud Party, Inc.
+ Conor Dickinson
+
 Aitor Moreno <aitormoreno at gmail.com>
 Jim Hauxwell <james at dattrax.co.uk>
 ddefrostt
 timeless
 Yore Apex
 Mark Callow
 Yuriy O'Donnell
 Sam Hocevar
 Pierre Leveille
+Jin Yang
 
--- a/gfx/angle/DEPS
+++ b/gfx/angle/DEPS
@@ -1,14 +1,17 @@
 deps = {
   "trunk/third_party/gyp":
       "http://gyp.googlecode.com/svn/trunk@1080",
 
   "trunk/third_party/googletest":
       "http://googletest.googlecode.com/svn/trunk@573", #release 1.6.0
+
+  "trunk/third_party/googlemock":
+      "http://googlemock.googlecode.com/svn/trunk@387", #release 1.6.0
 }
 
 hooks = [
   {
     # A change to a .gyp, .gypi, or to GYP itself should run the generator.
     "pattern": ".",
     "action": ["python", "trunk/build/gyp_angle"],
   },
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -24,48 +24,63 @@ EXPORTS_angle = \
 	$(NULL)
 
 LOCAL_INCLUDES += -I$(srcdir)/include -I$(srcdir)/src
 
 VPATH += $(srcdir)/src
 VPATH += $(srcdir)/src/compiler
 VPATH += $(srcdir)/src/compiler/preprocessor
 VPATH += $(srcdir)/src/compiler/preprocessor/new
+VPATH += $(srcdir)/src/compiler/timing
+VPATH += $(srcdir)/src/compiler/depgraph
 
 CPPSRCS = \
-	Compiler.cpp \
+        Diagnostics.cpp \
+        PreprocessorDiagnostics.cpp \
+        DirectiveHandler.cpp \
+        PreprocessorDirectiveHandler.cpp \
+        DirectiveParser.cpp \
+        ExpressionParser.cpp \
+        Macro.cpp \
+        MacroExpander.cpp \
+        Tokenizer.cpp \
+        InitializeParseContext.cpp \
+        DependencyGraph.cpp \
+        DependencyGraphBuilder.cpp \
+        DependencyGraphOutput.cpp \
+        DependencyGraphTraverse.cpp \
+        RestrictFragmentShaderTiming.cpp \
+        RestrictVertexShaderTiming.cpp \
+        Compiler.cpp \
         DetectRecursion.cpp \
         InfoSink.cpp \
         Initialize.cpp \
         InitializeDll.cpp \
         Intermediate.cpp \
         intermOut.cpp \
         IntermTraverse.cpp \
         parseConst.cpp \
         ParseHelper.cpp \
         PoolAlloc.cpp \
         QualifierAlive.cpp \
         RemoveTree.cpp \
         ShaderLang.cpp \
         SymbolTable.cpp \
         VariableInfo.cpp \
         compilerdebug.cpp \
-        ossource_nspr.cpp \
         util.cpp \
         ValidateLimitations.cpp \
         ForLoopUnroll.cpp \
         MapLongVariableNames.cpp \
         spooky.cpp \
         BuiltInFunctionEmulator.cpp \
         Input.cpp \
         Lexer.cpp \
-        pp_lex.cpp \
         Preprocessor.cpp \
         Token.cpp \
-        lexer_glue.cpp \
         $(NULL)
 
 # flex/yacc generated files
 CPPSRCS += \
         glslang_lex.cpp \
         glslang_tab.cpp \
         $(NULL)
 
@@ -73,45 +88,40 @@ CPPSRCS += \
 CPPSRCS += \
         CodeGenGLSL.cpp \
         OutputGLSL.cpp \
         TranslatorGLSL.cpp \
         VersionGLSL.cpp \
         OutputESSL.cpp \
         OutputGLSLBase.cpp \
         TranslatorESSL.cpp \
-	$(NULL)
-
-# Currently, only one or the other
-# can be selected.
+        $(NULL)
 
-## HLSL translator backend
-##CPPSRCS += \
-##	CodeGenHLSL.cpp \
-##	OutputHLSL.cpp \
-##	TranslatorHLSL.cpp \
-##	UnfoldSelect.cpp \
-##	SearchSymbol.cpp \
-##	$(NULL)
+ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
+CPPSRCS += ossource_win.cpp $(NULL)
+else
+CPPSRCS += ossource_posix.cpp $(NULL)
+endif
 
 CSRCS   = \
         atom.c \
         cpp.c \
         cppstruct.c \
         memory.c \
         scanner.c \
         symbols.c \
         tokens.c \
-	$(NULL)
+        $(NULL)
 
-DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD -DCOMPILER_IMPLEMENTATION
+DEFINES += -DANGLE_BUILD -DCOMPILER_IMPLEMENTATION
 
 #these defines are from ANGLE's build_angle.gyp
 DEFINES += -DANGLE_DISABLE_TRACE
 DEFINES += -DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0
+DEFINES += -DANGLE_USE_NEW_PREPROCESSOR=1
 
 ifdef MOZ_ANGLE_RENDERER
 
 # libEGL depends on (links against!) libGLESv2!
 DIRS = src/libGLESv2 src/libEGL
 
 libs::
 	expand "$(MOZ_D3DX9_CAB)" -F:$(MOZ_D3DX9_DLL) "$(DIST)/bin"
--- a/gfx/angle/README.mozilla
+++ b/gfx/angle/README.mozilla
@@ -1,23 +1,40 @@
 This is the ANGLE project, from http://code.google.com/p/angleproject/
 
-Current revision: r1042
+Current revision: r1242
 
 == Applied local patches ==
 
 In this order:
-  angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
-  angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
-  angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
-  angle-enforce-readpixels-spec.patch - see bug 724476.
-  angle-impl-read-bgra.patch - see bug 724476.
-  angle-long-identifier-hash-spooky.patch - see bug 676071
+
+  angle-renaming-debug.patch
+    rename debug.h to compilerdebug.h to avoid conflict in our makefiles
+
+  angle-renaming-preprocessor-diagonostics.patch
+    rename one of the two Diagnostics.cpp to avoid conflict in our makefiles
+
+  angle-renaming-preprocessor-directivehandler.patch
+    rename one of the two DirectiveHandler.cpp to avoid conflict in our makefiles
+
+  angle-enforce-readpixels-spec.patch
+    see bug 724476
+
+  angle-impl-read-bgra.patch
+    see bug 724476
+
+  gfx/angle/angle-long-identifier-hash-spooky.patch
+    see bug 676071
+
+  angle-abort-on-oom-in-preprocessor.patch
+    see bug 680840. Probably not useful anymore now that we're on the new
+    preprocessor, but it doesn't hurt to keep it around a bit longer.
 
 In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
+Therefore, changes made to the Makefile.in files should not be stored in the local .patch files.
 
 == How to update this ANGLE copy ==
 
 1. Unapply patches
 2. Apply diff with new ANGLE version
 3. Reapply patches.
 4. Check for changes in src/build_angle.gyp, update our Makefile.in files accordingly. Note that a single file may be recorded in more than one Makefile.
 
new file mode 100644
--- /dev/null
+++ b/gfx/angle/angle-abort-on-oom-in-preprocessor.patch
@@ -0,0 +1,29 @@
+# HG changeset patch
+# Parent 11023ab3d23865b71678e9a4b22a45646ec0c0f0
+diff --git a/gfx/angle/src/compiler/preprocessor/atom.c b/gfx/angle/src/compiler/preprocessor/atom.c
+--- a/gfx/angle/src/compiler/preprocessor/atom.c
++++ b/gfx/angle/src/compiler/preprocessor/atom.c
+@@ -327,22 +327,17 @@ static int GrowAtomTable(AtomTable *atab
+             newmap = realloc(atable->amap, sizeof(int)*size);
+             newrev = realloc(atable->arev, sizeof(int)*size);
+         } else {
+             newmap = malloc(sizeof(int)*size);
+             newrev = malloc(sizeof(int)*size);
+             atable->size = 0;
+         }
+         if (!newmap || !newrev) {
+-            /* failed to grow -- error */
+-            if (newmap)
+-                atable->amap = newmap;
+-            if (newrev)
+-                atable->arev = newrev;
+-            return -1;
++            abort();
+         }
+         memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int));
+         memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int));
+         atable->amap = newmap;
+         atable->arev = newrev;
+         atable->size = size;
+     }
+     return 0;
deleted file mode 100644
--- a/gfx/angle/angle-castrate-bug-241.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-# HG changeset patch
-# User Benoit Jacob <bjacob@mozilla.com>
-# Parent 7dcbce54a953090ae8e537f93c6c99ab8eb0dc62
-
-diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla
---- a/gfx/angle/README.mozilla
-+++ b/gfx/angle/README.mozilla
-@@ -4,16 +4,17 @@ Current revision: r963
- 
- == Applied local patches ==
- 
- In this order:
-   angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
-   angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
-   angle-limit-identifiers-to-250-chars.patch - see bug 675625
-   angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
-+  angle-castrate-bug-241.patch - see bug 699033 / angle bug 241
- 
- In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
- 
- == How to update this ANGLE copy ==
- 
- 1. Unapply patches
- 2. Apply diff with new ANGLE version
- 3. Reapply patches.
-diff --git a/gfx/angle/src/compiler/Types.h b/gfx/angle/src/compiler/Types.h
---- a/gfx/angle/src/compiler/Types.h
-+++ b/gfx/angle/src/compiler/Types.h
-@@ -5,16 +5,17 @@
- //
- 
- #ifndef _TYPES_INCLUDED
- #define _TYPES_INCLUDED
- 
- #include "compiler/BaseTypes.h"
- #include "compiler/Common.h"
- #include "compiler/compilerdebug.h"
-+#include <cstdlib>
- 
- //
- // Need to have association of line numbers to types in a list for building structs.
- //
- class TType;
- struct TTypeLine {
-     TType* type;
-     int line;
-@@ -203,17 +204,17 @@ public:
-     bool isVector() const { return size > 1 && !matrix; }
-     bool isScalar() const { return size == 1 && !matrix && !structure; }
- 
-     TTypeList* getStruct() const { return structure; }
-     void setStruct(TTypeList* s) { structure = s; computeDeepestStructNesting(); }
- 
-     const TString& getTypeName() const
-     {
--        assert(typeName);
-+        if(!typeName) abort();
-         return *typeName;
-     }
-     void setTypeName(const TString& n)
-     {
-         typeName = NewPoolTString(n.c_str());
-     }
- 
-     bool isField() const { return fieldName != 0; }
--- a/gfx/angle/angle-enforce-readpixels-spec.patch
+++ b/gfx/angle/angle-enforce-readpixels-spec.patch
@@ -1,14 +1,14 @@
 # HG changeset patch
-# Parent 8d84c8d4e3ed41a4941afdf9d51819b19ca64716
+# Parent a1fed68f51737972901e0d6fc829d3e044a453bd
 diff --git a/gfx/angle/src/libGLESv2/libGLESv2.cpp b/gfx/angle/src/libGLESv2/libGLESv2.cpp
 --- a/gfx/angle/src/libGLESv2/libGLESv2.cpp
 +++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp
-@@ -98,27 +98,16 @@ bool validReadFormatType(GLenum format, 
+@@ -231,27 +231,16 @@ bool validReadFormatType(GLenum format, 
          switch (type)
          {
            case GL_UNSIGNED_BYTE:
              break;
            default:
              return false;
          }
          break;
--- a/gfx/angle/angle-impl-read-bgra.patch
+++ b/gfx/angle/angle-impl-read-bgra.patch
@@ -1,14 +1,14 @@
 # HG changeset patch
-# Parent 8b838be49f115022e403c850c24b28ad62d72ad6
+# Parent 97ded57f965865c06306a8ef82d082064542caff
 diff --git a/gfx/angle/src/libGLESv2/Context.cpp b/gfx/angle/src/libGLESv2/Context.cpp
 --- a/gfx/angle/src/libGLESv2/Context.cpp
 +++ b/gfx/angle/src/libGLESv2/Context.cpp
-@@ -2518,16 +2518,17 @@ void Context::readPixels(GLint x, GLint 
+@@ -2585,16 +2585,17 @@ void Context::readPixels(GLint x, GLint 
      {
          if (desc.Format == D3DFMT_A8R8G8B8 &&
              format == GL_BGRA_EXT &&
              type == GL_UNSIGNED_BYTE)
          {
              // Fast path for EXT_read_format_bgra, given
              // an RGBA source buffer.  Note that buffers with no
              // alpha go through the slow path below.
@@ -16,17 +16,17 @@ diff --git a/gfx/angle/src/libGLESv2/Con
              memcpy(dest + j * outputPitch,
                     source + j * inputPitch,
                     (rect.right - rect.left) * 4);
              continue;
          }
  
          for (int i = 0; i < rect.right - rect.left; i++)
          {
-@@ -2665,20 +2666,20 @@ void Context::readPixels(GLint x, GLint 
+@@ -2732,20 +2733,20 @@ void Context::readPixels(GLint x, GLint 
                          ((unsigned short)(     a + 0.5f) << 15) |
                          ((unsigned short)(31 * r + 0.5f) << 10) |
                          ((unsigned short)(31 * g + 0.5f) << 5) |
                          ((unsigned short)(31 * b + 0.5f) << 0);
                      break;
                    default: UNREACHABLE();
                  }
                  break;
deleted file mode 100644
--- a/gfx/angle/angle-intrinsic-msvc2005.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-# HG changeset patch
-# Parent 4ef86d96d456866537beea57b0a4451cf919cd34
-diff --git a/gfx/angle/src/libGLESv2/Texture.cpp b/gfx/angle/src/libGLESv2/Texture.cpp
---- a/gfx/angle/src/libGLESv2/Texture.cpp
-+++ b/gfx/angle/src/libGLESv2/Texture.cpp
-@@ -8,16 +8,22 @@
- // Texture2D and TextureCubeMap. Implements GL texture objects and related
- // functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
- 
- #include "libGLESv2/Texture.h"
- 
- #include <d3dx9tex.h>
- 
- #include <algorithm>
-+
-+#if _MSC_VER <= 1400
-+#define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
-+#define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
-+#endif
-+
- #include <intrin.h>
- 
- #include "common/debug.h"
- 
- #include "libEGL/Display.h"
- 
- #include "libGLESv2/main.h"
- #include "libGLESv2/mathutil.h"
-diff --git a/gfx/angle/src/libGLESv2/mathutil.h b/gfx/angle/src/libGLESv2/mathutil.h
---- a/gfx/angle/src/libGLESv2/mathutil.h
-+++ b/gfx/angle/src/libGLESv2/mathutil.h
-@@ -3,16 +3,21 @@
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- //
- 
- // mathutil.h: Math and bit manipulation functions.
- 
- #ifndef LIBGLESV2_MATHUTIL_H_
- #define LIBGLESV2_MATHUTIL_H_
-+
-+#if _MSC_VER <= 1400
-+#define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
-+#define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
-+#endif
- 
- #include <intrin.h>
- #include <math.h>
- #include <windows.h>
- 
- namespace gl
- {
- inline bool isPow2(int x)
--- a/gfx/angle/angle-long-identifier-hash-spooky.patch
+++ b/gfx/angle/angle-long-identifier-hash-spooky.patch
@@ -1,35 +1,15 @@
 # HG changeset patch
-# Parent 268bda9ac676b6f4cca5aa044d0dcefff2008535
-diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
---- a/gfx/angle/Makefile.in
-+++ b/gfx/angle/Makefile.in
-@@ -79,16 +79,17 @@ CPPSRCS = \
-         SymbolTable.cpp \
-         VariableInfo.cpp \
-         compilerdebug.cpp \
-         ossource_nspr.cpp \
-         util.cpp \
-         ValidateLimitations.cpp \
-         ForLoopUnroll.cpp \
-         MapLongVariableNames.cpp \
-+        spooky.cpp \
-         BuiltInFunctionEmulator.cpp \
-         $(NULL)
- 
- # flex/yacc generated files
- CPPSRCS += \
-         glslang_lex.cpp \
-         glslang_tab.cpp \
-         $(NULL)
+# Parent c5e7517cbb1c38ce9821ba3deca88768b4dff066
+
 diff --git a/gfx/angle/src/compiler/MapLongVariableNames.cpp b/gfx/angle/src/compiler/MapLongVariableNames.cpp
 --- a/gfx/angle/src/compiler/MapLongVariableNames.cpp
 +++ b/gfx/angle/src/compiler/MapLongVariableNames.cpp
-@@ -1,27 +1,30 @@
+@@ -1,29 +1,36 @@
  //
  // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  //
  
  #include "compiler/MapLongVariableNames.h"
 +#include "spooky.h"
@@ -38,25 +18,33 @@ diff --git a/gfx/angle/src/compiler/MapL
  
  TString mapLongName(int id, const TString& name, bool isGlobal)
  {
      ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
      TStringStream stream;
 -    stream << "webgl_";
 -    if (isGlobal)
 -        stream << "g";
--    stream << id << "_";
+-    stream << id;
+-    if (name[0] != '_')
+-        stream << "_";
 -    stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
 +    uint64 hash = SpookyHash::Hash64(name.data(), name.length(), 0);
-+    stream << "webgl_"
++
++    // We want to avoid producing a string with a double underscore,
++    // which would be an illegal GLSL identifier. We can assume that the
++    // original identifier doesn't have a double underscore, otherwise
++    // it's illegal anyway.
++    stream << (name[0] == '_' ? "webgl" : "webgl_")
 +           << name.substr(0, 9)
-+           << "_"
++           << (name[8] == '_' ? "" : "_")
 +           << std::hex
 +           << hash;
-+    ASSERT(stream.str().length() == MAX_SHORTENED_IDENTIFIER_SIZE);
++    ASSERT(stream.str().length() <= MAX_SHORTENED_IDENTIFIER_SIZE);
++    ASSERT(stream.str().length() >= MAX_SHORTENED_IDENTIFIER_SIZE - 2);
      return stream.str();
  }
  
  LongNameMap* gLongNameMapInstance = NULL;
  
  }  // anonymous namespace
  
  LongNameMap::LongNameMap()
@@ -706,50 +694,8 @@ new file mode 100644
 +    uint64 m_data[2*sc_numVars];   // unhashed data, for partial messages
 +    uint64 m_state[sc_numVars];  // internal state of the hash
 +    size_t m_length;             // total length of the input so far
 +    uint8  m_remainder;          // length of unhashed data stashed in m_data
 +};
 +
 +
 +
-diff --git a/gfx/angle/src/libEGL/Makefile.in b/gfx/angle/src/libEGL/Makefile.in
---- a/gfx/angle/src/libEGL/Makefile.in
-+++ b/gfx/angle/src/libEGL/Makefile.in
-@@ -91,16 +91,17 @@ CPPSRCS = \
-   SymbolTable.cpp \
-   VariableInfo.cpp \
-   compilerdebug.cpp \
-   ossource_win.cpp \
-   util.cpp \
-   ValidateLimitations.cpp \
-   ForLoopUnroll.cpp \
-   MapLongVariableNames.cpp \
-+  spooky.cpp \
-   BuiltInFunctionEmulator.cpp \
-   $(NULL)
-