Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 26 Jul 2012 18:19:02 -0700
changeset 106638 31f9c38e4cb9719649d9b974c00fe232e3bbb71e
parent 106637 02f44534f7f55b9115924d8eeeedb66e899ef5ce (current diff)
parent 100666 f528e021ceb1daff2d854d9c460e907d4397b0d4 (diff)
child 106639 1274d6819bae7c97d22a872ac8092d8c51c80b01
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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"