Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 30 Jun 2014 15:53:28 +0200
changeset 191591 d2fae324ed754e095005d84c733b77b06a87d96f
parent 191590 dfb6187d8e17f2379fbcc12c45203026efb182aa (current diff)
parent 191468 3b46de297f3f5a3beda7df16c4cf8c511b4d99e9 (diff)
child 191592 c95990f3bf3fae6d5756b6e87695ae00a371a2ff
push id45618
push userkwierso@gmail.com
push dateTue, 01 Jul 2014 01:47:43 +0000
treeherdermozilla-inbound@d0787b1eebc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone33.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 mozilla-central to b2g-inbound
layout/reftests/font-inflation/disable-fontinfl-on-mobile-4.html
--- a/browser/devtools/canvasdebugger/test/browser.ini
+++ b/browser/devtools/canvasdebugger/test/browser.ini
@@ -1,23 +1,25 @@
 [DEFAULT]
 subsuite = devtools
 support-files =
   doc_simple-canvas.html
+  doc_simple-canvas-bitmasks.html
   doc_simple-canvas-deep-stack.html
   doc_simple-canvas-transparent.html
   head.js
 
 [browser_canvas-actor-test-01.js]
 [browser_canvas-actor-test-02.js]
 [browser_canvas-actor-test-03.js]
 [browser_canvas-actor-test-04.js]
 [browser_canvas-actor-test-05.js]
 [browser_canvas-actor-test-06.js]
 [browser_canvas-actor-test-07.js]
+[browser_canvas-actor-test-08.js]
 [browser_canvas-frontend-call-highlight.js]
 [browser_canvas-frontend-call-list.js]
 [browser_canvas-frontend-call-search.js]
 [browser_canvas-frontend-call-stack-01.js]
 [browser_canvas-frontend-call-stack-02.js]
 [browser_canvas-frontend-call-stack-03.js]
 [browser_canvas-frontend-clear.js]
 [browser_canvas-frontend-img-screenshots.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-08.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that integers used in arguments are not cast to their constant, enum value
+ * forms if the method's signature does not expect an enum. Bug 999687.
+ */
+
+function ifTestingSupported() {
+  let [target, debuggee, front] = yield initCanavsDebuggerBackend(SIMPLE_BITMASKS_URL);
+
+  let navigated = once(target, "navigate");
+
+  yield front.setup({ reload: true });
+  ok(true, "The front was setup up successfully.");
+
+  yield navigated;
+  ok(true, "Target automatically navigated when the front was set up.");
+
+  let snapshotActor = yield front.recordAnimationFrame();
+
+  let animationOverview = yield snapshotActor.getOverview();
+
+  let functionCalls = animationOverview.calls;
+
+  is(functionCalls[0].name, "clearRect",
+    "The first called function's name is correct.");
+  is(functionCalls[0].argsPreview, "0, 0, 4, 4",
+    "The first called function's args preview is not cast to enums.");
+
+  is(functionCalls[2].name, "fillRect",
+    "The fillRect called function's name is correct.");
+  is(functionCalls[2].argsPreview, "0, 0, 1, 1",
+    "The fillRect called function's args preview is not casted to enums.");
+
+  yield removeTab(target.tab);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/canvasdebugger/test/doc_simple-canvas-bitmasks.html
@@ -0,0 +1,34 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>Canvas inspector test page</title>
+  </head>
+
+  <body>
+    <canvas width="128" height="128"></canvas>
+
+    <script type="text/javascript;version=1.8">
+      "use strict";
+
+      var ctx = document.querySelector("canvas").getContext("2d");
+
+      function drawRect(fill, size) {
+        ctx.fillStyle = fill;
+        ctx.fillRect(size[0], size[1], size[2], size[3]);
+      }
+
+      function drawScene() {
+        ctx.clearRect(0, 0, 4, 4);
+        drawRect("rgb(192, 192, 192)", [0, 0, 1, 1]);
+        window.requestAnimationFrame(drawScene);
+      }
+
+      drawScene();
+    </script>
+  </body>
+
+</html>
--- a/browser/devtools/canvasdebugger/test/head.js
+++ b/browser/devtools/canvasdebugger/test/head.js
@@ -21,16 +21,17 @@ let { DebuggerClient } = Cu.import("reso
 let { CallWatcherFront } = devtools.require("devtools/server/actors/call-watcher");
 let { CanvasFront } = devtools.require("devtools/server/actors/canvas");
 let TiltGL = devtools.require("devtools/tilt/tilt-gl");
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/canvasdebugger/test/";
 const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html";
+const SIMPLE_BITMASKS_URL = EXAMPLE_URL + "doc_simple-canvas-bitmasks.html";
 const SIMPLE_CANVAS_TRANSPARENT_URL = EXAMPLE_URL + "doc_simple-canvas-transparent.html";
 const SIMPLE_CANVAS_DEEP_STACK_URL = EXAMPLE_URL + "doc_simple-canvas-deep-stack.html";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 let gToolEnabled = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled");
 
--- a/browser/devtools/netmonitor/test/browser_net_accessibility-01.js
+++ b/browser/devtools/netmonitor/test/browser_net_accessibility-01.js
@@ -4,16 +4,19 @@
 /**
  * Tests if focus modifiers work for the SideMenuWidget.
  */
 
 function test() {
   initNetMonitor(CUSTOM_GET_URL).then(([aTab, aDebuggee, aMonitor]) => {
     info("Starting test... ");
 
+    // It seems that this test may be slow on Ubuntu builds running on ec2.
+    requestLongerTimeout(2);
+
     let { NetMonitorView } = aMonitor.panelWin;
     let { RequestsMenu } = NetMonitorView;
 
     RequestsMenu.lazyUpdate = false;
 
     waitForNetworkEvents(aMonitor, 2).then(() => {
       check(-1, false);
 
--- a/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
+++ b/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
@@ -4,16 +4,19 @@
 /**
  * Tests if keyboard and mouse navigation works in the network requests menu.
  */
 
 function test() {
   initNetMonitor(CUSTOM_GET_URL).then(([aTab, aDebuggee, aMonitor]) => {
     info("Starting test... ");
 
+    // It seems that this test may be slow on Ubuntu builds running on ec2.
+    requestLongerTimeout(2);
+
     let { window, $, NetMonitorView } = aMonitor.panelWin;
     let { RequestsMenu } = NetMonitorView;
 
     RequestsMenu.lazyUpdate = false;
 
     waitForNetworkEvents(aMonitor, 2).then(() => {
       check(-1, false);
 
--- a/browser/devtools/webaudioeditor/test/browser.ini
+++ b/browser/devtools/webaudioeditor/test/browser.ini
@@ -27,16 +27,17 @@ support-files =
 [browser_wa_reset-02.js]
 [browser_wa_reset-03.js]
 
 [browser_wa_graph-click.js]
 [browser_wa_graph-render-01.js]
 [browser_wa_graph-render-02.js]
 [browser_wa_graph-markers.js]
 [browser_wa_graph-selected.js]
+[browser_wa_graph-zoom.js]
 
 [browser_wa_inspector.js]
 [browser_wa_inspector-toggle.js]
 
 [browser_wa_properties-view.js]
 [browser_wa_properties-view-media-nodes.js]
 # [browser_wa_properties-view-edit-01.js]
 # [browser_wa_properties-view-edit-02.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/browser_wa_graph-zoom.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the graph's scale and position is reset on a page reload.
+ */
+
+function spawnTest() {
+  let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
+  let { panelWin } = panel;
+  let { gFront, $, $$, EVENTS, WebAudioGraphView } = panelWin;
+
+  let started = once(gFront, "start-context");
+
+  yield Promise.all([
+    reload(target),
+    waitForGraphRendered(panelWin, 3, 2)
+  ]);
+
+  is(WebAudioGraphView.getCurrentScale(), 1, "Default graph scale is 1.");
+  is(WebAudioGraphView.getCurrentTranslation()[0], 20, "Default x-translation is 20.");
+  is(WebAudioGraphView.getCurrentTranslation()[1], 20, "Default y-translation is 20.");
+
+  // Change both attribute and D3's internal store
+  panelWin.d3.select("#graph-target").attr("transform", "translate([100, 400]) scale(10)");
+  WebAudioGraphView._zoomBinding.scale(10);
+  WebAudioGraphView._zoomBinding.translate([100, 400]);
+
+  is(WebAudioGraphView.getCurrentScale(), 10, "After zoom, scale is 10.");
+  is(WebAudioGraphView.getCurrentTranslation()[0], 100, "After zoom, x-translation is 100.");
+  is(WebAudioGraphView.getCurrentTranslation()[1], 400, "After zoom, y-translation is 400.");
+
+  yield Promise.all([
+    reload(target),
+    waitForGraphRendered(panelWin, 3, 2)
+  ]);
+
+  is(WebAudioGraphView.getCurrentScale(), 1, "After refresh, graph scale is 1.");
+  is(WebAudioGraphView.getCurrentTranslation()[0], 20, "After refresh, x-translation is 20.");
+  is(WebAudioGraphView.getCurrentTranslation()[1], 20, "After refresh, y-translation is 20.");
+
+  yield teardown(panel);
+  finish();
+}
+
--- a/browser/devtools/webaudioeditor/webaudioeditor-view.js
+++ b/browser/devtools/webaudioeditor/webaudioeditor-view.js
@@ -11,20 +11,21 @@ const { debounce } = require("sdk/lang/f
 const EXPAND_INSPECTOR_STRING = L10N.getStr("expandInspector");
 const COLLAPSE_INSPECTOR_STRING = L10N.getStr("collapseInspector");
 
 // Store width as a preference rather than hardcode
 // TODO bug 1009056
 const INSPECTOR_WIDTH = 300;
 
 // Globals for d3 stuff
-// Width/height in pixels of SVG graph
-// TODO investigate to see how this works in other host types bug 994257
-const WIDTH = 1000;
-const HEIGHT = 400;
+// Default properties of the graph on rerender
+const GRAPH_DEFAULTS = {
+  translate: [20, 20],
+  scale: 1
+};
 
 // Sizes of SVG arrows in graph
 const ARROW_HEIGHT = 5;
 const ARROW_WIDTH = 8;
 
 // Styles for markers as they cannot be done with CSS.
 const MARKER_STYLING = {
   light: "#AAA",
@@ -79,28 +80,52 @@ let WebAudioGraphView = {
     window.off(EVENTS.DESTROY_NODE, this._onDestroyNode);
   },
 
   /**
    * Called when a page is reloaded and waiting for a "start-context" event
    * and clears out old content
    */
   resetUI: function () {
-    this.resetGraph();
+    this.clearGraph();
+    this.resetGraphPosition();
   },
 
   /**
    * Clears out the rendered graph, called when resetting the SVG elements to draw again,
    * or when resetting the entire UI tool
    */
-  resetGraph: function () {
+  clearGraph: function () {
     $("#graph-target").innerHTML = "";
   },
 
   /**
+   * Moves the graph back to its original scale and translation.
+   */
+  resetGraphPosition: function () {
+    if (this._zoomBinding) {
+      let { translate, scale } = GRAPH_DEFAULTS;
+      // Must set the `zoomBinding` so the next `zoom` event is in sync with
+      // where the graph is visually (set by the `transform` attribute).
+      this._zoomBinding.scale(scale);
+      this._zoomBinding.translate(translate);
+      d3.select("#graph-target")
+        .attr("transform", "translate(" + translate + ") scale(" + scale + ")");
+    }
+  },
+
+  getCurrentScale: function () {
+    return this._zoomBinding ? this._zoomBinding.scale() : null;
+  },
+
+  getCurrentTranslation: function () {
+    return this._zoomBinding ? this._zoomBinding.translate() : null;
+  },
+
+  /**
    * Makes the corresponding graph node appear "focused", removing
    * focused styles from all other nodes. If no `actorID` specified,
    * make all nodes appear unselected.
    * Called from UI_INSPECTOR_NODE_SELECT.
    */
   focusNode: function (actorID) {
     // Remove class "selected" from all nodes
     Array.forEach($$(".nodes > g"), $node => $node.classList.remove("selected"));
@@ -119,17 +144,17 @@ let WebAudioGraphView = {
 
   /**
    * `draw` renders the ViewNodes currently available in `AudioNodes` with `AudioNodeConnections`,
    * and is throttled to be called at most every `GRAPH_DEBOUNCE_TIMER` milliseconds. Is called
    * whenever the audio context routing changes, after being debounced.
    */
   draw: function () {
     // Clear out previous SVG information
-    this.resetGraph();
+    this.clearGraph();
 
     let graph = new dagreD3.Digraph();
     let edges = [];
 
     AudioNodes.forEach(node => {
       // Add node to graph
       graph.addNode(node.id, { label: node.type, id: node.id });
 
@@ -215,16 +240,20 @@ let WebAudioGraphView = {
     // store as `this._zoomBinding` so we can unbind during destruction
     if (!this._zoomBinding) {
       this._zoomBinding = d3.behavior.zoom().on("zoom", function () {
         var ev = d3.event;
         d3.select("#graph-target")
           .attr("transform", "translate(" + ev.translate + ") scale(" + ev.scale + ")");
       });
       d3.select("svg").call(this._zoomBinding);
+
+      // Set initial translation and scale -- this puts D3's awareness of
+      // the graph in sync with what the user sees originally.
+      this.resetGraphPosition();
     }
   },
 
   /**
    * Event handlers
    */
 
   /**
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -2238,41 +2238,20 @@ nsresult MediaDecoderStateMachine::RunSt
   NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
 
   switch (mState) {
     case DECODER_STATE_SHUTDOWN: {
       if (IsPlaying()) {
         StopPlayback();
       }
 
-      // Put a task in the decode queue to abort any decoding operations.
-      // The reader is not supposed to put any tasks to deliver samples into
-      // the queue after we call this (unless we request another sample from it).
-      RefPtr<nsIRunnable> task;
-      task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
-      mDecodeTaskQueue->Dispatch(task);
-
-      {
-        // Wait for the thread decoding to abort decoding operations and run
-        // any pending callbacks. This is important, as we don't want any
-        // pending tasks posted to the task queue by the reader to deliver
-        // any samples after we've posted the reader Shutdown() task below,
-        // as the sample-delivery tasks will keep video frames alive until
-        // after we've called Reader::Shutdown(), and shutdown on B2G will
-        // fail as there are outstanding video frames alive.
-        ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
-        mDecodeTaskQueue->Flush();
-      }
-
-      // We must reset playback so that all references to frames queued
-      // in the state machine are dropped, else the Shutdown() call below
-      // can fail on B2G.
-      ResetPlayback();
+      FlushDecoding();
 
       // Put a task in the decode queue to shutdown the reader.
+      RefPtr<nsIRunnable> task;
       task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::Shutdown);
       mDecodeTaskQueue->Dispatch(task);
 
       StopAudioThread();
       // If mAudioSink is non-null after StopAudioThread completes, we are
       // running in a nested event loop waiting for Shutdown() on
       // mAudioSink to complete.  Return to the event loop and let it
       // finish processing before continuing with shutdown.
@@ -2320,16 +2299,17 @@ nsresult MediaDecoderStateMachine::RunSt
       mTimer = nullptr;
       return NS_OK;
     }
 
     case DECODER_STATE_DORMANT: {
       if (IsPlaying()) {
         StopPlayback();
       }
+      FlushDecoding();
       StopAudioThread();
       // Now that those threads are stopped, there's no possibility of
       // mPendingWakeDecoder being needed again. Revoke it.
       mPendingWakeDecoder = nullptr;
       {
         ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
         // Wait for the thread decoding, if any, to exit.
         mDecodeTaskQueue->AwaitIdle();
@@ -2462,16 +2442,48 @@ nsresult MediaDecoderStateMachine::RunSt
       }
       return NS_OK;
     }
   }
 
   return NS_OK;
 }
 
+void
+MediaDecoderStateMachine::FlushDecoding()
+{
+  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
+               "Should be on state machine or decode thread.");
+  mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
+
+  // Put a task in the decode queue to abort any decoding operations.
+  // The reader is not supposed to put any tasks to deliver samples into
+  // the queue after we call this (unless we request another sample from it).
+  RefPtr<nsIRunnable> task;
+  task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
+  mDecodeTaskQueue->Dispatch(task);
+
+  {
+    // Wait for the thread decoding to abort decoding operations and run
+    // any pending callbacks. This is important, as we don't want any
+    // pending tasks posted to the task queue by the reader to deliver
+    // any samples after we've posted the reader Shutdown() task below,
+    // as the sample-delivery tasks will keep video frames alive until
+    // after we've called Reader::Shutdown(), and shutdown on B2G will
+    // fail as there are outstanding video frames alive.
+    ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
+    mDecodeTaskQueue->Flush();
+  }
+
+  // We must reset playback so that all references to frames queued
+  // in the state machine are dropped, else subsequent calls to Shutdown()
+  // or ReleaseMediaResources() can fail on B2G.
+  ResetPlayback();
+}
+
 void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
                                                 TimeStamp aTarget)
 {
   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
                "Should be on state machine or decode thread.");
   mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
 
   if (aData->mDuplicate) {
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -440,16 +440,21 @@ protected:
   bool JustExitedQuickBuffering();
 
   // Dispatches an asynchronous event to update the media element's ready state.
   void UpdateReadyState();
 
   // Resets playback timing data. Called when we seek, on the decode thread.
   void ResetPlayback();
 
+  // Orders the Reader to stop decoding, and blocks until the Reader
+  // has stopped decoding and finished delivering samples, then calls
+  // ResetPlayback() to discard all enqueued data. 
+  void FlushDecoding();
+
   // Returns the audio clock, if we have audio, or -1 if we don't.
   // Called on the state machine thread.
   int64_t GetAudioClock();
 
   // Get the video stream position, taking the |playbackRate| change into
   // account. This is a position in the media, not the duration of the playback
   // so far.
   int64_t GetVideoStreamPosition();
--- a/content/media/gmp/GMPParent.cpp
+++ b/content/media/gmp/GMPParent.cpp
@@ -415,10 +415,31 @@ GMPParent::ReadGMPMetaData()
 
   if (mCapabilities.IsEmpty()) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
+bool
+GMPParent::CanBeSharedCrossOrigin() const
+{
+  return mOrigin.IsEmpty();
+}
+
+bool
+GMPParent::CanBeUsedFrom(const nsAString& aOrigin) const
+{
+  return (mOrigin.IsEmpty() && State() == GMPStateNotLoaded) ||
+         mOrigin.Equals(aOrigin);
+}
+
+void
+GMPParent::SetOrigin(const nsAString& aOrigin)
+{
+  MOZ_ASSERT(!aOrigin.IsEmpty());
+  MOZ_ASSERT(CanBeUsedFrom(aOrigin));
+  mOrigin = aOrigin;
+}
+
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/GMPParent.h
+++ b/content/media/gmp/GMPParent.h
@@ -51,16 +51,37 @@ public:
   void VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder);
   nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
   void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
   GMPState State() const;
 #ifdef DEBUG
   nsIThread* GMPThread();
 #endif
 
+  // A GMP can either be a single instance shared across all origins (like
+  // in the OpenH264 case), or we can require a new plugin instance for every
+  // origin running the plugin (as in the EME plugin case).
+  //
+  // Plugins are associated with an origin by calling SetOrigin() before
+  // loading.
+  //
+  // If a plugin has no origin specified and it is loaded, it is assumed to
+  // be shared across origins.
+
+  // Specifies that a GMP can only work with the specified origin.
+  void SetOrigin(const nsAString& aOrigin);
+
+  // Returns true if a plugin can be or is being used across multiple origins.
+  bool CanBeSharedCrossOrigin() const;
+
+  // A GMP can be used from an origin if it's already been set to work with
+  // that origin, or if it's not been set to work with any origin and has
+  // not yet been loaded (i.e. it's not shared across origins).
+  bool CanBeUsedFrom(const nsAString& aOrigin) const;
+
 private:
   ~GMPParent();
   bool EnsureProcessLoaded();
   nsresult ReadGMPMetaData();
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent() MOZ_OVERRIDE;
   virtual bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) MOZ_OVERRIDE;
   virtual PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() MOZ_OVERRIDE;
@@ -75,14 +96,17 @@ private:
   nsTArray<nsAutoPtr<GMPCapability>> mCapabilities;
   GMPProcessParent* mProcess;
 
   nsTArray<nsRefPtr<GMPVideoDecoderParent>> mVideoDecoders;
   nsTArray<nsRefPtr<GMPVideoEncoderParent>> mVideoEncoders;
 #ifdef DEBUG
   nsCOMPtr<nsIThread> mGMPThread;
 #endif
+  // Origin the plugin is assigned to, or empty if the the plugin is not
+  // assigned to an origin.
+  nsAutoString mOrigin;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPParent_h_
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -186,26 +186,33 @@ GeckoMediaPluginService::GetThread(nsITh
 
   NS_ADDREF(mGMPThread);
   *aThread = mGMPThread;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-GeckoMediaPluginService::GetGMPVideoDecoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoDecoder** aGMPVD)
+GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
+                                            const nsAString& aOrigin,
+                                            GMPVideoHost** aOutVideoHost,
+                                            GMPVideoDecoder** aGMPVD)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+  NS_ENSURE_ARG(aTags && aTags->Length() > 0);
+  NS_ENSURE_ARG(aOutVideoHost);
+  NS_ENSURE_ARG(aGMPVD);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("decode-video"),
-                                               NS_LITERAL_CSTRING("vp8"));
+  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
+                                               NS_LITERAL_CSTRING("decode-video"),
+                                               *aTags);
   if (!gmp) {
     return NS_ERROR_FAILURE;
   }
 
   GMPVideoDecoderParent* gmpVDP;
   nsresult rv = gmp->GetGMPVideoDecoder(&gmpVDP);
   if (NS_FAILED(rv)) {
     return rv;
@@ -213,26 +220,33 @@ GeckoMediaPluginService::GetGMPVideoDeco
 
   *aGMPVD = gmpVDP;
   *aOutVideoHost = &gmpVDP->Host();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-GeckoMediaPluginService::GetGMPVideoEncoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoEncoder** aGMPVE)
+GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
+                                            const nsAString& aOrigin,
+                                            GMPVideoHost** aOutVideoHost,
+                                            GMPVideoEncoder** aGMPVE)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+  NS_ENSURE_ARG(aTags && aTags->Length() > 0);
+  NS_ENSURE_ARG(aOutVideoHost);
+  NS_ENSURE_ARG(aGMPVE);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("encode-video"),
-                                               NS_LITERAL_CSTRING("vp8"));
+  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
+                                               NS_LITERAL_CSTRING("encode-video"),
+                                               *aTags);
   if (!gmp) {
     return NS_ERROR_FAILURE;
   }
 
   GMPVideoEncoderParent* gmpVEP;
   nsresult rv = gmp->GetGMPVideoEncoder(&gmpVEP);
   if (NS_FAILED(rv)) {
     return rv;
@@ -254,40 +268,60 @@ GeckoMediaPluginService::UnloadPlugins()
 
   for (uint32_t i = 0; i < mPlugins.Length(); i++) {
     mPlugins[i]->UnloadProcess();
   }
   mPlugins.Clear();
 }
 
 GMPParent*
-GeckoMediaPluginService::SelectPluginForAPI(const nsCString& aAPI,
-                                            const nsCString& aTag)
+GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
+                                            const nsCString& aAPI,
+                                            const nsTArray<nsCString>& aTags)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
-  GMPParent* gmp = SelectPluginFromListForAPI(aAPI, aTag);
+  GMPParent* gmp = SelectPluginFromListForAPI(aOrigin, aAPI, aTags);
   if (gmp) {
     return gmp;
   }
 
   RefreshPluginList();
 
-  return SelectPluginFromListForAPI(aAPI, aTag);
+  return SelectPluginFromListForAPI(aOrigin, aAPI, aTags);
 }
 
 GMPParent*
-GeckoMediaPluginService::SelectPluginFromListForAPI(const nsCString& aAPI,
-                                                    const nsCString& aTag)
+GeckoMediaPluginService::SelectPluginFromListForAPI(const nsAString& aOrigin,
+                                                    const nsCString& aAPI,
+                                                    const nsTArray<nsCString>& aTags)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
   for (uint32_t i = 0; i < mPlugins.Length(); i++) {
     GMPParent* gmp = mPlugins[i];
-    if (gmp->SupportsAPI(aAPI, aTag)) {
+    bool supportsAllTags = true;
+    for (uint32_t t = 0; t < aTags.Length(); t++) {
+      const nsCString& tag = aTags[t];
+      if (!gmp->SupportsAPI(aAPI, tag)) {
+        supportsAllTags = false;
+        break;
+      }
+    }
+    if (!supportsAllTags) {
+      continue;
+    }
+    if (aOrigin.IsEmpty()) {
+      if (gmp->CanBeSharedCrossOrigin()) {
+        return gmp;
+      }
+    } else if (gmp->CanBeUsedFrom(aOrigin)) {
+      if (!aOrigin.IsEmpty()) {
+        gmp->SetOrigin(aOrigin);
+      }
       return gmp;
     }
   }
   return nullptr;
 }
 
 nsresult
 GeckoMediaPluginService::GetDirectoriesToSearch(nsTArray<nsCOMPtr<nsIFile>> &aDirs)
--- a/content/media/gmp/GMPService.h
+++ b/content/media/gmp/GMPService.h
@@ -33,18 +33,22 @@ public:
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_MOZIGECKOMEDIAPLUGINSERVICE
   NS_DECL_NSIOBSERVER
 
 private:
   ~GeckoMediaPluginService();
 
-  GMPParent* SelectPluginFromListForAPI(const nsCString& aAPI, const nsCString& aTag);
-  GMPParent* SelectPluginForAPI(const nsCString& aAPI, const nsCString& aTag);
+  GMPParent* SelectPluginFromListForAPI(const nsAString& aOrigin,
+                                        const nsCString& aAPI,
+                                        const nsTArray<nsCString>& aTags);
+  GMPParent* SelectPluginForAPI(const nsAString& aOrigin,
+                                const nsCString& aAPI,
+                                const nsTArray<nsCString>& aTags);
   void UnloadPlugins();
 
   void RefreshPluginList();
   void ProcessPossiblePlugin(nsIFile* aDir);
   nsresult SearchDirectory(nsIFile* aSearchDir);
   nsresult GetPossiblePlugins(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
   nsresult GetDirectoriesToSearch(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
 
--- a/content/media/gmp/GMPVideoHost.cpp
+++ b/content/media/gmp/GMPVideoHost.cpp
@@ -91,17 +91,17 @@ GMPVideoHostImpl::ActorDestroyed()
   for (uint32_t i = mPlanes.Length(); i > 0; i--) {
     mPlanes[i - 1]->ActorDestroyed();
     mPlanes.RemoveElementAt(i - 1);
   }
   for (uint32_t i = mEncodedFrames.Length(); i > 0; i--) {
     mEncodedFrames[i - 1]->ActorDestroyed();
     mEncodedFrames.RemoveElementAt(i - 1);
   }
-  mSharedMemMgr = nullptr;  
+  mSharedMemMgr = nullptr;
 }
 
 void
 GMPVideoHostImpl::PlaneCreated(GMPPlaneImpl* aPlane)
 {
   mPlanes.AppendElement(aPlane);
 }
 
--- a/content/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/content/media/gmp/mozIGeckoMediaPluginService.idl
@@ -1,34 +1,46 @@
 /* -*- 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 "nsISupports.idl"
 #include "nsIThread.idl"
+#include "nsIPrincipal.idl"
 
 %{C++
+#include "nsTArray.h"
+#include "nsStringGlue.h"
 class GMPVideoDecoder;
 class GMPVideoEncoder;
 class GMPVideoHost;
 %}
 
 [ptr] native GMPVideoDecoder(GMPVideoDecoder);
 [ptr] native GMPVideoEncoder(GMPVideoEncoder);
 [ptr] native GMPVideoHost(GMPVideoHost);
 [ptr] native MessageLoop(MessageLoop);
+[ptr] native TagArray(nsTArray<nsCString>);
 
 [uuid(BF5A9086-70F5-4D38-832D-1609BBF963CD)]
 interface mozIGeckoMediaPluginService : nsISupports
 {
   // Returns the GMP thread.
   // Callable from any thread.
   readonly attribute nsIThread thread;
 
-  // Returns a video decoder API object that should support VP8.
+  // Returns a video decoder that supports the specified tags.
+  // The array of tags should at least contain a codec tag, and optionally
+  // other tags such as for EME keysystem.
   // Callable only on GMP thread.
-  GMPVideoDecoder getGMPVideoDecoderVP8(out GMPVideoHost outVideoHost);
+  GMPVideoDecoder getGMPVideoDecoder(in TagArray tags,
+                                     [optional] in AString origin,
+                                     out GMPVideoHost outVideoHost);
 
-  // Returns a video encoder API object that should support VP8.
+  // Returns a video encoder that supports the specified tags.
+  // The array of tags should at least contain a codec tag, and optionally
+  // other tags.
   // Callable only on GMP thread.
-  GMPVideoEncoder getGMPVideoEncoderVP8(out GMPVideoHost outVideoHost);
+  GMPVideoEncoder getGMPVideoEncoder(in TagArray tags,
+                                     [optional] in AString origin,
+                                     out GMPVideoHost outVideoHost);
 };
--- a/content/xul/templates/tests/chrome/test_bug476634.xul
+++ b/content/xul/templates/tests/chrome/test_bug476634.xul
@@ -34,33 +34,33 @@ https://bugzilla.mozilla.org/show_bug.cg
 <![CDATA[
 function startup() {
   var ss = Components.classes["@mozilla.org/storage/service;1"]
                      .getService(Components.interfaces.mozIStorageService);
   var db = ss.openSpecialDatabase("memory");
   
   db.createTable("test", "id TEXT, value INTEGER");
   var stmt = db.createStatement("INSERT INTO test (id, value) VALUES (?,?)");
-  stmt.bindStringParameter(0, "test1");
-  stmt.bindInt32Parameter(1, 0);
+  stmt.bindByIndex(0, "test1");
+  stmt.bindByIndex(1, 0);
   stmt.execute();
-  stmt.bindStringParameter(0, "test2");
-  stmt.bindInt32Parameter(1, 2147483647);
+  stmt.bindByIndex(0, "test2");
+  stmt.bindByIndex(1, 2147483647);
   stmt.execute();
-  stmt.bindStringParameter(0, "test3");
-  stmt.bindInt32Parameter(1, -2147483648);
+  stmt.bindByIndex(0, "test3");
+  stmt.bindByIndex(1, -2147483648);
   stmt.execute();
-  stmt.bindStringParameter(0, "test4");
-  stmt.bindInt64Parameter(1, 0);
+  stmt.bindByIndex(0, "test4");
+  stmt.bindByIndex(1, 0);
   stmt.execute();
-  stmt.bindStringParameter(0, "test5");
-  stmt.bindInt64Parameter(1, 3147483647);
+  stmt.bindByIndex(0, "test5");
+  stmt.bindByIndex(1, 3147483647);
   stmt.execute();
-  stmt.bindStringParameter(0, "test6");
-  stmt.bindInt64Parameter(1, -3147483648);
+  stmt.bindByIndex(0, "test6");
+  stmt.bindByIndex(1, -3147483648);
   stmt.execute();
   stmt.finalize();
 
   var list = document.getElementById("results-list");
   list.builder.datasource = db;
 
   is(list.childNodes.length, 6, "Should be 6 generated elements");
   is(list.childNodes[0].value, "0", "Should have seen the correct value");
--- a/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js
+++ b/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js
@@ -140,89 +140,144 @@ function startTest() {
 
   req0.onerror = function() {
     ok(false, 'setInputMethodActive failed (0): ' + this.error.name);
   };
 }
 
 var gCount = 0;
 
+var gFrameMsgCounts = {
+  'input': 0,
+  'im0': 0,
+  'im1': 0
+};
+
 function next(msg) {
   let wrappedMsg = SpecialPowers.wrap(msg);
   let from = wrappedMsg.data.from;
   let value = wrappedMsg.data.value;
 
   if (wrappedMsg.data.error) {
     ok(false, wrappedMsg.data.value);
 
     return;
   }
 
-  gCount++;
+  let fromId = from;
+  if (from === 'im') {
+    fromId += value[1];
+  }
+  gFrameMsgCounts[fromId]++;
 
   // The texts sent from the first and the second input method are '#0' and
   // '#1' respectively.
   switch (gCount) {
-    case 1:
-      is(from, 'im', 'Message sequence unexpected (1).');
-      is(value, '#0true', 'First frame should get the context first.');
-      // Do nothing and wait for the input to show up in input frame.
-      break;
+    case 0:
+      switch (fromId) {
+        case 'im0':
+          if (gFrameMsgCounts.im0 === 1) {
+            is(value, '#0true', 'First frame should get the context first.');
+          } else {
+            ok(false, 'Unexpected multiple messages from im0.')
+          }
+
+          break;
+
+        case 'im1':
+          is(false, 'Shouldn\'t be hearing anything from second frame.');
+
+          break;
 
-    case 2:
-      is(from, 'input', 'Message sequence unexpected (2).');
-      is(value, '#0hello',
-         'Failed to get correct input from the first iframe.');
+        case 'input':
+          if (gFrameMsgCounts.input === 1) {
+            is(value, '#0hello',
+              'Failed to get correct input from the first iframe.');
+          } else {
+            ok(false, 'Unexpected multiple messages from input.')
+          }
+
+          break;
+      }
+
+      if (gFrameMsgCounts.input !== 1 ||
+          gFrameMsgCounts.im0 !== 1 ||
+          gFrameMsgCounts.im1 !== 0) {
+        return;
+      }
+
+      gCount++;
 
       let req0 = gFrames[0].setInputMethodActive(false);
       req0.onsuccess = function() {
         ok(true, 'setInputMethodActive succeeded (0).');
       };
       req0.onerror = function() {
         ok(false, 'setInputMethodActive failed (0): ' + this.error.name);
       };
       let req1 = gFrames[1].setInputMethodActive(true);
       req1.onsuccess = function() {
-       ok(true, 'setInputMethodActive succeeded (1).');
+        ok(true, 'setInputMethodActive succeeded (1).');
       };
       req1.onerror = function() {
-       ok(false, 'setInputMethodActive failed (1): ' + this.error.name);
+        ok(false, 'setInputMethodActive failed (1): ' + this.error.name);
       };
+
       break;
 
-    case 3:
-      is(from, 'im', 'Message sequence unexpected (3).');
-      is(value, '#0false', 'First frame should have the context removed.');
-      // Do nothing and wait for the second frame to get the context;
-      break;
+    case 1:
+      switch (fromId) {
+        case 'im0':
+          if (gFrameMsgCounts.im0 === 2) {
+            is(value, '#0false', 'First frame should have the context removed.');
+          } else {
+            ok(false, 'Unexpected multiple messages from im0.')
+          }
+          break;
+
+        case 'im1':
+          if (gFrameMsgCounts.im1 === 1) {
+            is(value, '#1true', 'Second frame should get the context.');
+          } else {
+            ok(false, 'Unexpected multiple messages from im0.')
+          }
 
-    case 4:
-      is(from, 'im', 'Message sequence unexpected (4).');
-      is(value, '#1true', 'Second frame should get the context.');
-      // Do nothing and wait for the input to show up in input frame.
-      break;
+          break;
 
-    case 5:
-      is(from, 'input', 'Message sequence unexpected (5).');
-      is(value, '#0#1hello',
-         'Failed to get correct input from the second iframe.');
+        case 'input':
+          if (gFrameMsgCounts.input === 2) {
+            is(value, '#0#1hello',
+               'Failed to get correct input from the second iframe.');
+          } else {
+            ok(false, 'Unexpected multiple messages from input.')
+          }
+          break;
+      }
+
+      if (gFrameMsgCounts.input !== 2 ||
+          gFrameMsgCounts.im0 !== 2 ||
+          gFrameMsgCounts.im1 !== 1) {
+        return;
+      }
+
+      gCount++;
 
       // Receive the second input from the second iframe.
       // Deactive the second iframe.
       let req3 = gFrames[1].setInputMethodActive(false);
       req3.onsuccess = function() {
-        ok(true, 'setInputMethodActive(false) succeeded (3).');
+        ok(true, 'setInputMethodActive(false) succeeded (2).');
       };
       req3.onerror = function() {
-        ok(false, 'setInputMethodActive(false) failed (3): ' + this.error.name);
+        ok(false, 'setInputMethodActive(false) failed (2): ' + this.error.name);
       };
       break;
 
-    case 6:
-      is(from, 'im', 'Message sequence unexpected (6).');
+    case 2:
+      is(fromId, 'im1', 'Message sequence unexpected (3).');
       is(value, '#1false', 'Second frame should have the context removed.');
 
       tearDown();
       break;
   }
 }
 
 setup();
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -366,23 +366,23 @@ UpgradeSchemaFrom4To5(mozIStorageConnect
     "INSERT INTO database (name, version, dataVersion) "
     "VALUES (:name, :version, :dataVersion)"
   ), getter_AddRefs(stmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   {
     mozStorageStatementScoper scoper(stmt);
 
-    rv = stmt->BindStringParameter(0, name);
+    rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), name);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = stmt->BindInt32Parameter(1, intVersion);
+    rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("version"), intVersion);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = stmt->BindInt64Parameter(2, dataVersion);
+    rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"), dataVersion);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = aConnection->SetSchemaVersion(5);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -3194,22 +3194,26 @@ PluginInstanceChild::PaintRectToSurface(
     }
     if (mHelperSurface) {
         // On X11 we can paint to non Xlib surface only with HelperSurface
         renderSurface = mHelperSurface;
     }
 #endif
 
     if (mIsTransparent && !CanPaintOnBackground()) {
-        // Clear surface content for transparent rendering
-        nsRefPtr<gfxContext> ctx = new gfxContext(renderSurface);
-        ctx->SetDeviceColor(aColor);
-        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-        ctx->Rectangle(GfxFromNsRect(plPaintRect));
-        ctx->Fill();
+        RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(renderSurface);
+        gfx::Rect rect(plPaintRect.x, plPaintRect.y,
+                       plPaintRect.width, plPaintRect.height);
+        // Moz2D treats OP_SOURCE operations as unbounded, so we need to
+        // clip to the rect that we want to fill:
+        dt->PushClipRect(rect);
+        dt->FillRect(rect, ColorPattern(ToColor(aColor)),
+                     DrawOptions(1.f, CompositionOp::OP_SOURCE));
+        dt->PopClip();
+        dt->Flush();
     }
 
     PaintRectToPlatformSurface(plPaintRect, renderSurface);
 
     if (renderSurface != aSurface) {
         // Copy helper surface content to target
         RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(aSurface);
         RefPtr<SourceSurface> surface =
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -506,16 +506,17 @@ protected:
     GLuint mName;
     RefPtr<DataSourceSurface> mImage;
 };
 
 class DebugGLColorData : public DebugGLData {
 public:
     DebugGLColorData(void* layerRef, const gfxRGBA& color, int width, int height)
         : DebugGLData(DebugGLData::ColorData),
+          mLayerRef(layerRef),
           mColor(color.Packed()),
           mSize(width, height)
     { }
 
     void *GetLayerRef() const { return mLayerRef; }
     uint32_t GetColor() const { return mColor; }
     const nsIntSize& GetSize() const { return mSize; }
 
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -114,17 +114,17 @@ BasicThebesLayer::PaintThebes(gfxContext
   gfxRect clipExtents;
   clipExtents = aContext->GetClipExtents();
 
   // Pull out the mask surface and transform here, because the mask
   // is internal to basic layers
   AutoMoz2DMaskData mask;
   SourceSurface* maskSurface = nullptr;
   Matrix maskTransform;
-  if (GetMaskData(aMaskLayer, Point(), &mask)) {
+  if (GetMaskData(aMaskLayer, aContext->GetDeviceOffset(), &mask)) {
     maskSurface = mask.GetSurface();
     maskTransform = mask.GetTransform();
   }
 
   if (!IsHidden() && !clipExtents.IsEmpty()) {
     mContentClient->DrawTo(this, aContext->GetDrawTarget(), opacity,
                            effectiveOperator,
                            maskSurface, &maskTransform);
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -121,72 +121,69 @@ gfxUserFontSet::~gfxUserFontSet()
 
 gfxFontEntry*
 gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
                             const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                             uint32_t aWeight,
                             int32_t aStretch,
                             uint32_t aItalicStyle,
                             const nsTArray<gfxFontFeature>& aFeatureSettings,
-                            const nsString& aLanguageOverride,
+                            uint32_t aLanguageOverride,
                             gfxSparseBitSet *aUnicodeRanges)
 {
+    MOZ_ASSERT(aWeight != 0,
+               "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
+
     nsAutoString key(aFamilyName);
     ToLowerCase(key);
 
     bool found;
 
-    if (aWeight == 0)
-        aWeight = NS_FONT_WEIGHT_NORMAL;
-
     // stretch, italic/oblique ==> zero implies normal
 
     gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
     if (!family) {
         family = new gfxMixedFontFamily(aFamilyName);
         mFontFamilies.Put(key, family);
     }
 
-    uint32_t languageOverride =
-        gfxFontStyle::ParseFontLanguageOverride(aLanguageOverride);
-
     // If there's already a proxy in the family whose descriptors all match,
     // we can just move it to the end of the list instead of adding a new
     // face that will always "shadow" the old one.
     // Note that we can't do this for "real" (non-proxy) entries, even if the
     // style descriptors match, as they might have had a different source list,
     // but we no longer have the old source list available to check.
     nsTArray<nsRefPtr<gfxFontEntry> >& fontList = family->GetFontList();
     for (uint32_t i = 0, count = fontList.Length(); i < count; i++) {
         if (!fontList[i]->mIsProxy) {
             continue;
         }
 
         gfxProxyFontEntry *existingProxyEntry =
             static_cast<gfxProxyFontEntry*>(fontList[i].get());
         if (!existingProxyEntry->Matches(aFontFaceSrcList,
                                          aWeight, aStretch, aItalicStyle,
-                                         aFeatureSettings, languageOverride,
+                                         aFeatureSettings, aLanguageOverride,
                                          aUnicodeRanges)) {
             continue;
         }
 
         // We've found an entry that matches the new face exactly, so just add
         // it to the end of the list. gfxMixedFontFamily::AddFontEntry() will
         // automatically remove any earlier occurrence of the same proxy.
         family->AddFontEntry(existingProxyEntry);
         return existingProxyEntry;
     }
 
     // construct a new face and add it into the family
     gfxProxyFontEntry *proxyEntry =
         new gfxProxyFontEntry(aFontFaceSrcList, aWeight, aStretch,
                               aItalicStyle,
                               aFeatureSettings,
-                              languageOverride,
+                              aLanguageOverride,
                               aUnicodeRanges);
     family->AddFontEntry(proxyEntry);
 #ifdef PR_LOGGING
     if (LOG_ENABLED()) {
         LOG(("userfonts (%p) added (%s) with style: %s weight: %d stretch: %d",
              this, NS_ConvertUTF16toUTF8(aFamilyName).get(),
              (aItalicStyle & NS_FONT_STYLE_ITALIC ? "italic" :
                  (aItalicStyle & NS_FONT_STYLE_OBLIQUE ? "oblique" : "normal")),
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -162,27 +162,28 @@ public:
         STATUS_LOADED,
         STATUS_FORMAT_NOT_SUPPORTED,
         STATUS_ERROR,
         STATUS_END_OF_LIST
     };
 
 
     // add in a font face
-    // weight - 0 == unknown, [100, 900] otherwise (multiples of 100)
+    // weight - [100, 900] (multiples of 100)
     // stretch = [NS_FONT_STRETCH_ULTRA_CONDENSED, NS_FONT_STRETCH_ULTRA_EXPANDED]
     // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
+    // language override = result of calling gfxFontStyle::ParseFontLanguageOverride
     // TODO: support for unicode ranges not yet implemented
     gfxFontEntry *AddFontFace(const nsAString& aFamilyName,
                               const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                               uint32_t aWeight,
                               int32_t aStretch,
                               uint32_t aItalicStyle,
                               const nsTArray<gfxFontFeature>& aFeatureSettings,
-                              const nsString& aLanguageOverride,
+                              uint32_t aLanguageOverride,
                               gfxSparseBitSet *aUnicodeRanges = nullptr);
 
     // add in a font face for which we have the gfxFontEntry already
     void AddFontFace(const nsAString& aFamilyName, gfxFontEntry* aFontEntry);
 
     // Whether there is a face with this family name
     bool HasFamily(const nsAString& aFamilyName) const
     {
--- a/layout/base/nsBidi.cpp
+++ b/layout/base/nsBidi.cpp
@@ -1447,30 +1447,29 @@ nsresult nsBidi::GetVisualRun(int32_t aR
  */
 bool nsBidi::GetRuns()
 {
   if(mDirection!=NSBIDI_MIXED) {
     /* simple, single-run case - this covers length==0 */
     GetSingleRun(mParaLevel);
   } else /* NSBIDI_MIXED, length>0 */ {
     /* mixed directionality */
-    int32_t length=mLength, limit=length;
+    int32_t length=mLength, limit=mTrailingWSStart;
 
     /*
      * If there are WS characters at the end of the line
      * and the run preceding them has a level different from
      * paraLevel, then they will form their own run at paraLevel (L1).
      * Count them separately.
      * We need some special treatment for this in order to not
      * modify the levels array which a line nsBidi object shares
      * with its paragraph parent and its other line siblings.
      * In other words, for the trailing WS, it may be
      * levels[]!=paraLevel but we have to treat it like it were so.
      */
-    limit=mTrailingWSStart;
     if(limit==0) {
       /* there is only WS on this line */
       GetSingleRun(mParaLevel);
     } else {
       nsBidiLevel *levels=mLevels;
       int32_t i, runCount;
       nsBidiLevel level=NSBIDI_DEFAULT_LTR;   /* initialize with no valid level */
 
deleted file mode 100644
--- a/layout/reftests/font-inflation/disable-fontinfl-on-mobile-4.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
-Without the patch for bug 706198, this website should not show up as inflated. That means
-that with a 450px container, the minimum font size with 15em per line should be 30px.
-So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
-
-With the patch, the text should be uninflated, which means that 12px should still be
-12px.
--->
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta name="viewport" content="width=320"/>
-    <style>
-      p { font-size: 12px; line-height: 1.0;}
-    </style>
-    <body>
-      <p>Some uninflated text.</p>
-    </body>
-  </head>
-</html>
--- a/layout/reftests/font-inflation/reftest.list
+++ b/layout/reftests/font-inflation/reftest.list
@@ -50,17 +50,16 @@ test-pref(font.size.inflation.emPerLine,
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-2.html select-combobox-2-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != select-combobox-2.html select-combobox-2.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-3.html select-combobox-3-ref.html
 asserts-if(gtk2Widget,0-4) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != input-checkbox.html input-checkbox.html
 asserts-if(gtk2Widget,0-4) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != input-radio.html input-radio.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == disable-fontinfl-on-mobile.html disable-fontinfl-on-mobile-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == disable-fontinfl-on-mobile-2.html disable-fontinfl-on-mobile-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == disable-fontinfl-on-mobile-3.html disable-fontinfl-on-mobile-ref.html
-test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == disable-fontinfl-on-mobile-4.html disable-fontinfl-on-mobile-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != disable-fontinfl-on-mobile-5.html disable-fontinfl-on-mobile-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == preformatted-text.html preformatted-text-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == fixed-height-body.html fixed-height-body-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == fixed-height-body-child.html fixed-height-body-child-ref.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == consecutive-inline.html consecutive-inline-ref.html
 
 # The tests below use nonzero values of the lineThreshold preference.
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,100) == text-1.html text-1.html
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -566,23 +566,26 @@ nsUserFontSet::InsertRule(nsCSSFontFaceR
     }
   }
 
   // this is a new rule:
 
   uint32_t weight = NS_STYLE_FONT_WEIGHT_NORMAL;
   int32_t stretch = NS_STYLE_FONT_STRETCH_NORMAL;
   uint32_t italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
-  nsString languageOverride;
+  uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
 
   // set up weight
   aRule->GetDesc(eCSSFontDesc_Weight, val);
   unit = val.GetUnit();
   if (unit == eCSSUnit_Integer || unit == eCSSUnit_Enumerated) {
     weight = val.GetIntValue();
+    if (weight == 0) {
+      weight = NS_STYLE_FONT_STYLE_NORMAL;
+    }
   } else if (unit == eCSSUnit_Normal) {
     weight = NS_STYLE_FONT_WEIGHT_NORMAL;
   } else {
     NS_ASSERTION(unit == eCSSUnit_Null,
                  "@font-face weight has unexpected unit");
   }
 
   // set up stretch
@@ -623,17 +626,19 @@ nsUserFontSet::InsertRule(nsCSSFontFaceR
   }
 
   // set up font language override
   aRule->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
   unit = val.GetUnit();
   if (unit == eCSSUnit_Normal) {
     // empty feature string
   } else if (unit == eCSSUnit_String) {
-    val.GetStringValue(languageOverride);
+    nsString stringValue;
+    val.GetStringValue(stringValue);
+    languageOverride = gfxFontStyle::ParseFontLanguageOverride(stringValue);
   } else {
     NS_ASSERTION(unit == eCSSUnit_Null,
                  "@font-face font-language-override has unexpected unit");
   }
 
   // set up src array
   nsTArray<gfxFontFaceSrc> srcArray;
 
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
@@ -118,17 +118,22 @@ WebrtcGmpVideoEncoder::InitEncode(const 
 int32_t
 WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
                                     int32_t aNumberOfCores,
                                     uint32_t aMaxPayloadSize)
 {
   GMPVideoHost* host = nullptr;
   GMPVideoEncoder* gmp = nullptr;
 
-  nsresult rv = mMPS->GetGMPVideoEncoderVP8(&host, &gmp);
+  nsTArray<nsCString> tags;
+  tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
+  nsresult rv = mMPS->GetGMPVideoEncoder(&tags,
+                                         NS_LITERAL_STRING(""),
+                                         &host,
+                                         &gmp);
   if (NS_FAILED(rv)) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   mGMP = gmp;
   mHost = host;
 
   if (!gmp || !host) {
@@ -453,18 +458,22 @@ WebrtcGmpVideoDecoder::InitDecode(const 
 
 int32_t
 WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
                                     int32_t aNumberOfCores)
 {
   GMPVideoHost* host = nullptr;
   GMPVideoDecoder* gmp = nullptr;
 
-  if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoderVP8(&host, &gmp))))
-  {
+  nsTArray<nsCString> tags;
+  tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
+  if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoder(&tags,
+                                                    NS_LITERAL_STRING(""),
+                                                    &host,
+                                                    &gmp)))) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   mGMP = gmp;
   mHost = host;
   if (!gmp || !host) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -39,18 +39,18 @@
 <!ENTITY bookmark "Bookmark">
 <!ENTITY bookmark_added "Bookmark added">
 <!ENTITY bookmark_removed "Bookmark removed">
 <!ENTITY bookmark_updated "Bookmark updated">
 <!ENTITY bookmark_options "Options">
 
 <!ENTITY history_today_section "Today">
 <!ENTITY history_yesterday_section "Yesterday">
-<!ENTITY history_week_section "7 days ago">
-<!ENTITY history_older_section "Older than 7 days">
+<!ENTITY history_week_section2 "Last Week">
+<!ENTITY history_older_section2 "Last Month">
 
 <!ENTITY go "Go">
 <!ENTITY search "Search">
 <!ENTITY reload "Reload">
 <!ENTITY forward "Forward">
 <!ENTITY menu "Menu">
 <!ENTITY back "Back">
 <!ENTITY stop "Stop">
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -69,18 +69,18 @@
   <string name="bookmark">&bookmark;</string>
   <string name="bookmark_added">&bookmark_added;</string>
   <string name="bookmark_removed">&bookmark_removed;</string>
   <string name="bookmark_updated">&bookmark_updated;</string>
   <string name="bookmark_options">&bookmark_options;</string>
 
   <string name="history_today_section">&history_today_section;</string>
   <string name="history_yesterday_section">&history_yesterday_section;</string>
-  <string name="history_week_section">&history_week_section;</string>
-  <string name="history_older_section">&history_older_section;</string>
+  <string name="history_week_section">&history_week_section2;</string>
+  <string name="history_older_section">&history_older_section2;</string>
 
   <string name="share">&share;</string>
   <string name="share_title">&share_title;</string>
   <string name="share_image_failed">&share_image_failed;</string>
   <string name="save_as_pdf">&save_as_pdf;</string>
   <string name="find_in_page">&find_in_page;</string>
   <string name="desktop_mode">&desktop_mode;</string>
   <string name="page">&page;</string>
--- a/mobile/android/chrome/content/aboutDownloads.js
+++ b/mobile/android/chrome/content/aboutDownloads.js
@@ -413,21 +413,21 @@ let Downloads = {
     }
   },
 
   getDownloads: function dl_getDownloads(aParams) {
     aParams = aParams || {};
     let stmt = this._initStatement(aParams.isPrivate);
 
     stmt.reset();
-    stmt.bindInt32Parameter(0, Ci.nsIDownloadManager.DOWNLOAD_NOTSTARTED);
-    stmt.bindInt32Parameter(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
-    stmt.bindInt32Parameter(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
-    stmt.bindInt32Parameter(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
-    stmt.bindInt32Parameter(4, Ci.nsIDownloadManager.DOWNLOAD_SCANNING);
+    stmt.bindByIndex(0, Ci.nsIDownloadManager.DOWNLOAD_NOTSTARTED);
+    stmt.bindByIndex(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
+    stmt.bindByIndex(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
+    stmt.bindByIndex(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
+    stmt.bindByIndex(4, Ci.nsIDownloadManager.DOWNLOAD_SCANNING);
 
     let entries = [];
     while (entry = this._getEntry(stmt)) {
       entries.push(entry);
     }
 
     stmt.finalize();
 
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -7037,17 +7037,17 @@ var SearchEngines = {
     if (!Services.prompt.prompt(null, promptTitle, null, title, null, {}))
       return;
 
     // fetch the favicon for this page
     let dbFile = FileUtils.getFile("ProfD", ["browser.db"]);
     let mDBConn = Services.storage.openDatabase(dbFile);
     let stmts = [];
     stmts[0] = mDBConn.createStatement("SELECT favicon FROM history_with_favicons WHERE url = ?");
-    stmts[0].bindStringParameter(0, docURI.spec);
+    stmts[0].bindByIndex(0, docURI.spec);
     let favicon = null;
     Services.search.init(function addEngine_cb(rv) {
       if (!Components.isSuccessCode(rv)) {
         Cu.reportError("Could not initialize search service, bailing out.");
         return;
       }
       mDBConn.executeAsync(stmts, stmts.length, {
         handleResult: function (results) {
--- a/mobile/android/modules/Sanitizer.jsm
+++ b/mobile/android/modules/Sanitizer.jsm
@@ -22,22 +22,22 @@ this.EXPORTED_SYMBOLS = ["Sanitizer"];
 let downloads = {
   dlmgr: Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager),
 
   iterate: function (aCallback) {
     let dlmgr = downloads.dlmgr;
     let dbConn = dlmgr.DBConnection;
     let stmt = dbConn.createStatement("SELECT id FROM moz_downloads WHERE " +
         "state = ? OR state = ? OR state = ? OR state = ? OR state = ? OR state = ?");
-    stmt.bindInt32Parameter(0, Ci.nsIDownloadManager.DOWNLOAD_FINISHED);
-    stmt.bindInt32Parameter(1, Ci.nsIDownloadManager.DOWNLOAD_FAILED);
-    stmt.bindInt32Parameter(2, Ci.nsIDownloadManager.DOWNLOAD_CANCELED);
-    stmt.bindInt32Parameter(3, Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL);
-    stmt.bindInt32Parameter(4, Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_POLICY);
-    stmt.bindInt32Parameter(5, Ci.nsIDownloadManager.DOWNLOAD_DIRTY);
+    stmt.bindByIndex(0, Ci.nsIDownloadManager.DOWNLOAD_FINISHED);
+    stmt.bindByIndex(1, Ci.nsIDownloadManager.DOWNLOAD_FAILED);
+    stmt.bindByIndex(2, Ci.nsIDownloadManager.DOWNLOAD_CANCELED);
+    stmt.bindByIndex(3, Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL);
+    stmt.bindByIndex(4, Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_POLICY);
+    stmt.bindByIndex(5, Ci.nsIDownloadManager.DOWNLOAD_DIRTY);
     while (stmt.executeStep()) {
       aCallback(dlmgr.getDownload(stmt.row.id));
     }
     stmt.finalize();
   },
 
   get canClear() {
     return this.dlmgr.canCleanUp;
--- a/security/build/nss.def
+++ b/security/build/nss.def
@@ -184,16 +184,17 @@ NSS_CMSDecoder_Update
 NSS_CMSEncoder_Cancel
 NSS_CMSEncoder_Finish
 NSS_CMSEncoder_Start
 NSS_CMSEncoder_Update
 NSS_CMSEnvelopedData_AddRecipient
 NSS_CMSEnvelopedData_Create
 NSS_CMSEnvelopedData_GetContentInfo
 NSS_CMSMessage_ContentLevel
+NSS_CMSMessage_ContentLevelCount
 NSS_CMSMessage_Create
 NSS_CMSMessage_CreateFromDER
 NSS_CMSMessage_Destroy
 NSS_CMSMessage_GetContent
 NSS_CMSMessage_GetContentInfo
 NSS_CMSMessage_IsEncrypted
 NSS_CMSMessage_IsSigned
 NSS_CMSRecipientInfo_Create
--- a/toolkit/devtools/server/actors/call-watcher.js
+++ b/toolkit/devtools/server/actors/call-watcher.js
@@ -192,37 +192,42 @@ let FunctionCallActor = protocol.ActorCl
   /**
    * Serializes the arguments so that they can be easily be transferred
    * as a string, but still be useful when displayed in a potential UI.
    *
    * @return string
    *         The arguments as a string.
    */
   _generateArgsPreview: function() {
-    let { caller, args } = this.details;
+    let { caller, args, name } = this.details;
     let { global } = this.meta;
 
+    // Get method signature to determine if there are any enums
+    // used in this method.
+    let enumArgs = (CallWatcherFront.ENUM_METHODS[global] || {})[name];
+    if (typeof enumArgs === "function") {
+      enumArgs = enumArgs(args);
+    }
+
     // XXX: All of this sucks. Make this smarter, so that the frontend
     // can inspect each argument, be it object or primitive. Bug 978960.
-    let serializeArgs = () => args.map(arg => {
+    let serializeArgs = () => args.map((arg, i) => {
       if (typeof arg == "undefined") {
         return "undefined";
       }
       if (typeof arg == "function") {
         return "Function";
       }
       if (typeof arg == "object") {
         return "Object";
       }
-      if (global == CallWatcherFront.CANVAS_WEBGL_CONTEXT) {
-        // XXX: This doesn't handle combined bitmasks. Bug 978964.
-        return getEnumsLookupTable("webgl", caller)[arg] || arg;
-      }
-      if (global == CallWatcherFront.CANVAS_2D_CONTEXT) {
-        return getEnumsLookupTable("2d", caller)[arg] || arg;
+      // If this argument matches the method's signature
+      // and is an enum, change it to its constant name.
+      if (enumArgs && enumArgs.indexOf(i) !== -1) {
+        return getEnumsLookupTable(global, caller)[arg] || arg;
       }
       return arg;
     });
 
     return serializeArgs().join(", ");
   }
 });
 
@@ -553,16 +558,78 @@ CallWatcherFront.METHOD_FUNCTION = 0;
 CallWatcherFront.GETTER_FUNCTION = 1;
 CallWatcherFront.SETTER_FUNCTION = 2;
 
 CallWatcherFront.GLOBAL_SCOPE = 0;
 CallWatcherFront.UNKNOWN_SCOPE = 1;
 CallWatcherFront.CANVAS_WEBGL_CONTEXT = 2;
 CallWatcherFront.CANVAS_2D_CONTEXT = 3;
 
+CallWatcherFront.ENUM_METHODS = {};
+CallWatcherFront.ENUM_METHODS[CallWatcherFront.CANVAS_2D_CONTEXT] = {
+  asyncDrawXULElement: [6],
+  drawWindow: [6]
+};
+
+CallWatcherFront.ENUM_METHODS[CallWatcherFront.CANVAS_WEBGL_CONTEXT] = {
+  activeTexture: [0],
+  bindBuffer: [0],
+  bindFramebuffer: [0],
+  bindRenderbuffer: [0],
+  bindTexture: [0],
+  blendEquation: [0],
+  blendEquationSeparate: [0, 1],
+  blendFunc: [0, 1],
+  blendFuncSeparate: [0, 1, 2, 3],
+  bufferData: [0, 1, 2],
+  bufferSubData: [0, 1],
+  checkFramebufferStatus: [0],
+  clear: [0],
+  compressedTexImage2D: [0, 2],
+  compressedTexSubImage2D: [0, 6],
+  copyTexImage2D: [0, 2],
+  copyTexSubImage2D: [0],
+  createShader: [0],
+  cullFace: [0],
+  depthFunc: [0],
+  disable: [0],
+  drawArrays: [0],
+  drawElements: [0, 2],
+  enable: [0],
+  framebufferRenderbuffer: [0, 1, 2],
+  framebufferTexture2D: [0, 1, 2],
+  frontFace: [0],
+  generateMipmap: [0],
+  getBufferParameter: [0, 1],
+  getParameter: [0],
+  getFramebufferAttachmentParameter: [0, 1, 2],
+  getProgramParameter: [1],
+  getRenderbufferParameter: [0, 1],
+  getShaderParameter: [1],
+  getShaderPrecisionFormat: [0, 1],
+  getTexParameter: [0, 1],
+  getVertexAttrib: [1],
+  getVertexAttribOffset: [1],
+  hint: [0, 1],
+  isEnabled: [0],
+  pixelStorei: [0],
+  readPixels: [4, 5],
+  renderbufferStorage: [0, 1],
+  stencilFunc: [0],
+  stencilFuncSeparate: [0, 1],
+  stencilMaskSeparate: [0],
+  stencilOp: [0, 1, 2],
+  stencilOpSeparate: [0, 1, 2, 3],
+  texImage2D: (args) => args.length > 6 ? [0, 2, 6, 7] : [0, 2, 3, 4],
+  texParameterf: [0, 1],
+  texParameteri: [0, 1],
+  texSubImage2D: (args) => args.length === 9 ? [0, 6, 7] : [0, 4, 5],
+  vertexAttribPointer: [2]
+};
+
 /**
  * A lookup table for cross-referencing flags or properties with their name
  * assuming they look LIKE_THIS most of the time.
  *
  * For example, when gl.clear(gl.COLOR_BUFFER_BIT) is called, the actual passed
  * argument's value is 16384, which we want identified as "COLOR_BUFFER_BIT".
  */
 var gEnumRegex = /^[A-Z_]+$/;
--- a/toolkit/mozapps/downloads/tests/chrome/test_bug_412360.xul
+++ b/toolkit/mozapps/downloads/tests/chrome/test_bug_412360.xul
@@ -81,30 +81,30 @@ function test()
   db.executeSimpleSQL("DELETE FROM moz_downloads");
 
   let stmt = db.createStatement(
     "INSERT INTO moz_downloads (source, target, state, endTime) " +
     "VALUES (?1, ?2, ?3, ?4)");
 
   try {
     // Saving javascript URIs doesn't work
-    stmt.bindStringParameter(0, "javascript:5");
+    stmt.bindByIndex(0, "javascript:5");
 
     // Download to a temp local file
     file = Cc["@mozilla.org/file/directory_service;1"].
            getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
     file.append("javascriptURI");
     file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
-    stmt.bindStringParameter(1, Cc["@mozilla.org/network/io-service;1"].
+    stmt.bindByIndex(1, Cc["@mozilla.org/network/io-service;1"].
       getService(Ci.nsIIOService).newFileURI(file).spec);
 
     // Start it as canceled
-    stmt.bindInt32Parameter(2, dm.DOWNLOAD_CANCELED);
+    stmt.bindByIndex(2, dm.DOWNLOAD_CANCELED);
 
-    stmt.bindInt32Parameter(3, Date.now() * 1000);
+    stmt.bindByIndex(3, Date.now() * 1000);
 
     // Add it!
     stmt.execute();
   }
   finally {
     stmt.finalize();
   }
 
--- a/toolkit/mozapps/downloads/tests/chrome/test_cleanup_search.xul
+++ b/toolkit/mozapps/downloads/tests/chrome/test_cleanup_search.xul
@@ -45,20 +45,20 @@ function test()
                  getService(Ci.nsIIOService).newFileURI(file).spec;
 
   let stmt = db.createStatement(
     "INSERT INTO moz_downloads (name, target, source, state) " +
     "VALUES (?1, ?2, ?3, ?4)");
 
   try {
     for each (let site in ["delete.me", "i.live"]) {
-      stmt.bindStringParameter(0, "Super Pimped Download");
-      stmt.bindStringParameter(1, filePath);
-      stmt.bindStringParameter(2, "http://" + site + "/file");
-      stmt.bindInt32Parameter(3, dm.DOWNLOAD_FINISHED);
+      stmt.bindByIndex(0, "Super Pimped Download");
+      stmt.bindByIndex(1, filePath);
+      stmt.bindByIndex(2, "http://" + site + "/file");
+      stmt.bindByIndex(3, dm.DOWNLOAD_FINISHED);
 
       // Add it!
       stmt.execute();
     }
   }
   finally {
     stmt.reset();
     stmt.finalize();
--- a/toolkit/mozapps/downloads/tests/chrome/test_multi_select.xul
+++ b/toolkit/mozapps/downloads/tests/chrome/test_multi_select.xul
@@ -44,20 +44,20 @@ function test()
   try {
     for each (let site in ["ed.agadak.net", "mozilla.org", "mozilla.com", "mozilla.net"]) {
       let file = Cc["@mozilla.org/file/directory_service;1"].
         getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
       file.append(site);
       let fileSpec = Cc["@mozilla.org/network/io-service;1"].
         getService(Ci.nsIIOService).newFileURI(file).spec;
 
-      stmt.bindStringParameter(0, "http://" + site + "/file");
-      stmt.bindInt32Parameter(1, dm.DOWNLOAD_FINISHED);
-      stmt.bindStringParameter(2, fileSpec);
-      stmt.bindStringParameter(3, "http://referrer/");
+      stmt.bindByIndex(0, "http://" + site + "/file");
+      stmt.bindByIndex(1, dm.DOWNLOAD_FINISHED);
+      stmt.bindByIndex(2, fileSpec);
+      stmt.bindByIndex(3, "http://referrer/");
 
       // Add it!
       stmt.execute();
     }
   }
   finally {
     stmt.reset();
     stmt.finalize();
--- a/toolkit/mozapps/downloads/tests/chrome/test_multiword_search.xul
+++ b/toolkit/mozapps/downloads/tests/chrome/test_multiword_search.xul
@@ -43,22 +43,22 @@ function test()
                  getService(Ci.nsIIOService).newFileURI(file).spec;
 
   let stmt = db.createStatement(
     "INSERT INTO moz_downloads (name, target, source, state, endTime, maxBytes) " +
     "VALUES (?1, ?2, ?3, ?4, ?5, ?6)");
 
   try {
     for each (let site in ["ed.agadak.net", "mozilla.org"]) {
-      stmt.bindStringParameter(0, "Super Pimped Download");
-      stmt.bindStringParameter(1, filePath);
-      stmt.bindStringParameter(2, "http://" + site + "/file");
-      stmt.bindInt32Parameter(3, dm.DOWNLOAD_FINISHED);
-      stmt.bindInt64Parameter(4, new Date(1985, 7, 2) * 1000);
-      stmt.bindInt64Parameter(5, 111222333444);
+      stmt.bindByIndex(0, "Super Pimped Download");
+      stmt.bindByIndex(1, filePath);
+      stmt.bindByIndex(2, "http://" + site + "/file");
+      stmt.bindByIndex(3, dm.DOWNLOAD_FINISHED);
+      stmt.bindByIndex(4, new Date(1985, 7, 2) * 1000);
+      stmt.bindByIndex(5, 111222333444);
 
       // Add it!
       stmt.execute();
     }
   } finally {
     stmt.reset();
     stmt.finalize();
   }
--- a/toolkit/mozapps/downloads/tests/chrome/test_search_clearlist.xul
+++ b/toolkit/mozapps/downloads/tests/chrome/test_search_clearlist.xul
@@ -51,21 +51,21 @@ function test()
     sites.push("i-hate.clear-list-" + i);
 
   // Add one download that matches the search
   let searchTerm = "one-download.match-search";
   sites.push(searchTerm);
 
   try {
     for each (let site in sites) {
-      stmt.bindStringParameter(0, filePath);
-      stmt.bindStringParameter(1, "http://" + site + "/file");
-      stmt.bindInt32Parameter(2, dm.DOWNLOAD_FINISHED);
+      stmt.bindByIndex(0, filePath);
+      stmt.bindByIndex(1, "http://" + site + "/file");
+      stmt.bindByIndex(2, dm.DOWNLOAD_FINISHED);
       // Make the one that matches slightly older so it appears last
-      stmt.bindInt64Parameter(3, 1112223334445556 - (site == searchTerm));
+      stmt.bindByIndex(3, 1112223334445556 - (site == searchTerm));
 
       // Add it!
       stmt.execute();
     }
   }
   finally {
     stmt.reset();
     stmt.finalize();
--- a/toolkit/mozapps/downloads/tests/chrome/test_select_all.xul
+++ b/toolkit/mozapps/downloads/tests/chrome/test_select_all.xul
@@ -45,19 +45,19 @@ function test()
 
   let stmt = db.createStatement(
     "INSERT INTO moz_downloads (target, source, state) " +
     "VALUES (?1, ?2, ?3)");
 
   let sites = ["mozilla.org", "mozilla.com", "select.all"];
   try {
     for each (let site in sites) {
-      stmt.bindStringParameter(0, filePath);
-      stmt.bindStringParameter(1, "http://" + site + "/file");
-      stmt.bindInt32Parameter(2, dm.DOWNLOAD_FINISHED);
+      stmt.bindByIndex(0, filePath);
+      stmt.bindByIndex(1, "http://" + site + "/file");
+      stmt.bindByIndex(2, dm.DOWNLOAD_FINISHED);
 
       // Add it!
       stmt.execute();
     }
   }
   finally {
     stmt.reset();
     stmt.finalize();