Merge inbound to m-c on a CLOSED TREE. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 10 Jul 2014 18:22:38 -0400
changeset 215338 e1a037c085d13e5ac044e5385a23f701460ed27f
parent 215279 0a0348d3f0c85f54565fe4f701bbc5366d9631d6 (current diff)
parent 215337 28cffea656488425f68f68c281d338827fe3a8bc (diff)
child 215339 d153db92b3ccfe613ec0a13d98443a6668b6a4b5
child 215405 0729de0a4a0214a8a0e9142e9fb4ef590663c29a
child 215420 24b61c6aad57f4786d1655124a90cc6212241f73
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone33.0a1
first release with
nightly linux32
e1a037c085d1 / 33.0a1 / 20140711030201 / files
nightly linux64
e1a037c085d1 / 33.0a1 / 20140711030201 / files
nightly mac
e1a037c085d1 / 33.0a1 / 20140711030201 / files
nightly win32
e1a037c085d1 / 33.0a1 / 20140711030201 / files
nightly win64
e1a037c085d1 / 33.0a1 / 20140711030201 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c on a CLOSED TREE. a=merge
content/base/src/nsGkAtomList.h
--- a/addon-sdk/source/lib/sdk/content/sandbox.js
+++ b/addon-sdk/source/lib/sdk/content/sandbox.js
@@ -131,17 +131,17 @@ const WorkerSandbox = Class({
       if (!waiveSecurityMembrane)
         principals = EXPANDED_PRINCIPALS.concat(window);
     }
 
     // Create the sandbox and bind it to window in order for content scripts to
     // have access to all standard globals (window, document, ...)
     let content = sandbox(principals, {
       sandboxPrototype: proto,
-      wantXrays: true,
+      wantXrays: !requiresAddonGlobal(worker),
       wantGlobalProperties: wantGlobalProperties,
       wantExportHelpers: true,
       sameZoneAs: window,
       metadata: {
         SDKContentScript: true,
         'inner-window-id': getInnerId(window)
       }
     });
--- a/addon-sdk/source/lib/sdk/deprecated/traits-worker.js
+++ b/addon-sdk/source/lib/sdk/deprecated/traits-worker.js
@@ -144,17 +144,17 @@ const WorkerSandbox = EventEmitter.compo
       delete proto.XMLHttpRequest;
       wantGlobalProperties.push("XMLHttpRequest");
     }
 
     // Create the sandbox and bind it to window in order for content scripts to
     // have access to all standard globals (window, document, ...)
     let content = this._sandbox = sandbox(principals, {
       sandboxPrototype: proto,
-      wantXrays: true,
+      wantXrays: !worker._injectInDocument,
       wantGlobalProperties: wantGlobalProperties,
       sameZoneAs: window,
       metadata: {
         SDKContentScript: true,
         'inner-window-id': getInnerId(window)
       }
     });
     // We have to ensure that window.top and window.parent are the exact same
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -277,17 +277,19 @@ skip-if = e10s # Bug ?????? - [JavaScrip
 [browser_contextSearchTabPosition.js]
 skip-if = os == "mac" # bug 967013, bug 926729
 [browser_ctrlTab.js]
 skip-if = e10s # Bug ????? - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.)
 [browser_customize_popupNotification.js]
 [browser_datareporting_notification.js]
 run-if = datareporting
 [browser_devices_get_user_media.js]
-skip-if = (os == "linux" && debug) || e10s # linux: bug 976544; e10s: Bug ?????? - appears user media notifications only happen in the child and don't make their way to the parent?
+skip-if = (os == "linux" && debug) || e10s # linux: bug 976544; e10s: Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent?
+[browser_devices_get_user_media_about_urls.js]
+skip-if = e10s # Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent?
 [browser_discovery.js]
 skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome
 [browser_duplicateIDs.js]
 [browser_drag.js]
 skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 [browser_findbarClose.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (tries to grab an iframe directly from content)
 [browser_fullscreen-window-open.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
@@ -0,0 +1,260 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kObservedTopics = [
+  "getUserMedia:response:allow",
+  "getUserMedia:revoke",
+  "getUserMedia:response:deny",
+  "getUserMedia:request",
+  "recording-device-events",
+  "recording-window-ended"
+];
+
+const PREF_PERMISSION_FAKE = "media.navigator.permission.fake";
+
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService",
+                                   "@mozilla.org/mediaManagerService;1",
+                                   "nsIMediaManagerService");
+
+var gTab;
+
+var gObservedTopics = {};
+function observer(aSubject, aTopic, aData) {
+  if (!(aTopic in gObservedTopics))
+    gObservedTopics[aTopic] = 1;
+  else
+    ++gObservedTopics[aTopic];
+}
+
+function promiseObserverCalled(aTopic, aAction) {
+  let deferred = Promise.defer();
+  info("Waiting for " + aTopic);
+
+  Services.obs.addObserver(function observer(aSubject, topic, aData) {
+    ok(true, "got " + aTopic + " notification");
+    info("Message: " + aData);
+    Services.obs.removeObserver(observer, aTopic);
+
+    if (kObservedTopics.indexOf(aTopic) != -1) {
+      if (!(aTopic in gObservedTopics))
+        gObservedTopics[aTopic] = -1;
+      else
+        --gObservedTopics[aTopic];
+    }
+
+    deferred.resolve();
+  }, aTopic, false);
+
+  if (aAction)
+    aAction();
+
+  return deferred.promise;
+}
+
+function promisePopupNotification(aName) {
+  let deferred = Promise.defer();
+
+  waitForCondition(() => PopupNotifications.getNotification(aName),
+                   () => {
+    ok(!!PopupNotifications.getNotification(aName),
+       aName + " notification appeared");
+
+    deferred.resolve();
+  }, "timeout waiting for popup notification " + aName);
+
+  return deferred.promise;
+}
+
+function promiseNoPopupNotification(aName) {
+  let deferred = Promise.defer();
+  info("Waiting for " + aName + " to be removed");
+
+  waitForCondition(() => !PopupNotifications.getNotification(aName),
+                   () => {
+    ok(!PopupNotifications.getNotification(aName),
+       aName + " notification removed");
+    deferred.resolve();
+  }, "timeout waiting for popup notification " + aName + " to disappear");
+
+  return deferred.promise;
+}
+
+function expectObserverCalled(aTopic) {
+  is(gObservedTopics[aTopic], 1, "expected notification " + aTopic);
+  if (aTopic in gObservedTopics)
+    --gObservedTopics[aTopic];
+}
+
+function expectNoObserverCalled() {
+  for (let topic in gObservedTopics) {
+    if (gObservedTopics[topic])
+      is(gObservedTopics[topic], 0, topic + " notification unexpected");
+  }
+  gObservedTopics = {};
+}
+
+function getMediaCaptureState() {
+  let hasVideo = {};
+  let hasAudio = {};
+  MediaManagerService.mediaCaptureWindowState(content, hasVideo, hasAudio);
+  if (hasVideo.value && hasAudio.value)
+    return "CameraAndMicrophone";
+  if (hasVideo.value)
+    return "Camera";
+  if (hasAudio.value)
+    return "Microphone";
+  return "none";
+}
+
+function closeStream(aAlreadyClosed) {
+  expectNoObserverCalled();
+
+  info("closing the stream");
+  content.wrappedJSObject.closeStream();
+
+  if (!aAlreadyClosed)
+    yield promiseObserverCalled("recording-device-events");
+
+  yield promiseNoPopupNotification("webRTC-sharingDevices");
+  if (!aAlreadyClosed)
+    expectObserverCalled("recording-window-ended");
+
+  let statusButton = document.getElementById("webrtc-status-button");
+  ok(statusButton.hidden, "WebRTC status button hidden");
+}
+
+function loadPage(aUrl) {
+  let deferred = Promise.defer();
+
+  gTab.linkedBrowser.addEventListener("load", function onload() {
+    gTab.linkedBrowser.removeEventListener("load", onload, true);
+
+    is(PopupNotifications._currentNotifications.length, 0,
+       "should start the test without any prior popup notification");
+
+    deferred.resolve();
+  }, true);
+  content.location = aUrl;
+  return deferred.promise;
+}
+
+// A fake about module to map get_user_media.html to different about urls.
+function fakeLoopAboutModule() {
+}
+
+fakeLoopAboutModule.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+  newChannel: function (aURI) {
+    let rootDir = getRootDirectory(gTestPath);
+    let chan = Services.io.newChannel(rootDir + "get_user_media.html", null, null);
+    chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
+    return chan;
+  },
+  getURIFlags: function (aURI) {
+    return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+           Ci.nsIAboutModule.ALLOW_SCRIPT |
+           Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
+  }
+};
+
+let factory = XPCOMUtils._getFactory(fakeLoopAboutModule);
+let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
+registerCleanupFunction(function() {
+  gBrowser.removeCurrentTab();
+  kObservedTopics.forEach(topic => {
+    Services.obs.removeObserver(observer, topic);
+  });
+  Services.prefs.clearUserPref(PREF_PERMISSION_FAKE);
+});
+
+
+let gTests = [
+
+{
+  desc: "getUserMedia about:loopconversation shouldn't prompt",
+  run: function checkAudioVideoLoop() {
+    let classID = Cc["@mozilla.org/uuid-generator;1"]
+                    .getService(Ci.nsIUUIDGenerator).generateUUID();
+    registrar.registerFactory(classID, "",
+                              "@mozilla.org/network/protocol/about;1?what=loopconversation",
+                              factory);
+
+    yield loadPage("about:loopconversation");
+
+    yield promiseObserverCalled("recording-device-events", () => {
+      info("requesting devices");
+      content.wrappedJSObject.requestDevice(true, true);
+    });
+    // Wait for the devices to actually be captured and running before
+    // proceeding.
+    yield promisePopupNotification("webRTC-sharingDevices");
+
+    is(getMediaCaptureState(), "CameraAndMicrophone",
+       "expected camera and microphone to be shared");
+
+    yield closeStream();
+
+    registrar.unregisterFactory(classID, factory);
+  }
+},
+
+{
+  desc: "getUserMedia about:evil should prompt",
+  run: function checkAudioVideoNonLoop() {
+    let classID = Cc["@mozilla.org/uuid-generator;1"]
+                    .getService(Ci.nsIUUIDGenerator).generateUUID();
+    registrar.registerFactory(classID, "",
+                              "@mozilla.org/network/protocol/about;1?what=evil",
+                              factory);
+
+    yield loadPage("about:evil");
+
+    yield promiseObserverCalled("getUserMedia:request", () => {
+      info("requesting devices");
+      content.wrappedJSObject.requestDevice(true, true);
+    });
+
+    isnot(getMediaCaptureState(), "CameraAndMicrophone",
+       "expected camera and microphone not to be shared");
+
+    registrar.unregisterFactory(classID, factory);
+  }
+},
+
+];
+
+function test() {
+  waitForExplicitFinish();
+
+  Services.prefs.setBoolPref(PREF_PERMISSION_FAKE, true);
+
+  gTab = gBrowser.addTab();
+  gBrowser.selectedTab = gTab;
+
+  kObservedTopics.forEach(topic => {
+    Services.obs.addObserver(observer, topic, false);
+  });
+
+  Task.spawn(function () {
+    for (let test of gTests) {
+      info(test.desc);
+      yield test.run();
+
+      // Cleanup before the next test
+      expectNoObserverCalled();
+    }
+  }).then(finish, ex => {
+    ok(false, "Unexpected Exception: " + ex);
+    finish();
+  });
+}
+
+function wait(time) {
+  let deferred = Promise.defer();
+  setTimeout(deferred.resolve, time);
+  return deferred.promise;
+}
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -162,16 +162,17 @@
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_base.xpt
 @BINPATH@/components/content_events.xpt
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.xpt
+@BINPATH@/components/content_geckomediaplugins.xpt
 #ifdef MOZ_WEBRTC
 @BINPATH@/components/content_webrtc.xpt
 #endif
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -19,16 +19,17 @@ EXTRA_JS_MODULES += [
     'offlineAppCache.jsm',
     'PanelFrame.jsm',
     'RemotePrompt.jsm',
     'SharedFrame.jsm',
     'SitePermissions.jsm',
     'Social.jsm',
     'TabCrashReporter.jsm',
     'WebappManager.jsm',
+    'webrtcUI.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXTRA_JS_MODULES += [
         'Windows8WindowFrameColor.jsm',
         'WindowsJumpLists.jsm',
         'WindowsPreviewPerTab.jsm',
     ]
@@ -37,13 +38,12 @@ if CONFIG['NIGHTLY_BUILD']:
     EXTRA_JS_MODULES += [
         'SignInToWebsite.jsm',
     ]
 
 EXTRA_PP_JS_MODULES += [
     'AboutHome.jsm',
     'RecentWindow.jsm',
     'UITour.jsm',
-    'webrtcUI.jsm',
 ]
 
 if CONFIG['MOZILLA_OFFICIAL']:
     DEFINES['MOZILLA_OFFICIAL'] = 1
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -123,38 +123,18 @@ function prompt(aContentWindow, aCallID,
     return;
   }
 
   let uri = aContentWindow.document.documentURIObject;
   let browser = getBrowserForWindow(aContentWindow);
   let chromeDoc = browser.ownerDocument;
   let chromeWin = chromeDoc.defaultView;
   let stringBundle = chromeWin.gNavigatorBundle;
-#ifdef MOZ_LOOP
-  let host;
-  // For Loop protocols that start with about:, use brandShortName instead of the host for now.
-  // Bug 990678 will implement improvements/replacements for the permissions dialog, so this
-  // should become unnecessary.
-  if (uri.spec.startsWith("about:loop")) {
-    let brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
-
-    host = brandBundle.GetStringFromName("brandShortName");
-  }
-  else {
-    // uri.host throws for about: protocols, so we have to do this once we know
-    // it isn't about:loop.
-    host = uri.host;
-  }
-
-  let message = stringBundle.getFormattedString("getUserMedia.share" + requestType + ".message",
-                                                [ host ]);
-#else
   let message = stringBundle.getFormattedString("getUserMedia.share" + requestType + ".message",
                                                 [ uri.host ]);
-#endif
 
   let mainAction = {
     label: PluralForm.get(requestType == "CameraAndMicrophone" ? 2 : 1,
                           stringBundle.getString("getUserMedia.shareSelectedDevices.label")),
     accessKey: stringBundle.getString("getUserMedia.shareSelectedDevices.accesskey"),
     // The real callback will be set during the "showing" event. The
     // empty function here is so that PopupNotifications.show doesn't
     // reject the action.
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -831,18 +831,16 @@ GK_ATOM(onstkcommand, "onstkcommand")
 GK_ATOM(onstksessionend, "onstksessionend")
 GK_ATOM(onsubmit, "onsubmit")
 GK_ATOM(onsuccess, "onsuccess")
 GK_ATOM(ontypechange, "ontypechange")
 GK_ATOM(ontext, "ontext")
 GK_ATOM(ontouchstart, "ontouchstart")
 GK_ATOM(ontouchend, "ontouchend")
 GK_ATOM(ontouchmove, "ontouchmove")
-GK_ATOM(ontouchenter, "ontouchenter")
-GK_ATOM(ontouchleave, "ontouchleave")
 GK_ATOM(ontouchcancel, "ontouchcancel")
 GK_ATOM(ontransitionend, "ontransitionend")
 GK_ATOM(onunderflow, "onunderflow")
 GK_ATOM(onunload, "onunload")
 GK_ATOM(onupdatefound, "onupdatefound")
 GK_ATOM(onupdateready, "onupdateready")
 GK_ATOM(onupgradeneeded, "onupgradeneeded")
 GK_ATOM(onussdreceived, "onussdreceived")
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -970,16 +970,25 @@ CanvasRenderingContext2D::EnsureTarget()
 
     gCanvasAzureMemoryUsed += mWidth * mHeight * 4;
     JSContext* context = nsContentUtils::GetCurrentJSContext();
     if (context) {
       JS_updateMallocCounter(context, mWidth * mHeight * 4);
     }
 
     mTarget->ClearRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
+    if (mTarget->GetBackendType() == mgfx::BackendType::CAIRO) {
+      // Cairo doesn't play well with huge clips. When given a very big clip it
+      // will try to allocate big mask surface without taking the target
+      // size into account which can cause OOM. See bug 1034593.
+      // This limits the clip extents to the size of the canvas.
+      // A fix in Cairo would probably be preferable, but requires somewhat
+      // invasive changes.
+      mTarget->PushClipRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
+    }
     // Force a full layer transaction since we didn't have a layer before
     // and now we might need one.
     if (mCanvasElement) {
       mCanvasElement->InvalidateCanvas();
     }
     // Calling Redraw() tells our invalidation machinery that the entire
     // canvas is already invalid, which can speed up future drawing.
     Redraw();
@@ -1057,16 +1066,21 @@ CanvasRenderingContext2D::InitializeWith
   mTarget = gfxPlatform::GetPlatform()->
     CreateDrawTargetForSurface(surface, IntSize(width, height));
 
   if (!mTarget) {
     EnsureErrorTarget();
     mTarget = sErrorTarget;
   }
 
+  if (mTarget->GetBackendType() == mgfx::BackendType::CAIRO) {
+    // Cf comment in EnsureTarget
+    mTarget->PushClipRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CanvasRenderingContext2D::SetIsOpaque(bool isOpaque)
 {
   if (isOpaque != mOpaque) {
     mOpaque = isOpaque;
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -6594,16 +6594,18 @@ HTMLInputElement::UpdateTooLongValidityS
 }
 
 void
 HTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
 {
   bool notify = !mParserCreating;
   nsCOMPtr<nsIDOMHTMLInputElement> selection = GetSelectedRadioButton();
 
+  aIgnoreSelf = aIgnoreSelf || !IsMutable();
+
   // If there is no selection, that might mean the radio is not in a group.
   // In that case, we can look for the checked state of the radio.
   bool selected = selection || (!aIgnoreSelf && mChecked);
   bool required = !aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required);
   bool valueMissing = false;
 
   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
 
@@ -6619,17 +6621,17 @@ HTMLInputElement::UpdateValueMissingVali
   // If the current radio is required and not ignored, we can assume the entire
   // group is required.
   if (!required) {
     required = (aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required))
                  ? container->GetRequiredRadioCount(name) - 1
                  : container->GetRequiredRadioCount(name);
   }
 
-  valueMissing = IsMutable() && required && !selected;
+  valueMissing = required && !selected;
 
   if (container->GetValueMissingState(name) != valueMissing) {
     container->SetValueMissingState(name, valueMissing);
 
     SetValidityState(VALIDITY_STATE_VALUE_MISSING, valueMissing);
 
     // nsRadioSetValueMissingState will call ContentStateChanged while visiting.
     nsAutoScriptBlocker scriptBlocker;
--- a/content/html/content/test/mochitest.ini
+++ b/content/html/content/test/mochitest.ini
@@ -409,16 +409,17 @@ skip-if = (toolkit == 'gonk' && debug) |
 [test_bug845057.html]
 [test_bug869040.html]
 [test_bug870787.html]
 [test_bug874758.html]
 [test_bug879319.html]
 [test_bug885024.html]
 [test_bug893537.html]
 [test_bug969346.html]
+[test_bug982039.html]
 [test_bug1003539.html]
 [test_change_crossorigin.html]
 [test_checked.html]
 [test_dir_attributes_reflection.html]
 [test_dl_attributes_reflection.html]
 [test_element_prototype.html]
 [test_embed_attributes_reflection.html]
 [test_formData.html]
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug982039.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=982039
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 982039</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 982039 **/
+  SimpleTest.waitForExplicitFinish();
+  function test() {
+    var f = document.getElementById("testform");
+    f.elements[0].disabled = true;
+    is(f.checkValidity(), false,
+       "Setting a radiobutton to disabled shouldn't make form valid.");
+
+    f.elements[1].checked = true;
+    ok(f.checkValidity(), "Form should be now valid.");
+
+    f.elements[0].required = false;
+    f.elements[1].required = false;
+    f.elements[2].required = false;
+    SimpleTest.finish();
+  }
+
+  </script>
+</head>
+<body onload="test()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=982039">Mozilla Bug 982039</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+<form action="#" id="testform">
+  <input type="radio" name="radio" value="1" required>
+  <input type="radio" name="radio" value="2" required>
+  <input type="radio" name="radio" value="3" required>
+</form>
+</body>
+</html>
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2784,19 +2784,25 @@ MediaStreamGraphImpl::CollectReports(nsI
     mNeedsMemoryReport = true;
 
     {
       // Wake up the MSG thread.
       MonitorAutoLock monitorLock(mMonitor);
       EnsureImmediateWakeUpLocked(monitorLock);
     }
 
-    // Wait for the report to complete.
+    if (mLifecycleState >= LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN) {
+      // Shutting down, nothing to report.
+      return NS_OK;
+    }
+
+    // Wait for up to one second for the report to complete.
     nsresult rv;
-    while ((rv = memoryReportLock.Wait()) != NS_OK) {
+    const PRIntervalTime kMaxWait = PR_SecondsToInterval(1);
+    while ((rv = memoryReportLock.Wait(kMaxWait)) != NS_OK) {
       if (PR_GetError() != PR_PENDING_INTERRUPT_ERROR) {
         return rv;
       }
     }
   }
 
 #define REPORT(_path, _amount, _desc)                                       \
   do {                                                                      \
--- a/content/media/gmp/GMPParent.h
+++ b/content/media/gmp/GMPParent.h
@@ -10,20 +10,20 @@
 #include "GMPVideoDecoderParent.h"
 #include "GMPVideoEncoderParent.h"
 #include "mozilla/gmp/PGMPParent.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 #include "nsISupports.h"
 #include "nsString.h"
 #include "nsTArray.h"
+#include "nsIFile.h"
 
 class nsILineInputStream;
 class nsIThread;
-class nsIFile;
 
 namespace mozilla {
 namespace gmp {
 
 class GMPCapability
 {
 public:
   nsCString mAPIName;
@@ -72,16 +72,20 @@ public:
   // 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;
 
+  already_AddRefed<nsIFile> GetDirectory() {
+    return nsCOMPtr<nsIFile>(mDirectory).forget();
+  }
+
 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;
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -3,26 +3,22 @@
  * 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 "GMPService.h"
 #include "GMPParent.h"
 #include "GMPVideoDecoderParent.h"
 #include "nsIObserverService.h"
 #include "GeckoChildProcessHost.h"
-#if defined(XP_WIN)
-#include "nsIWindowsRegKey.h"
-#endif
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SyncRunnable.h"
-#include "nsDirectoryServiceUtils.h"
-#include "nsDirectoryServiceDefs.h"
 #include "nsXPCOMPrivate.h"
-#include "nsISimpleEnumerator.h"
 #include "mozilla/Services.h"
+#include "nsNativeCharsetUtils.h"
+#include "nsIConsoleService.h"
 
 namespace mozilla {
 namespace gmp {
 
 static StaticRefPtr<GeckoMediaPluginService> sSingletonService;
 
 class GMPServiceCreateHelper MOZ_FINAL : public nsRunnable
 {
@@ -108,26 +104,16 @@ GeckoMediaPluginService::~GeckoMediaPlug
   MOZ_ASSERT(mPlugins.IsEmpty());
 }
 
 void
 GeckoMediaPluginService::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  // Cache user directory while we're on the main thread. We do this because
-  // if we try to use "~" in a path during plugin lookup on a non-main thread,
-  // the nsIFile code will try to resolve it using NS_GetSpecialDirectory, which
-  // doesn't work on non-main threads.
-  nsCOMPtr<nsIFile> homeDir;
-  NS_GetSpecialDirectory(NS_OS_HOME_DIR, getter_AddRefs(homeDir));
-  if (homeDir) {
-    homeDir->GetPath(mHomePath);
-  }
-
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   MOZ_ASSERT(obsService);
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)));
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false)));
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::Observe(nsISupports* aSubject,
@@ -177,16 +163,19 @@ GeckoMediaPluginService::GetThread(nsITh
     if (mShuttingDown) {
       return NS_ERROR_FAILURE;
     }
 
     nsresult rv = NS_NewNamedThread("GMPThread", getter_AddRefs(mGMPThread));
     if (NS_FAILED(rv)) {
       return rv;
     }
+
+    // Tell the thread to initialize plugins
+    mGMPThread->Dispatch(NS_NewRunnableMethod(this, &GeckoMediaPluginService::LoadFromEnvironment), NS_DISPATCH_NORMAL);
   }
 
   NS_ADDREF(mGMPThread);
   *aThread = mGMPThread;
 
   return NS_OK;
 }
 
@@ -267,40 +256,92 @@ GeckoMediaPluginService::UnloadPlugins()
   mShuttingDownOnGMPThread = true;
 
   for (uint32_t i = 0; i < mPlugins.Length(); i++) {
     mPlugins[i]->UnloadProcess();
   }
   mPlugins.Clear();
 }
 
+void
+GeckoMediaPluginService::LoadFromEnvironment()
+{
+  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+
+  const char* env = PR_GetEnv("MOZ_GMP_PATH");
+  if (!env || !*env) {
+    return;
+  }
+
+  nsString allpaths;
+  if (NS_WARN_IF(NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(env), allpaths)))) {
+    return;
+  }
+
+  uint32_t pos = 0;
+  while (pos < allpaths.Length()) {
+    // Loop over multiple path entries separated by colons (*nix) or
+    // semicolons (Windows)
+    int32_t next = allpaths.FindChar(XPCOM_ENV_PATH_SEPARATOR[0], pos);
+    if (next == -1) {
+      AddOnGMPThread(nsDependentSubstring(allpaths, pos));
+      break;
+    } else {
+      AddOnGMPThread(nsDependentSubstring(allpaths, pos, next - pos));
+      pos = next + 1;
+    }
+  }
+}
+
+NS_IMETHODIMP
+GeckoMediaPluginService::PathRunnable::Run()
+{
+  if (mAdd) {
+    mService->AddOnGMPThread(mPath);
+  } else {
+    mService->RemoveOnGMPThread(mPath);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIThread> thread;
+  nsresult rv = GetThread(getter_AddRefs(thread));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  nsCOMPtr<nsIRunnable> r = new PathRunnable(this, aDirectory, true);
+  thread->Dispatch(r, NS_DISPATCH_NORMAL);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIThread> thread;
+  nsresult rv = GetThread(getter_AddRefs(thread));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  nsCOMPtr<nsIRunnable> r = new PathRunnable(this, aDirectory, false);
+  thread->Dispatch(r, NS_DISPATCH_NORMAL);
+  return NS_OK;
+}
+
 GMPParent*
 GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
                                             const nsCString& aAPI,
                                             const nsTArray<nsCString>& aTags)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
-  GMPParent* gmp = SelectPluginFromListForAPI(aOrigin, aAPI, aTags);
-  if (gmp) {
-    return gmp;
-  }
-
-  RefreshPluginList();
-
-  return SelectPluginFromListForAPI(aOrigin, aAPI, aTags);
-}
-
-GMPParent*
-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];
     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;
@@ -318,202 +359,56 @@ GeckoMediaPluginService::SelectPluginFro
         gmp->SetOrigin(aOrigin);
       }
       return gmp;
     }
   }
   return nullptr;
 }
 
-nsresult
-GeckoMediaPluginService::GetDirectoriesToSearch(nsTArray<nsCOMPtr<nsIFile>> &aDirs)
+
+void
+GeckoMediaPluginService::AddOnGMPThread(const nsAString& aDirectory)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
-#if defined(XP_MACOSX)
-  nsCOMPtr<nsIFile> searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
-  MOZ_ASSERT(!mHomePath.IsEmpty());
-  nsresult rv = searchDir->InitWithPath(mHomePath + NS_LITERAL_STRING("/Library/Internet Plug-Ins/"));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  aDirs.AppendElement(searchDir);
-  searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
-  rv = searchDir->InitWithPath(NS_LITERAL_STRING("/Library/Internet Plug-Ins/"));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  aDirs.AppendElement(searchDir);
-#elif defined(OS_POSIX)
-  nsCOMPtr<nsIFile> searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
-  nsresult rv = searchDir->InitWithPath(NS_LITERAL_STRING("/usr/lib/mozilla/plugins/"));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  aDirs.AppendElement(searchDir);
-#endif
-  return NS_OK;
-}
-
-#if defined(XP_WIN)
-static nsresult
-GetPossiblePluginsForRegRoot(uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs)
-{
-  nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
-  if (!regKey) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsresult rv = regKey->Open(aKey,
-                             NS_LITERAL_STRING("Software\\MozillaPlugins"),
-                             nsIWindowsRegKey::ACCESS_READ);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  uint32_t childCount = 0;
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(regKey->GetChildCount(&childCount)));
-  for (uint32_t index = 0; index < childCount; index++) {
-    nsAutoString childName;
-    rv = regKey->GetChildName(index, childName);
-    if (NS_FAILED(rv)) {
-      continue;
-    }
-
-    nsCOMPtr<nsIWindowsRegKey> childKey;
-    rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE,
-                           getter_AddRefs(childKey));
-    if (NS_FAILED(rv) || !childKey) {
-      continue;
-    }
-
-    nsAutoString path;
-    rv = childKey->ReadStringValue(NS_LITERAL_STRING("Path"), path);
-    if (NS_FAILED(rv)) {
-      continue;
-    }
-
-    nsCOMPtr<nsIFile> localFile;
-    if (NS_SUCCEEDED(NS_NewLocalFile(path, true, getter_AddRefs(localFile))) &&
-        localFile) {
-      bool isFileThere = false;
-      if (NS_SUCCEEDED(localFile->Exists(&isFileThere)) && isFileThere) {
-        aDirs.AppendElement(localFile);
-      }
-    }
-  }
-
-  regKey->Close();
-
-  return NS_OK;
-}
-#endif
-
-nsresult
-GeckoMediaPluginService::GetPossiblePlugins(nsTArray<nsCOMPtr<nsIFile>>& aDirs)
-{
-  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
-
-#if defined(XP_WIN)
-  // The ROOT_KEY_CURRENT_USER entry typically fails to open, causing this call to
-  // fail. Don't check any return values because if we find nothing we don't care.
-  GetPossiblePluginsForRegRoot(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, aDirs);
-  GetPossiblePluginsForRegRoot(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, aDirs);
-#endif
-  return NS_OK;
-}
-
-nsresult
-GeckoMediaPluginService::SearchDirectory(nsIFile* aSearchDir)
-{
-  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
-  MOZ_ASSERT(aSearchDir);
-
-  nsCOMPtr<nsISimpleEnumerator> iter;
-  nsresult rv = aSearchDir->GetDirectoryEntries(getter_AddRefs(iter));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  bool hasMore;
-  while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
-    nsCOMPtr<nsISupports> supports;
-    rv = iter->GetNext(getter_AddRefs(supports));
-    if (NS_FAILED(rv)) {
-      continue;
-    }
-    nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
-    if (NS_FAILED(rv)) {
-      continue;
-    }
-    ProcessPossiblePlugin(dirEntry);
-  }
-
-  return NS_OK;
-}
-
-void
-GeckoMediaPluginService::ProcessPossiblePlugin(nsIFile* aDir)
-{
-  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
-  MOZ_ASSERT(aDir);
-
-  bool isDirectory = false;
-  nsresult rv = aDir->IsDirectory(&isDirectory);
-  if (NS_FAILED(rv) || !isDirectory) {
-    return;
-  }
-
-  nsAutoString leafName;
-  rv = aDir->GetLeafName(leafName);
-  if (NS_FAILED(rv)) {
-    return;
-  }
-
-  NS_NAMED_LITERAL_STRING(prefix, "gmp-");
-  if (leafName.Length() <= prefix.Length() ||
-      !Substring(leafName, 0, prefix.Length()).Equals(prefix)) {
+  nsCOMPtr<nsIFile> directory;
+  nsresult rv = NS_NewLocalFile(aDirectory, false, getter_AddRefs(directory));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   nsRefPtr<GMPParent> gmp = new GMPParent();
-  rv = gmp->Init(aDir);
+  rv = gmp->Init(directory);
   if (NS_FAILED(rv)) {
     return;
   }
 
   mPlugins.AppendElement(gmp);
 }
 
 void
-GeckoMediaPluginService::RefreshPluginList()
+GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
-  for (uint32_t iPlusOne = mPlugins.Length(); iPlusOne > 0; iPlusOne--) {
-    if (mPlugins[iPlusOne - 1]->State() == GMPStateNotLoaded) {
-      mPlugins.RemoveElementAt(iPlusOne - 1);
-    }
-  }
-
-  nsTArray<nsCOMPtr<nsIFile>> searchDirs;
-  nsresult rv = GetDirectoriesToSearch(searchDirs);
-  if (NS_FAILED(rv)) {
+  nsCOMPtr<nsIFile> directory;
+  nsresult rv = NS_NewLocalFile(aDirectory, false, getter_AddRefs(directory));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  for (uint32_t i = 0; i < searchDirs.Length(); i++) {
-    SearchDirectory(searchDirs[i]);
+  for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
+    nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory();
+    bool equals;
+    if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
+      mPlugins[i]->UnloadProcess();
+      mPlugins.RemoveElementAt(i);
+      return;
+    }
   }
-
-  nsTArray<nsCOMPtr<nsIFile>> possiblePlugins;
-  rv = GetPossiblePlugins(possiblePlugins);
-  if (NS_FAILED(rv)) {
-    return;
-  }
-
-  for (uint32_t i = 0; i < possiblePlugins.Length(); i++) {
-    ProcessPossiblePlugin(possiblePlugins[i]);
-  }
+  NS_WARNING("Removing GMP which was never added.");
+  nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
+  cs->LogStringMessage(MOZ_UTF16("Removing GMP which was never added."));
 }
 
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/GMPService.h
+++ b/content/media/gmp/GMPService.h
@@ -8,18 +8,18 @@
 
 #include "mozIGeckoMediaPluginService.h"
 #include "nsIObserver.h"
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
+#include "nsThreadUtils.h"
 
-class nsIFile;
 template <class> struct already_AddRefed;
 
 namespace mozilla {
 namespace gmp {
 
 class GMPParent;
 
 class GeckoMediaPluginService MOZ_FINAL : public mozIGeckoMediaPluginService
@@ -33,34 +33,49 @@ public:
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_MOZIGECKOMEDIAPLUGINSERVICE
   NS_DECL_NSIOBSERVER
 
 private:
   ~GeckoMediaPluginService();
 
-  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 LoadFromEnvironment();
   void ProcessPossiblePlugin(nsIFile* aDir);
-  nsresult SearchDirectory(nsIFile* aSearchDir);
-  nsresult GetPossiblePlugins(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
-  nsresult GetDirectoriesToSearch(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
+
+  void AddOnGMPThread(const nsAString& aSearchDir);
+  void RemoveOnGMPThread(const nsAString& aSearchDir);
+
+  class PathRunnable : public nsRunnable
+  {
+  public:
+    PathRunnable(GeckoMediaPluginService* service, const nsAString& path,
+                 bool add)
+      : mService(service)
+      , mPath(path)
+      , mAdd(add)
+    { }
+
+    NS_DECL_NSIRUNNABLE
+
+  private:
+    nsRefPtr<GeckoMediaPluginService> mService;
+    nsString mPath;
+    bool mAdd;
+  };
 
   nsTArray<nsRefPtr<GMPParent>> mPlugins;
   Mutex mMutex; // Protects mGMPThread and mShuttingDown
   nsCOMPtr<nsIThread> mGMPThread;
   bool mShuttingDown;
   bool mShuttingDownOnGMPThread;
-  nsString mHomePath;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPService_h_
--- a/content/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/content/media/gmp/mozIGeckoMediaPluginService.idl
@@ -16,31 +16,50 @@ 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)]
+[scriptable, uuid(63fc797f-9d01-43f4-8b93-5b1fe713c2f8)]
 interface mozIGeckoMediaPluginService : nsISupports
 {
-  // Returns the GMP thread.
-  // Callable from any thread.
+  /**
+   * The GMP thread. Callable from any thread.
+   */
   readonly attribute nsIThread thread;
 
-  // 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.
+  /**
+   * Get 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.
+   */
+  [noscript]
   GMPVideoDecoder getGMPVideoDecoder(in TagArray tags,
                                      [optional] in AString origin,
                                      out GMPVideoHost outVideoHost);
 
-  // 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.
+  /**
+   * Get 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.
+   */
+  [noscript]
   GMPVideoEncoder getGMPVideoEncoder(in TagArray tags,
                                      [optional] in AString origin,
                                      out GMPVideoHost outVideoHost);
+
+  /**
+   * Add a directory to scan for gecko media plugins.
+   * @note Main-thread API.
+   */
+  void addPluginDirectory(in AString directory);
+
+  /**
+   * Remove a directory for gecko media plugins.
+   * @note Main-thread API.
+   */
+  void removePluginDirectory(in AString directory);
 };
--- a/content/media/webrtc/MediaEngineWebRTC.cpp
+++ b/content/media/webrtc/MediaEngineWebRTC.cpp
@@ -262,17 +262,24 @@ MediaEngineWebRTC::EnumerateAudioDevices
 
   ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
   if (!ptrVoEHw)  {
     return;
   }
 
   int nDevices = 0;
   ptrVoEHw->GetNumOfRecordingDevices(nDevices);
-  for (int i = 0; i < nDevices; i++) {
+  int i;
+#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
+  i = 0; // Bug 1037025 - let the OS handle defaulting for now on android/b2g
+#else
+  // -1 is "default communications device" depending on OS in webrtc.org code
+  i = -1;
+#endif
+  for (; i < nDevices; i++) {
     // We use constants here because GetRecordingDeviceName takes char[128].
     char deviceName[128];
     char uniqueId[128];
     // paranoia; jingle doesn't bother with this
     deviceName[0] = '\0';
     uniqueId[0] = '\0';
 
     int error = ptrVoEHw->GetRecordingDeviceName(i, deviceName, uniqueId);
--- a/content/svg/content/src/SVGEllipseElement.cpp
+++ b/content/svg/content/src/SVGEllipseElement.cpp
@@ -91,36 +91,25 @@ SVGEllipseElement::GetLengthInfo()
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 void
 SVGEllipseElement::ConstructPath(gfxContext *aCtx)
 {
-  if (!aCtx->IsCairo()) {
-    RefPtr<DrawTarget> dt = aCtx->GetDrawTarget();
-    FillRule fillRule =
-      aCtx->CurrentFillRule() == gfxContext::FILL_RULE_WINDING ?
-        FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
-    RefPtr<PathBuilder> builder = dt->CreatePathBuilder(fillRule);
-    RefPtr<Path> path = BuildPath(builder);
-    if (path) {
-      nsRefPtr<gfxPath> gfxpath = new gfxPath(path);
-      aCtx->SetPath(gfxpath);
-    }
-    return;
-  }
-
-  float x, y, rx, ry;
-
-  GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
-
-  if (rx > 0.0f && ry > 0.0f) {
-    aCtx->Ellipse(gfxPoint(x, y), gfxSize(2.0*rx, 2.0*ry));
+  RefPtr<DrawTarget> dt = aCtx->GetDrawTarget();
+  FillRule fillRule =
+    aCtx->CurrentFillRule() == gfxContext::FILL_RULE_WINDING ?
+      FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
+  RefPtr<PathBuilder> builder = dt->CreatePathBuilder(fillRule);
+  RefPtr<Path> path = BuildPath(builder);
+  if (path) {
+    nsRefPtr<gfxPath> gfxpath = new gfxPath(path);
+    aCtx->SetPath(gfxpath);
   }
 }
 
 TemporaryRef<Path>
 SVGEllipseElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, rx, ry;
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -804,17 +804,17 @@ Navigator::Vibrate(const nsTArray<uint32
   for (size_t i = 0; i < pattern.Length(); ++i) {
     if (pattern[i] > sMaxVibrateMS) {
       pattern[i] = sMaxVibrateMS;
     }
   }
 
   // The spec says we check sVibratorEnabled after we've done the sanity
   // checking on the pattern.
-  if (pattern.IsEmpty() || !sVibratorEnabled) {
+  if (!sVibratorEnabled) {
     return true;
   }
 
   // Add a listener to cancel the vibration if the document becomes hidden,
   // and remove the old visibility listener, if there was one.
 
   if (!gVibrateWindowListener) {
     // If gVibrateWindowListener is null, this is the first time we've vibrated,
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -683,16 +683,33 @@ GetButtonsFlagForButton(int32_t aButton)
     case 5:
       return WidgetMouseEvent::e5thButtonFlag;
     default:
       NS_ERROR("Button not known.");
       return 0;
   }
 }
 
+nsView*
+nsDOMWindowUtils::GetViewToDispatchEvent(nsPresContext* presContext, nsIPresShell** presShell)
+{
+  if (presContext && presShell) {
+    *presShell = presContext->PresShell();
+    if (*presShell) {
+      NS_ADDREF(*presShell);
+      if (nsViewManager* viewManager = (*presShell)->GetViewManager()) {
+        if (nsView* view = viewManager->GetRootView()) {
+          return view;
+        }
+      }
+    }
+  }
+  return nullptr;
+}
+
 NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseEventCommon(const nsAString& aType,
                                        float aX,
                                        float aY,
                                        int32_t aButton,
                                        int32_t aClickCount,
                                        int32_t aModifiers,
                                        bool aIgnoreRootScrollFrame,
@@ -751,54 +768,52 @@ nsDOMWindowUtils::SendMouseEventCommon(c
   if (!presContext)
     return NS_ERROR_FAILURE;
 
   event.refPoint = ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
   event.ignoreRootScrollFrame = aIgnoreRootScrollFrame;
 
   nsEventStatus status;
   if (aToWindow) {
-    nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
-    if (!presShell)
+    nsCOMPtr<nsIPresShell> presShell;
+    nsView* view = GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
+    if (!presShell || !view) {
       return NS_ERROR_FAILURE;
-    nsViewManager* viewManager = presShell->GetViewManager();
-    if (!viewManager)
-      return NS_ERROR_FAILURE;
-    nsView* view = viewManager->GetRootView();
-    if (!view)
-      return NS_ERROR_FAILURE;
-
+    }
     status = nsEventStatus_eIgnore;
     return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
   }
   nsresult rv = widget->DispatchEvent(&event, status);
-  *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
+  if (aPreventDefault) {
+    *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
+  }
 
   return rv;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::SendPointerEvent(const nsAString& aType,
-                                   float aX,
-                                   float aY,
-                                   int32_t aButton,
-                                   int32_t aClickCount,
-                                   int32_t aModifiers,
-                                   bool aIgnoreRootScrollFrame,
-                                   float aPressure,
-                                   unsigned short aInputSourceArg,
-                                   int32_t aPointerId,
-                                   int32_t aWidth,
-                                   int32_t aHeight,
-                                   int32_t tiltX,
-                                   int32_t tiltY,
-                                   bool aIsPrimary,
-                                   bool aIsSynthesized,
-                                   uint8_t aOptionalArgCount,
-                                   bool* aPreventDefault)
+nsDOMWindowUtils::SendPointerEventCommon(const nsAString& aType,
+                                         float aX,
+                                         float aY,
+                                         int32_t aButton,
+                                         int32_t aClickCount,
+                                         int32_t aModifiers,
+                                         bool aIgnoreRootScrollFrame,
+                                         float aPressure,
+                                         unsigned short aInputSourceArg,
+                                         int32_t aPointerId,
+                                         int32_t aWidth,
+                                         int32_t aHeight,
+                                         int32_t aTiltX,
+                                         int32_t aTiltY,
+                                         bool aIsPrimary,
+                                         bool aIsSynthesized,
+                                         uint8_t aOptionalArgCount,
+                                         bool aToWindow,
+                                         bool* aPreventDefault)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   // get the widget to send the event to
   nsPoint offset;
   nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
   if (!widget) {
     return NS_ERROR_FAILURE;
@@ -828,39 +843,111 @@ nsDOMWindowUtils::SendPointerEvent(const
   event.button = aButton;
   event.buttons = GetButtonsFlagForButton(aButton);
   event.widget = widget;
   event.pressure = aPressure;
   event.inputSource = aInputSourceArg;
   event.pointerId = aPointerId;
   event.width = aWidth;
   event.height = aHeight;
-  event.tiltX = tiltX;
-  event.tiltY = tiltY;
+  event.tiltX = aTiltX;
+  event.tiltY = aTiltY;
   event.isPrimary = aIsPrimary;
   event.clickCount = aClickCount;
   event.time = PR_IntervalNow();
   event.mFlags.mIsSynthesizedForTests = aOptionalArgCount >= 10 ? aIsSynthesized : true;
 
   nsPresContext* presContext = GetPresContext();
   if (!presContext) {
     return NS_ERROR_FAILURE;
   }
 
   event.refPoint = ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
   event.ignoreRootScrollFrame = aIgnoreRootScrollFrame;
 
   nsEventStatus status;
+  if (aToWindow) {
+    nsCOMPtr<nsIPresShell> presShell;
+    nsView* view = GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
+    if (!presShell || !view) {
+      return NS_ERROR_FAILURE;
+    }
+    status = nsEventStatus_eIgnore;
+    return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
+  }
   nsresult rv = widget->DispatchEvent(&event, status);
-  *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
+  if (aPreventDefault) {
+    *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
+  }
 
   return rv;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::SendPointerEvent(const nsAString& aType,
+                                   float aX,
+                                   float aY,
+                                   int32_t aButton,
+                                   int32_t aClickCount,
+                                   int32_t aModifiers,
+                                   bool aIgnoreRootScrollFrame,
+                                   float aPressure,
+                                   unsigned short aInputSourceArg,
+                                   int32_t aPointerId,
+                                   int32_t aWidth,
+                                   int32_t aHeight,
+                                   int32_t aTiltX,
+                                   int32_t aTiltY,
+                                   bool aIsPrimary,
+                                   bool aIsSynthesized,
+                                   uint8_t aOptionalArgCount,
+                                   bool* aPreventDefault)
+{
+  PROFILER_LABEL("nsDOMWindowUtils", "SendPointerEvent",
+                 js::ProfileEntry::Category::EVENTS);
+
+  return SendPointerEventCommon(aType, aX, aY, aButton, aClickCount,
+                                aModifiers, aIgnoreRootScrollFrame,
+                                aPressure, aInputSourceArg, aPointerId,
+                                aWidth, aHeight, aTiltX, aTiltY,
+                                aIsPrimary, aIsSynthesized,
+                                aOptionalArgCount, false, aPreventDefault);
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::SendPointerEventToWindow(const nsAString& aType,
+                                           float aX,
+                                           float aY,
+                                           int32_t aButton,
+                                           int32_t aClickCount,
+                                           int32_t aModifiers,
+                                           bool aIgnoreRootScrollFrame,
+                                           float aPressure,
+                                           unsigned short aInputSourceArg,
+                                           int32_t aPointerId,
+                                           int32_t aWidth,
+                                           int32_t aHeight,
+                                           int32_t aTiltX,
+                                           int32_t aTiltY,
+                                           bool aIsPrimary,
+                                           bool aIsSynthesized,
+                                           uint8_t aOptionalArgCount)
+{
+  PROFILER_LABEL("nsDOMWindowUtils", "SendPointerEventToWindow",
+                 js::ProfileEntry::Category::EVENTS);
+
+  return SendPointerEventCommon(aType, aX, aY, aButton, aClickCount,
+                                aModifiers, aIgnoreRootScrollFrame,
+                                aPressure, aInputSourceArg, aPointerId,
+                                aWidth, aHeight, aTiltX, aTiltY,
+                                aIsPrimary, aIsSynthesized,
+                                aOptionalArgCount, true, nullptr);
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::SendWheelEvent(float aX,
                                  float aY,
                                  double aDeltaX,
                                  double aDeltaY,
                                  double aDeltaZ,
                                  uint32_t aDeltaMode,
                                  int32_t aModifiers,
                                  int32_t aLineOrPageDeltaX,
@@ -1037,31 +1124,21 @@ nsDOMWindowUtils::SendTouchEventCommon(c
                                   nsIntPoint(aRxs[i], aRys[i]),
                                   aRotationAngles[i],
                                   aForces[i]);
     event.touches.AppendElement(t);
   }
 
   nsEventStatus status;
   if (aToWindow) {
-    nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
-    if (!presShell) {
+    nsCOMPtr<nsIPresShell> presShell;
+    nsView* view = GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
+    if (!presShell || !view) {
       return NS_ERROR_FAILURE;
     }
-
-    nsViewManager* viewManager = presShell->GetViewManager();
-    if (!viewManager) {
-      return NS_ERROR_FAILURE;
-    }
-
-    nsView* view = viewManager->GetRootView();
-    if (!view) {
-      return NS_ERROR_FAILURE;
-    }
-
     status = nsEventStatus_eIgnore;
     *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
     return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
   }
 
   nsresult rv = widget->DispatchEvent(&event, status);
   *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
   return rv;
--- a/dom/base/nsDOMWindowUtils.h
+++ b/dom/base/nsDOMWindowUtils.h
@@ -12,16 +12,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/BasicEvents.h"
 
 class nsGlobalWindow;
 class nsIPresShell;
 class nsIWidget;
 class nsPresContext;
 class nsIDocument;
+class nsView;
 struct nsPoint;
 
 namespace mozilla {
   namespace layers {
     class LayerTransactionChild;
   }
 }
 
@@ -73,40 +74,61 @@ protected:
   nsIWidget* GetWidget(nsPoint* aOffset = nullptr);
   nsIWidget* GetWidgetForElement(nsIDOMElement* aElement);
 
   nsIPresShell* GetPresShell();
   nsPresContext* GetPresContext();
   nsIDocument* GetDocument();
   mozilla::layers::LayerTransactionChild* GetLayerTransaction();
 
+  nsView* GetViewToDispatchEvent(nsPresContext* presContext, nsIPresShell** presShell);
+
   NS_IMETHOD SendMouseEventCommon(const nsAString& aType,
                                   float aX,
                                   float aY,
                                   int32_t aButton,
                                   int32_t aClickCount,
                                   int32_t aModifiers,
                                   bool aIgnoreRootScrollFrame,
                                   float aPressure,
                                   unsigned short aInputSourceArg,
                                   bool aToWindow,
                                   bool *aPreventDefault,
                                   bool aIsSynthesized);
 
+  NS_IMETHOD SendPointerEventCommon(const nsAString& aType,
+                                    float aX,
+                                    float aY,
+                                    int32_t aButton,
+                                    int32_t aClickCount,
+                                    int32_t aModifiers,
+                                    bool aIgnoreRootScrollFrame,
+                                    float aPressure,
+                                    unsigned short aInputSourceArg,
+                                    int32_t aPointerId,
+                                    int32_t aWidth,
+                                    int32_t aHeight,
+                                    int32_t aTiltX,
+                                    int32_t aTiltY,
+                                    bool aIsPrimary,
+                                    bool aIsSynthesized,
+                                    uint8_t aOptionalArgCount,
+                                    bool aToWindow,
+                                    bool* aPreventDefault);
+
   NS_IMETHOD SendTouchEventCommon(const nsAString& aType,
                                   uint32_t* aIdentifiers,
                                   int32_t* aXs,
                                   int32_t* aYs,
                                   uint32_t* aRxs,
                                   uint32_t* aRys,
                                   float* aRotationAngles,
                                   float* aForces,
                                   uint32_t aCount,
                                   int32_t aModifiers,
                                   bool aIgnoreRootScrollFrame,
                                   bool aToWindow,
                                   bool* aPreventDefault);
 
-
   static mozilla::Modifiers GetWidgetModifiers(int32_t aModifiers);
 };
 
 #endif
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -323,18 +323,16 @@ EventListenerManager::AddEventListenerIn
     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
     if (window) {
       window->EnableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
     }
 #endif // MOZ_B2G
   } else if (aTypeAtom == nsGkAtoms::ontouchstart ||
              aTypeAtom == nsGkAtoms::ontouchend ||
              aTypeAtom == nsGkAtoms::ontouchmove ||
-             aTypeAtom == nsGkAtoms::ontouchenter ||
-             aTypeAtom == nsGkAtoms::ontouchleave ||
              aTypeAtom == nsGkAtoms::ontouchcancel) {
     mMayHaveTouchEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
     // we don't want touchevent listeners added by scrollbars to flip this flag
     // so we ignore listeners created with system event flag
     if (window && !aFlags.mInSystemGroup) {
       window->SetHasTouchEventListeners();
     }
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -554,24 +554,16 @@ TOUCH_EVENT(touchstart,
 TOUCH_EVENT(touchend,
             NS_TOUCH_END,
             EventNameType_All,
             NS_TOUCH_EVENT)
 TOUCH_EVENT(touchmove,
             NS_TOUCH_MOVE,
             EventNameType_All,
             NS_TOUCH_EVENT )
-TOUCH_EVENT(touchenter,
-            NS_TOUCH_ENTER,
-            EventNameType_All,
-            NS_TOUCH_EVENT )
-TOUCH_EVENT(touchleave,
-            NS_TOUCH_LEAVE,
-            EventNameType_All,
-            NS_TOUCH_EVENT)
 TOUCH_EVENT(touchcancel,
             NS_TOUCH_CANCEL,
             EventNameType_All,
             NS_TOUCH_EVENT)
 
 DOCUMENT_ONLY_EVENT(readystatechange,
                     NS_READYSTATECHANGE,
                     EventNameType_HTMLXUL,
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -3843,73 +3843,80 @@ EventStateManager::NotifyMouseOut(Widget
 }
 
 void
 EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
                                    nsIContent* aContent)
 {
   NS_ASSERTION(aContent, "Mouse must be over something");
 
+  // If pointer capture is set, we should suppress pointerover/pointerenter events
+  // for all elements except element which have pointer capture.
+  bool dispatch = !aMouseEvent->retargetedByPointerCapture;
+
   OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
 
-  if (wrapper->mLastOverElement == aContent)
+  if (wrapper->mLastOverElement == aContent && dispatch)
     return;
 
   // Before firing mouseover, check for recursion
   if (aContent == wrapper->mFirstOverEventElement)
     return;
 
   // Check to see if we're a subdocument and if so update the parent
   // document's ESM state to indicate that the mouse is over the
   // content associated with our subdocument.
   EnsureDocument(mPresContext);
-  nsIDocument *parentDoc = mDocument->GetParentDocument();
-  if (parentDoc) {
-    nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument);
-    if (docContent) {
-      nsIPresShell *parentShell = parentDoc->GetShell();
-      if (parentShell) {
+  if (nsIDocument *parentDoc = mDocument->GetParentDocument()) {
+    if (nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument)) {
+      if (nsIPresShell *parentShell = parentDoc->GetShell()) {
         EventStateManager* parentESM =
           parentShell->GetPresContext()->EventStateManager();
         parentESM->NotifyMouseOver(aMouseEvent, docContent);
       }
     }
   }
   // Firing the DOM event in the parent document could cause all kinds
   // of havoc.  Reverify and take care.
-  if (wrapper->mLastOverElement == aContent)
+  if (wrapper->mLastOverElement == aContent && dispatch)
     return;
 
   // Remember mLastOverElement as the related content for the
   // DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477.
   nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
 
   bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
-  EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
-                                       aMouseEvent,
-                                       isPointer ? NS_POINTER_ENTER :
-                                                   NS_MOUSEENTER);
+  
+  Maybe<EnterLeaveDispatcher> enterDispatcher;
+  if (dispatch) {
+    enterDispatcher.construct(this, aContent, lastOverElement, aMouseEvent,
+                              isPointer ? NS_POINTER_ENTER : NS_MOUSEENTER);
+  }
 
   NotifyMouseOut(aMouseEvent, aContent);
 
   // Store the first mouseOver event we fire and don't refire mouseOver
   // to that element while the first mouseOver is still ongoing.
   wrapper->mFirstOverEventElement = aContent;
 
   if (!isPointer) {
     SetContentState(aContent, NS_EVENT_STATE_HOVER);
   }
 
-  // Fire mouseover
-  wrapper->mLastOverFrame =
-    DispatchMouseOrPointerEvent(aMouseEvent,
-                                isPointer ? NS_POINTER_OVER :
-                                            NS_MOUSE_ENTER_SYNTH,
-                                aContent, lastOverElement);
-  wrapper->mLastOverElement = aContent;
+  if (dispatch) {
+    // Fire mouseover
+    wrapper->mLastOverFrame = 
+      DispatchMouseOrPointerEvent(aMouseEvent,
+                                  isPointer ? NS_POINTER_OVER : NS_MOUSE_ENTER_SYNTH,
+                                  aContent, lastOverElement);
+    wrapper->mLastOverElement = aContent;
+  } else {
+    wrapper->mLastOverFrame = nullptr;
+    wrapper->mLastOverElement = nullptr;
+  }
 
   // Turn recursion protection back off
   wrapper->mFirstOverEventElement = nullptr;
 }
 
 // Returns the center point of the window's inner content area.
 // This is in widget coordinates, i.e. relative to the widget's top
 // left corner, not in screen coordinates, the same units that
--- a/dom/events/test/test_bug648573.html
+++ b/dom/events/test/test_bug648573.html
@@ -69,18 +69,16 @@ ok(e.metaKey, "Meta should be true");
 ok(e.ctrlKey, "Ctrl should be true");
 ok(e.shiftKey, "Shift should be true");
 
 
 var events =
   ["touchstart",
    "touchend",
    "touchmove",
-   "touchenter",
-   "touchleave",
    "touchcancel"];
 
 function runEventTest(type) {
   var e = document.createEvent("touchevent");
   e.initTouchEvent(type, true, true, window, 0, true, true, true, true,
                    l1, l2, l3);
   var t = document.createElement("div");
   // Testing target.onFoo;
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -46,17 +46,17 @@ interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 interface nsITranslationNodeList;
 interface nsIJSRAIIHelper;
 interface nsIContentPermissionRequest;
 
-[scriptable, uuid(0ef9e8bb-b934-4f6b-ae05-e98774d8d3d3)]
+[scriptable, uuid(11911980-607c-4efd-aacc-de3b9005c058)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -366,18 +366,18 @@ interface nsIDOMWindowUtils : nsISupport
                            in long aClickCount,
                            in long aModifiers,
                            [optional] in boolean aIgnoreRootScrollFrame,
                            [optional] in float aPressure,
                            [optional] in unsigned short aInputSourceArg,
                            [optional] in long aPointerId,
                            [optional] in long aWidth,
                            [optional] in long aHeight,
-                           [optional] in long tiltX,
-                           [optional] in long tiltY,
+                           [optional] in long aTiltX,
+                           [optional] in long aTiltY,
                            [optional] in boolean aIsPrimary,
                            [optional] in boolean aIsSynthesized);
 
   /** Synthesize a touch event. The event types supported are:
    *    touchstart, touchend, touchmove, and touchcancel
    *
    * Events are sent in coordinates offset by aX and aY from the window.
    *
@@ -424,16 +424,37 @@ interface nsIDOMWindowUtils : nsISupport
                               in long aButton,
                               in long aClickCount,
                               in long aModifiers,
                               [optional] in boolean aIgnoreRootScrollFrame,
                               [optional] in float aPressure,
                               [optional] in unsigned short aInputSourceArg,
                               [optional] in boolean aIsSynthesized);
 
+  /** The same as sendPointerEvent but ensures that the event
+   *  is dispatched to this DOM window or one of its children.
+   */
+  [optional_argc]
+  void sendPointerEventToWindow(in AString aType,
+                                in float aX,
+                                in float aY,
+                                in long aButton,
+                                in long aClickCount,
+                                in long aModifiers,
+                                [optional] in boolean aIgnoreRootScrollFrame,
+                                [optional] in float aPressure,
+                                [optional] in unsigned short aInputSourceArg,
+                                [optional] in long aPointerId,
+                                [optional] in long aWidth,
+                                [optional] in long aHeight,
+                                [optional] in long aTiltX,
+                                [optional] in long aTiltY,
+                                [optional] in boolean aIsPrimary,
+                                [optional] in boolean aIsSynthesized);
+
   /** The same as sendTouchEvent but ensures that the event is dispatched to
    *  this DOM window or one of its children.
    */
   boolean sendTouchEventToWindow(in AString aType,
                                  [array, size_is(count)] in uint32_t aIdentifiers,
                                  [array, size_is(count)] in int32_t aXs,
                                  [array, size_is(count)] in int32_t aYs,
                                  [array, size_is(count)] in uint32_t aRxs,
--- a/dom/interfaces/events/nsIDOMTouchEvent.idl
+++ b/dom/interfaces/events/nsIDOMTouchEvent.idl
@@ -10,12 +10,10 @@
 %}
 interface nsIVariant;
 
 [scriptable, uuid(6d5484f7-92ac-45f8-9388-39b5bad055ce)]
 interface nsITouchEventReceiver : nsISupports {
   [implicit_jscontext] attribute jsval           ontouchstart;
   [implicit_jscontext] attribute jsval           ontouchend;
   [implicit_jscontext] attribute jsval           ontouchmove;
-  [implicit_jscontext] attribute jsval           ontouchenter;
-  [implicit_jscontext] attribute jsval           ontouchleave;
   [implicit_jscontext] attribute jsval           ontouchcancel;
 };
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -18,16 +18,17 @@
 #include "nsIScriptGlobalObject.h"
 #include "nsIPermissionManager.h"
 #include "nsIPopupWindowManager.h"
 #include "nsISupportsArray.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIInterfaceRequestorUtils.h"
+#include "nsNetUtil.h"
 #include "mozilla/Types.h"
 #include "mozilla/PeerIdentity.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/GetUserMediaRequestBinding.h"
 #include "mozilla/Preferences.h"
 #include "MediaTrackConstraints.h"
@@ -1472,23 +1473,38 @@ MediaManager::GetUserMedia(bool aPrivile
 
 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
   if (c.mPicture) {
     // ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
     NS_DispatchToMainThread(runnable);
     return NS_OK;
   }
 #endif
+  nsIURI* docURI = aWindow->GetDocumentURI();
+#ifdef MOZ_LOOP
+  {
+    bool isLoop = false;
+    nsCOMPtr<nsIURI> loopURI;
+    nsresult rv = NS_NewURI(getter_AddRefs(loopURI), "about:loopconversation");
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = docURI->EqualsExceptRef(loopURI, &isLoop);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (isLoop) {
+      aPrivileged = true;
+    }
+  }
+#endif
+
   // XXX No full support for picture in Desktop yet (needs proper UI)
   if (aPrivileged ||
       (c.mFake && !Preferences::GetBool("media.navigator.permission.fake"))) {
     mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
   } else {
     bool isHTTPS = false;
-    nsIURI* docURI = aWindow->GetDocumentURI();
     if (docURI) {
       docURI->SchemeIs("https", &isHTTPS);
     }
 
     // Check if this site has persistent permissions.
     nsresult rv;
     nsCOMPtr<nsIPermissionManager> permManager =
       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
--- a/dom/webidl/HTMLElement.webidl
+++ b/dom/webidl/HTMLElement.webidl
@@ -106,20 +106,16 @@ partial interface HTMLElement {
 interface TouchEventHandlers {
   [Func="nsGenericHTMLElement::TouchEventsEnabled"]
            attribute EventHandler ontouchstart;
   [Func="nsGenericHTMLElement::TouchEventsEnabled"]
            attribute EventHandler ontouchend;
   [Func="nsGenericHTMLElement::TouchEventsEnabled"]
            attribute EventHandler ontouchmove;
   [Func="nsGenericHTMLElement::TouchEventsEnabled"]
-           attribute EventHandler ontouchenter;
-  [Func="nsGenericHTMLElement::TouchEventsEnabled"]
-           attribute EventHandler ontouchleave;
-  [Func="nsGenericHTMLElement::TouchEventsEnabled"]
            attribute EventHandler ontouchcancel;
 };
 
 HTMLElement implements GlobalEventHandlers;
 HTMLElement implements TouchEventHandlers;
 HTMLElement implements OnErrorEventHandlerForNodes;
 
 interface HTMLUnknownElement : HTMLElement {};
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -129,17 +129,17 @@ interface XMLHttpRequest : XMLHttpReques
   [Throws]
   readonly attribute DOMString? responseText;
 
   [Throws=MainThread]
   readonly attribute Document? responseXML;
 
   // Mozilla-specific stuff
 
-  [SetterThrows=Workers]
+  [ChromeOnly, SetterThrows=Workers]
   attribute boolean mozBackgroundRequest;
 
   [ChromeOnly]
   readonly attribute MozChannel? channel;
 
   [Throws]
   void sendAsBinary(DOMString body);
   [Throws, ChromeOnly]
--- a/dom/xbl/test/file_bug821850.xhtml
+++ b/dom/xbl/test/file_bug821850.xhtml
@@ -100,24 +100,22 @@ https://bugzilla.mozilla.org/show_bug.cg
           <body>
             return "method:" + arg;
           </body>
         </method>
         <method name="passMeAJSObject" exposeToUntrustedContent="true">
           <parameter name="arg" />
           <body>
             is(typeof arg.prop, 'undefined', "No properties");
+            is(arg.wrappedJSObject.prop, 2, "Underlying object has properties");
             is(Object.getOwnPropertyNames(arg).length, 0, "Should have no own properties");
-            try {
-              arg.foo = 2;
-              ok(true, "Stuff fails silently");
-            } catch (e) {
-              ok(false, "Stuff should fail silently");
-            }
-            is(typeof arg.foo, 'undefined', "Shouldn't place props");
+            is(Object.getOwnPropertyNames(arg.wrappedJSObject).length, 1, "Underlying object has properties");
+            arg.foo = 2;
+            is(arg.foo, 2, "Should place expandos");
+            is(typeof arg.wrappedJSObject.foo, 'undefined', "Expandos should be invisible to content");
           </body>
         </method>
         <property name="prop" exposeToUntrustedContent="true">
           <getter>return this._prop;</getter>
           <setter>this._prop = "set:" + val;</setter>
         </property>
       </implementation>
       <handlers>
--- a/gfx/cairo/cairo/src/cairo-clip.c
+++ b/gfx/cairo/cairo/src/cairo-clip.c
@@ -949,60 +949,50 @@ static cairo_int_status_t
 }
 
 static cairo_surface_t *
 _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
 			      cairo_surface_t *target,
 			      int *tx, int *ty)
 {
     const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
-    cairo_rectangle_int_t surface_extents;
     cairo_bool_t need_translate;
     cairo_surface_t *surface;
     cairo_clip_path_t *prev;
     cairo_status_t status;
 
     while (clip_path->prev != NULL &&
 	   clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
 	   clip_path->path.maybe_fill_region)
     {
 	clip_path = clip_path->prev;
     }
 
     clip_extents = &clip_path->extents;
-    if (_cairo_surface_get_extents (target, &surface_extents))
-    {
-    	_cairo_rectangle_intersect(&surface_extents, clip_extents);
-    }
-    else
-    {
-    	surface_extents = *clip_extents;
-    }
-
     if (clip_path->surface != NULL &&
 	clip_path->surface->backend == target->backend)
     {
-	*tx = surface_extents.x;
-	*ty = surface_extents.y;
+	*tx = clip_extents->x;
+	*ty = clip_extents->y;
 	return clip_path->surface;
     }
 
     surface = _cairo_surface_create_similar_scratch (target,
 						     CAIRO_CONTENT_ALPHA,
-						     surface_extents.width,
-						     surface_extents.height);
+						     clip_extents->width,
+						     clip_extents->height);
     if (surface == NULL) {
 	surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
-					      surface_extents.width,
-					      surface_extents.height);
+					      clip_extents->width,
+					      clip_extents->height);
     }
     if (unlikely (surface->status))
 	return surface;
 
-    need_translate = surface_extents.x | surface_extents.y;
+    need_translate = clip_extents->x | clip_extents->y;
     if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
 	clip_path->path.maybe_fill_region)
     {
 	status = _cairo_surface_paint (surface,
 				       CAIRO_OPERATOR_SOURCE,
 				       &_cairo_pattern_white.base,
 				       NULL);
 	if (unlikely (status))
@@ -1014,31 +1004,31 @@ static cairo_surface_t *
 				       CAIRO_OPERATOR_CLEAR,
 				       &_cairo_pattern_clear.base,
 				       NULL);
 	if (unlikely (status))
 	    goto BAIL;
 
 	if (need_translate) {
 	    _cairo_path_fixed_translate (&clip_path->path,
-					 _cairo_fixed_from_int (-surface_extents.x),
-					 _cairo_fixed_from_int (-surface_extents.y));
+					 _cairo_fixed_from_int (-clip_extents->x),
+					 _cairo_fixed_from_int (-clip_extents->y));
 	}
 	status = _cairo_surface_fill (surface,
 				      CAIRO_OPERATOR_ADD,
 				      &_cairo_pattern_white.base,
 				      &clip_path->path,
 				      clip_path->fill_rule,
 				      clip_path->tolerance,
 				      clip_path->antialias,
 				      NULL);
 	if (need_translate) {
 	    _cairo_path_fixed_translate (&clip_path->path,
-					 _cairo_fixed_from_int (surface_extents.x),
-					 _cairo_fixed_from_int (surface_extents.y));
+					 _cairo_fixed_from_int (clip_extents->x),
+					 _cairo_fixed_from_int (clip_extents->y));
 	}
 
 	if (unlikely (status))
 	    goto BAIL;
     }
 
     prev = clip_path->prev;
     while (prev != NULL) {
@@ -1048,31 +1038,31 @@ static cairo_surface_t *
 	    /* a simple box only affects the extents */
 	}
 	else if (prev->path.is_rectilinear ||
 		prev->surface == NULL ||
 		prev->surface->backend != target->backend)
 	{
 	    if (need_translate) {
 		_cairo_path_fixed_translate (&prev->path,
-					     _cairo_fixed_from_int (-surface_extents.x),
-					     _cairo_fixed_from_int (-surface_extents.y));
+					     _cairo_fixed_from_int (-clip_extents->x),
+					     _cairo_fixed_from_int (-clip_extents->y));
 	    }
 	    status = _cairo_surface_fill (surface,
 					  CAIRO_OPERATOR_IN,
 					  &_cairo_pattern_white.base,
 					  &prev->path,
 					  prev->fill_rule,
 					  prev->tolerance,
 					  prev->antialias,
 					  NULL);
 	    if (need_translate) {
 		_cairo_path_fixed_translate (&prev->path,
-					     _cairo_fixed_from_int (surface_extents.x),
-					     _cairo_fixed_from_int (surface_extents.y));
+					     _cairo_fixed_from_int (clip_extents->x),
+					     _cairo_fixed_from_int (clip_extents->y));
 	    }
 
 	    if (unlikely (status))
 		goto BAIL;
 	}
 	else
 	{
 	    cairo_surface_pattern_t pattern;
@@ -1082,35 +1072,35 @@ static cairo_surface_t *
 	    prev_surface = _cairo_clip_path_get_surface (prev, target, &prev_tx, &prev_ty);
 	    status = prev_surface->status;
 	    if (unlikely (status))
 		goto BAIL;
 
 	    _cairo_pattern_init_for_surface (&pattern, prev_surface);
 	    pattern.base.filter = CAIRO_FILTER_NEAREST;
 	    cairo_matrix_init_translate (&pattern.base.matrix,
-					 surface_extents.x - prev_tx,
-					 surface_extents.y - prev_ty);
+					 clip_extents->x - prev_tx,
+					 clip_extents->y - prev_ty);
 	    status = _cairo_surface_paint (surface,
 					   CAIRO_OPERATOR_IN,
 					   &pattern.base,
 					   NULL);
 	    _cairo_pattern_fini (&pattern.base);
 
 	    if (unlikely (status))
 		goto BAIL;
 
 	    break;
 	}
 
 	prev = prev->prev;
     }
 
-    *tx = surface_extents.x;
-    *ty = surface_extents.y;
+    *tx = clip_extents->x;
+    *ty = clip_extents->y;
     cairo_surface_destroy (clip_path->surface);
     return clip_path->surface = surface;
 
   BAIL:
     cairo_surface_destroy (surface);
     return _cairo_surface_create_in_error (status);
 }
 
--- a/gfx/cairo/cairo/src/cairo-type1-subset.c
+++ b/gfx/cairo/cairo/src/cairo-type1-subset.c
@@ -865,16 +865,19 @@ cairo_type1_font_subset_look_for_seac(ca
 	    switch (command) {
 	    case TYPE1_CHARSTRING_COMMAND_SEAC:
 		/* The seac command takes five integer arguments.  The
 		 * last two are glyph indices into the PS standard
 		 * encoding give the names of the glyphs that this
 		 * glyph is composed from.  All we need to do is to
 		 * make sure those glyphs are present in the subset
 		 * under their standard names. */
+		if (unlikely (sp < 5))
+		    return CAIRO_INT_STATUS_UNSUPPORTED;
+
 		status = use_standard_encoding_glyph (font, stack[3]);
 		if (unlikely (status))
 		    return status;
 
 		status = use_standard_encoding_glyph (font, stack[4]);
 		if (unlikely (status))
 		    return status;
 
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -632,25 +632,24 @@ CairoImage::GetTextureClient(Compositabl
   RefPtr<SourceSurface> surface = GetAsSourceSurface();
   MOZ_ASSERT(surface);
   if (!surface) {
     return nullptr;
   }
 
   // gfx::BackendType::NONE means default to content backend
   textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
-                                                         TextureFlags::DEFAULT,
+                                                         surface->GetSize(),
                                                          gfx::BackendType::NONE,
-                                                         surface->GetSize());
+                                                         TextureFlags::DEFAULT);
   if (!textureClient) {
     return nullptr;
   }
   MOZ_ASSERT(textureClient->CanExposeDrawTarget());
-  if (!textureClient->AllocateForSurface(surface->GetSize()) ||
-      !textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
+  if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
     return nullptr;
   }
 
   TextureClientAutoUnlock autoUnolck(textureClient);
   {
     // We must not keep a reference to the DrawTarget after it has been unlocked.
     DrawTarget* dt = textureClient->BorrowDrawTarget();
     if (!dt) {
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -1616,35 +1616,12 @@ SetAntialiasingFlags(Layer* aLayer, Draw
   transformedBounds.RoundOut();
   IntRect intTransformedBounds;
   transformedBounds.ToIntRect(&intTransformedBounds);
   permitSubpixelAA &= !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
                       aTarget->GetOpaqueRect().Contains(intTransformedBounds);
   aTarget->SetPermitSubpixelAA(permitSubpixelAA);
 }
 
-void
-SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget)
-{
-  if (!aTarget->IsCairo()) {
-    SetAntialiasingFlags(aLayer, aTarget->GetDrawTarget());
-    return;
-  }
-
-  bool permitSubpixelAA = !(aLayer->GetContentFlags() & Layer::CONTENT_DISABLE_SUBPIXEL_AA);
-  nsRefPtr<gfxASurface> surface = aTarget->CurrentSurface();
-  if (surface->GetContentType() != gfxContentType::COLOR_ALPHA) {
-    // Destination doesn't have alpha channel; no need to set any special flags
-    surface->SetSubpixelAntialiasingEnabled(permitSubpixelAA);
-    return;
-  }
-
-  const nsIntRect& bounds = aLayer->GetVisibleRegion().GetBounds();
-  permitSubpixelAA &= !(aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) ||
-      surface->GetOpaqueRect().Contains(
-      aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
-  surface->SetSubpixelAntialiasingEnabled(permitSubpixelAA);
-}
-
 PRLogModuleInfo* LayerManager::sLog;
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -2173,17 +2173,16 @@ protected:
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
 
   Layer* mTempReferent;
   // 0 is a special value that means "no ID".
   uint64_t mId;
 };
 
-void SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget);
 void SetAntialiasingFlags(Layer* aLayer, gfx::DrawTarget* aTarget);
 
 #ifdef MOZ_DUMP_PAINTING
 void WriteSnapshotToDumpFile(Layer* aLayer, gfx::DataSourceSurface* aSurf);
 void WriteSnapshotToDumpFile(LayerManager* aManager, gfx::DataSourceSurface* aSurf);
 void WriteSnapshotToDumpFile(Compositor* aCompositor, gfx::DrawTarget* aTarget);
 #endif
 
--- a/gfx/layers/apz/src/GestureEventListener.cpp
+++ b/gfx/layers/apz/src/GestureEventListener.cpp
@@ -69,33 +69,31 @@ nsEventStatus GestureEventListener::Hand
   nsEventStatus rv = nsEventStatus_eIgnore;
 
   // Cache the current event since it may become the single or long tap that we
   // send.
   mLastTouchInput = aEvent;
 
   switch (aEvent.mType) {
   case MultiTouchInput::MULTITOUCH_START:
-  case MultiTouchInput::MULTITOUCH_ENTER:
     mTouches.Clear();
     for (size_t i = 0; i < aEvent.mTouches.Length(); i++) {
       mTouches.AppendElement(aEvent.mTouches[i]);
     }
 
     if (aEvent.mTouches.Length() == 1) {
       rv = HandleInputTouchSingleStart();
     } else {
       rv = HandleInputTouchMultiStart();
     }
     break;
   case MultiTouchInput::MULTITOUCH_MOVE:
     rv = HandleInputTouchMove();
     break;
   case MultiTouchInput::MULTITOUCH_END:
-  case MultiTouchInput::MULTITOUCH_LEAVE:
     for (size_t i = 0; i < aEvent.mTouches.Length(); i++) {
       for (size_t j = 0; j < mTouches.Length(); j++) {
         if (aEvent.mTouches[i].mIdentifier == mTouches[j].mIdentifier) {
           mTouches.RemoveElementAt(j);
           break;
         }
       }
     }
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -91,17 +91,16 @@ BasicLayerManager::PushGroupForLayer(gfx
   if (aLayer->CanUseOpaqueSurface() &&
       ((didCompleteClip && aRegion.GetNumRects() == 1) ||
        !aContext->CurrentMatrix().HasNonIntegerTranslation())) {
     // If the layer is opaque in its visible region we can push a gfxContentType::COLOR
     // group. We need to make sure that only pixels inside the layer's visible
     // region are copied back to the destination. Remember if we've already
     // clipped precisely to the visible region.
     *aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1;
-    MOZ_ASSERT(!aContext->IsCairo());
     aContext->PushGroup(gfxContentType::COLOR);
     result = aContext;
   } else {
     *aNeedsClipToVisibleRegion = false;
     result = aContext;
     if (aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) {
       aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA);
     } else {
@@ -170,61 +169,41 @@ public:
   }
 
   // Set the opaque rect to match the bounds of the visible region.
   void AnnotateOpaqueRect()
   {
     const nsIntRegion& visibleRegion = mLayer->GetEffectiveVisibleRegion();
     const nsIntRect& bounds = visibleRegion.GetBounds();
 
-    if (mTarget->IsCairo()) {
-      nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
-      const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
+    DrawTarget *dt = mTarget->GetDrawTarget();
+    const IntRect& targetOpaqueRect = dt->GetOpaqueRect();
 
-      // Try to annotate currentSurface with a region of pixels that have been
-      // (or will be) painted opaque, if no such region is currently set.
-      if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
-          (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
-          !mTransform.HasNonAxisAlignedTransform()) {
-        currentSurface->SetOpaqueRect(
-            mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
+    // Try to annotate currentSurface with a region of pixels that have been
+    // (or will be) painted opaque, if no such region is currently set.
+    if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
+        (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
+        !mTransform.HasNonAxisAlignedTransform()) {
+
+      gfx::Rect opaqueRect = dt->GetTransform().TransformBounds(
+        gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
+      opaqueRect.RoundIn();
+      IntRect intOpaqueRect;
+      if (opaqueRect.ToIntRect(&intOpaqueRect)) {
+        mTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
         mPushedOpaqueRect = true;
       }
-    } else {
-      DrawTarget *dt = mTarget->GetDrawTarget();
-      const IntRect& targetOpaqueRect = dt->GetOpaqueRect();
-
-      // Try to annotate currentSurface with a region of pixels that have been
-      // (or will be) painted opaque, if no such region is currently set.
-      if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
-          (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
-          !mTransform.HasNonAxisAlignedTransform()) {
-
-        gfx::Rect opaqueRect = dt->GetTransform().TransformBounds(
-          gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
-        opaqueRect.RoundIn();
-        IntRect intOpaqueRect;
-        if (opaqueRect.ToIntRect(&intOpaqueRect)) {
-          mTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
-          mPushedOpaqueRect = true;
-        }
-      }
     }
   }
 
   // Clear the Opaque rect. Although this doesn't really restore it to it's
   // previous state it will happen on the exit path of the PaintLayer() so when
   // painting is complete the opaque rect qill be clear.
   void ClearOpaqueRect() {
-    if (mTarget->IsCairo()) {
-      nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
-      currentSurface->SetOpaqueRect(gfxRect());
-    } else {
-      mTarget->GetDrawTarget()->SetOpaqueRect(IntRect());
-    }
+    mTarget->GetDrawTarget()->SetOpaqueRect(IntRect());
   }
 
   gfxContext* mTarget;
   gfxContextMatrixAutoSaveRestore mTargetMatrixSR;
   Layer* mLayer;
   LayerManager::DrawThebesLayerCallback mCallback;
   void* mCallbackData;
   Matrix mTransform;
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -85,17 +85,17 @@ BasicThebesLayer::PaintThebes(gfxContext
           BasicManager()->PushGroupForLayer(aContext, this, toDraw,
                                             &needsClipToVisibleRegion);
         if (effectiveOperator != CompositionOp::OP_OVER) {
           needsClipToVisibleRegion = true;
         }
       } else {
         groupContext = aContext;
       }
-      SetAntialiasingFlags(this, groupContext);
+      SetAntialiasingFlags(this, groupContext->GetDrawTarget());
       aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData);
       if (needsGroup) {
         aContext->PopGroupToSource();
         if (needsClipToVisibleRegion) {
           gfxUtils::ClipToRegion(aContext, toDraw);
         }
         AutoSetOperator setOptimizedOperator(aContext, ThebesOp(effectiveOperator));
         PaintWithMask(aContext, opacity, aMaskLayer);
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -69,18 +69,21 @@ CanvasClient2D::Update(gfx::IntSize aSiz
       = gfxPlatform::GetPlatform()->OptimalFormatForContent(contentType);
     TextureFlags flags = TextureFlags::DEFAULT;
     if (mTextureFlags & TextureFlags::NEEDS_Y_FLIP) {
       flags |= TextureFlags::NEEDS_Y_FLIP;
     }
 
     gfx::SurfaceFormat surfaceFormat = gfx::ImageFormatToSurfaceFormat(format);
     mBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aLayer);
+    if (!mBuffer) {
+      NS_WARNING("Failed to allocate the TextureClient");
+      return;
+    }
     MOZ_ASSERT(mBuffer->CanExposeDrawTarget());
-    mBuffer->AllocateForSurface(aSize);
 
     bufferCreated = true;
   }
 
   if (!mBuffer->Lock(OpenMode::OPEN_WRITE_ONLY)) {
     mBuffer = nullptr;
     return;
   }
@@ -113,26 +116,30 @@ CanvasClient2D::CreateTextureClientForCa
                                              gfx::IntSize aSize,
                                              TextureFlags aFlags,
                                              ClientCanvasLayer* aLayer)
 {
   if (aLayer->IsGLLayer()) {
     // We want a cairo backend here as we don't want to be copying into
     // an accelerated backend and we like LockBits to work. This is currently
     // the most effective way to make this work.
-    return CreateBufferTextureClient(aFormat, aFlags, BackendType::CAIRO);
+    return TextureClient::CreateForRawBufferAccess(GetForwarder(),
+                                                   aFormat, aSize, BackendType::CAIRO,
+                                                   mTextureInfo.mTextureFlags | aFlags);
   }
 
   gfx::BackendType backend = gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
 #ifdef XP_WIN
-  return CreateTextureClientForDrawing(aFormat, aFlags, backend, aSize);
+  return CreateTextureClientForDrawing(aFormat, aSize, backend, aFlags);
 #else
   // XXX - We should use CreateTextureClientForDrawing, but we first need
   // to use double buffering.
-  return CreateBufferTextureClient(aFormat, aFlags, backend);
+  return TextureClient::CreateForRawBufferAccess(GetForwarder(),
+                                                 aFormat, aSize, backend,
+                                                 mTextureInfo.mTextureFlags | aFlags);
 #endif
 }
 
 CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder,
                                                      TextureFlags aFlags)
   : CanvasClient(aLayerForwarder, aFlags)
 {
 }
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -96,20 +96,21 @@ public:
   }
 
   virtual void OnDetach() MOZ_OVERRIDE
   {
     mBuffer = nullptr;
   }
 
 private:
-  TemporaryRef<TextureClient> CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
-                                                           gfx::IntSize aSize,
-                                                           TextureFlags aFlags,
-                                                           ClientCanvasLayer* aLayer);
+  TemporaryRef<TextureClient>
+    CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
+                                 gfx::IntSize aSize,
+                                 TextureFlags aFlags,
+                                 ClientCanvasLayer* aLayer);
 
   RefPtr<TextureClient> mBuffer;
 };
 
 // Used for GL canvases where we don't need to do any readback, i.e., with a
 // GL backend.
 class CanvasClientSurfaceStream : public CanvasClient
 {
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -186,25 +186,26 @@ CompositableClient::CreateBufferTextureC
                                               gfx::BackendType aMoz2DBackend)
 {
   return TextureClient::CreateBufferTextureClient(GetForwarder(), aFormat,
                                                   aTextureFlags | mTextureFlags,
                                                   aMoz2DBackend);
 }
 
 TemporaryRef<TextureClient>
-CompositableClient::CreateTextureClientForDrawing(SurfaceFormat aFormat,
+CompositableClient::CreateTextureClientForDrawing(gfx::SurfaceFormat aFormat,
+                                                  gfx::IntSize aSize,
+                                                  gfx::BackendType aMoz2DBackend,
                                                   TextureFlags aTextureFlags,
-                                                  gfx::BackendType aMoz2DBackend,
-                                                  const IntSize& aSizeHint)
+                                                  TextureAllocationFlags aAllocFlags)
 {
-  return TextureClient::CreateTextureClientForDrawing(GetForwarder(), aFormat,
-                                                      aTextureFlags | mTextureFlags,
-                                                      aMoz2DBackend,
-                                                      aSizeHint);
+  return TextureClient::CreateForDrawing(GetForwarder(),
+                                         aFormat, aSize, aMoz2DBackend,
+                                         aTextureFlags | mTextureFlags,
+                                         aAllocFlags);
 }
 
 bool
 CompositableClient::AddTextureClient(TextureClient* aClient)
 {
   if(!aClient || !aClient->IsAllocated()) {
     return false;
   }
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -129,19 +129,20 @@ public:
 
   TemporaryRef<BufferTextureClient>
   CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
                             TextureFlags aFlags = TextureFlags::DEFAULT,
                             gfx::BackendType aMoz2dBackend = gfx::BackendType::NONE);
 
   TemporaryRef<TextureClient>
   CreateTextureClientForDrawing(gfx::SurfaceFormat aFormat,
+                                gfx::IntSize aSize,
+                                gfx::BackendType aMoz2DBackend,
                                 TextureFlags aTextureFlags,
-                                gfx::BackendType aMoz2dBackend,
-                                const gfx::IntSize& aSizeHint);
+                                TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
 
   virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
                                       const SurfaceDescriptor& aDescriptor)
   {
     MOZ_CRASH("If you want to call this, you should have implemented it");
   }
 
   /**
@@ -220,16 +221,18 @@ public:
   void InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID = 0);
 
   static void TransactionCompleteted(PCompositableChild* aActor, uint64_t aTransactionId);
 
   static void HoldUntilComplete(PCompositableChild* aActor, AsyncTransactionTracker* aTracker);
 
   static uint64_t GetTrackersHolderId(PCompositableChild* aActor);
 
+  TextureFlags GetTextureFlags() const { return mTextureFlags; }
+
 protected:
   CompositableChild* mCompositableChild;
   CompositableForwarder* mForwarder;
   // Some layers may want to enforce some flags to all their textures
   // (like disallowing tiling)
   TextureFlags mTextureFlags;
 
   friend class CompositableChild;
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -184,43 +184,38 @@ ContentClientRemoteBuffer::EndPaint()
   }
   ContentClientRemote::EndPaint();
 }
 
 bool
 ContentClientRemoteBuffer::CreateAndAllocateTextureClient(RefPtr<TextureClient>& aClient,
                                                           TextureFlags aFlags)
 {
-  // gfx::BackendType::NONE means fallback to the content backend
-  aClient = CreateTextureClientForDrawing(mSurfaceFormat,
-                                          mTextureInfo.mTextureFlags | aFlags,
-                                          gfx::BackendType::NONE,
-                                          mSize);
-  if (!aClient) {
-    return false;
-  }
-
-  TextureAllocationFlags flags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
+  TextureAllocationFlags allocFlags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
   if (aFlags & TextureFlags::ON_WHITE) {
-    flags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE;
+    allocFlags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE;
   }
 
-  if (!aClient->AllocateForSurface(mSize, flags)) {
-    aClient = CreateTextureClientForDrawing(mSurfaceFormat,
-                mTextureInfo.mTextureFlags | TextureFlags::ALLOC_FALLBACK | aFlags,
-                gfx::BackendType::NONE,
-                mSize);
-    if (!aClient) {
-      return false;
-    }
-    if (!aClient->AllocateForSurface(mSize, flags)) {
-      NS_WARNING("Could not allocate texture client");
-      aClient = nullptr;
-      return false;
-    }
+  // gfx::BackendType::NONE means fallback to the content backend
+  aClient = CreateTextureClientForDrawing(mSurfaceFormat, mSize,
+                                          gfx::BackendType::NONE,
+                                          mTextureInfo.mTextureFlags | aFlags,
+                                          allocFlags);
+  if (!aClient) {
+    // try with ALLOC_FALLBACK
+    aClient = CreateTextureClientForDrawing(mSurfaceFormat, mSize,
+                                            gfx::BackendType::NONE,
+                                            mTextureInfo.mTextureFlags
+                                            | TextureFlags::ALLOC_FALLBACK
+                                            | aFlags,
+                                            allocFlags);
+  }
+
+  if (!aClient) {
+    return false;
   }
 
   NS_WARN_IF_FALSE(aClient->IsValid(), "Created an invalid texture client");
   return true;
 }
 
 void
 ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -271,24 +271,22 @@ ImageClientSingle::UpdateImageInternal(I
       autoRemoveTexture.mTexture = mFrontBuffer;
       mFrontBuffer = nullptr;
     }
 
     bool bufferCreated = false;
     if (!mFrontBuffer) {
       gfxImageFormat format
         = gfxPlatform::GetPlatform()->OptimalFormatForContent(gfx::ContentForFormat(surface->GetFormat()));
-      mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format),
-                                                   mTextureFlags, gfx::BackendType::NONE, size);
-      MOZ_ASSERT(mFrontBuffer->CanExposeDrawTarget());
-      if (!mFrontBuffer->AllocateForSurface(size)) {
-        mFrontBuffer = nullptr;
+      mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format), size,
+                                                   gfx::BackendType::NONE, mTextureFlags);
+      if (!mFrontBuffer) {
         return false;
       }
-
+      MOZ_ASSERT(mFrontBuffer->CanExposeDrawTarget());
       bufferCreated = true;
     }
 
     if (!mFrontBuffer->Lock(OpenMode::OPEN_WRITE_ONLY)) {
       mFrontBuffer = nullptr;
       return false;
     }
 
--- a/gfx/layers/client/SimpleTextureClientPool.cpp
+++ b/gfx/layers/client/SimpleTextureClientPool.cpp
@@ -67,22 +67,22 @@ SimpleTextureClientPool::GetTextureClien
     mAvailableTextureClients.pop();
     RECYCLE_LOG("%s Skip allocate (%i left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.size(), textureClient.get());
 
   } else {
     // No unused clients in the pool, create one
     if (gfxPrefs::ForceShmemTiles()) {
       textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator,
         mFormat, TextureFlags::IMMEDIATE_UPLOAD | TextureFlags::RECYCLE, gfx::BackendType::NONE);
+      if (!textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT)) {
+        NS_WARNING("TextureClient::AllocateForSurface failed!");
+      }
     } else {
-      textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator,
-        mFormat, TextureFlags::DEFAULT | TextureFlags::RECYCLE, gfx::BackendType::NONE, mSize);
-    }
-    if (!textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT)) {
-      NS_WARNING("TextureClient::AllocateForSurface failed!");
+      textureClient = TextureClient::CreateForDrawing(mSurfaceAllocator,
+        mFormat, mSize, gfx::BackendType::NONE, TextureFlags::DEFAULT | TextureFlags::RECYCLE);
     }
     RECYCLE_LOG("%s Must allocate (0 left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), textureClient.get());
   }
 
   if (aAutoRecycle) {
     mOutstandingTextureClients.push_back(textureClient);
     textureClient->SetRecycleCallback(SimpleTextureClientPool::WaitForCompositorRecycleCallback, this);
   }
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -230,23 +230,23 @@ DisableGralloc(SurfaceFormat aFormat, co
     return true;
   }
 #endif
 
   return false;
 }
 #endif
 
-// static
+static
 TemporaryRef<TextureClient>
-TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
-                                             SurfaceFormat aFormat,
-                                             TextureFlags aTextureFlags,
-                                             gfx::BackendType aMoz2DBackend,
-                                             const gfx::IntSize& aSizeHint)
+CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
+                              SurfaceFormat aFormat,
+                              TextureFlags aTextureFlags,
+                              gfx::BackendType aMoz2DBackend,
+                              const gfx::IntSize& aSizeHint)
 {
   if (aMoz2DBackend == gfx::BackendType::NONE) {
     aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend();
   }
 
   RefPtr<TextureClient> result;
 
 #if defined(MOZ_WIDGET_GONK) || defined(XP_WIN)
@@ -310,24 +310,92 @@ TextureClient::CreateTextureClientForDra
       result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend,
                                            aTextureFlags);
     }
   }
 #endif
 
   // Can't do any better than a buffer texture client.
   if (!result) {
-    result = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, aMoz2DBackend);
+    result = TextureClient::CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, aMoz2DBackend);
   }
 
   MOZ_ASSERT(!result || result->CanExposeDrawTarget(), "texture cannot expose a DrawTarget?");
   return result;
 }
 
 // static
+TemporaryRef<TextureClient>
+TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
+                                gfx::SurfaceFormat aFormat,
+                                gfx::IntSize aSize,
+                                gfx::BackendType aMoz2DBackend,
+                                TextureFlags aTextureFlags,
+                                TextureAllocationFlags aAllocFlags)
+{
+  RefPtr<TextureClient> texture =
+    CreateTextureClientForDrawing(aAllocator, aFormat,
+                                  aTextureFlags, aMoz2DBackend,
+                                  aSize);
+  if (texture) {
+    if (!texture->AllocateForSurface(aSize, aAllocFlags)) {
+      return nullptr;
+    }
+  }
+  return texture;
+}
+
+// static
+TemporaryRef<BufferTextureClient>
+TextureClient::CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
+                                        gfx::SurfaceFormat aFormat,
+                                        gfx::IntSize aSize,
+                                        gfx::BackendType aMoz2DBackend,
+                                        TextureFlags aTextureFlags,
+                                        TextureAllocationFlags aAllocFlags)
+{
+  RefPtr<BufferTextureClient> texture =
+    CreateBufferTextureClient(aAllocator, aFormat,
+                              aTextureFlags, aMoz2DBackend);
+  if (texture) {
+    if (!texture->AllocateForSurface(aSize, aAllocFlags)) {
+      return nullptr;
+    }
+  }
+  return texture;
+}
+
+// static
+TemporaryRef<BufferTextureClient>
+TextureClient::CreateForYCbCr(ISurfaceAllocator* aAllocator,
+                              gfx::IntSize aYSize,
+                              gfx::IntSize aCbCrSize,
+                              StereoMode aStereoMode,
+                              TextureFlags aTextureFlags)
+{
+  RefPtr<BufferTextureClient> texture;
+  if (aAllocator->IsSameProcess()) {
+    texture = new MemoryTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
+                                      gfx::BackendType::NONE,
+                                      aTextureFlags);
+  } else {
+    texture = new ShmemTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
+                                     gfx::BackendType::NONE,
+                                     aTextureFlags);
+  }
+
+  if (!texture->AllocateForYCbCr(aYSize, aCbCrSize, aStereoMode)) {
+    return nullptr;
+  }
+
+  return texture;
+}
+
+
+// static
 TemporaryRef<BufferTextureClient>
 TextureClient::CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
                                          SurfaceFormat aFormat,
                                          TextureFlags aTextureFlags,
                                          gfx::BackendType aMoz2DBackend)
 {
   if (aAllocator->IsSameProcess()) {
     RefPtr<BufferTextureClient> result = new MemoryTextureClient(aAllocator, aFormat,
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -115,28 +115,52 @@ public:
  */
 class TextureClient
   : public AtomicRefCountedWithFinalize<TextureClient>
 {
 public:
   TextureClient(TextureFlags aFlags = TextureFlags::DEFAULT);
   virtual ~TextureClient();
 
+  // Creates a TextureClient that can be accessed through a raw pointer.
+  // XXX - this doesn't allocate the texture data.
+  // Prefer CreateForRawBufferAccess which returns a BufferTextureClient
+  // only if allocation suceeded.
   static TemporaryRef<BufferTextureClient>
   CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
                             gfx::SurfaceFormat aFormat,
                             TextureFlags aTextureFlags,
                             gfx::BackendType aMoz2dBackend);
 
+  // Creates and allocates a TextureClient usable with Moz2D.
   static TemporaryRef<TextureClient>
-  CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
-                                gfx::SurfaceFormat aFormat,
-                                TextureFlags aTextureFlags,
-                                gfx::BackendType aMoz2dBackend,
-                                const gfx::IntSize& aSizeHint);
+  CreateForDrawing(ISurfaceAllocator* aAllocator,
+                   gfx::SurfaceFormat aFormat,
+                   gfx::IntSize aSize,
+                   gfx::BackendType aMoz2dBackend,
+                   TextureFlags aTextureFlags,
+                   TextureAllocationFlags flags = ALLOC_DEFAULT);
+
+  // Creates and allocates a BufferTextureClient supporting the YCbCr format.
+  static TemporaryRef<BufferTextureClient>
+  CreateForYCbCr(ISurfaceAllocator* aAllocator,
+                 gfx::IntSize aYSize,
+                 gfx::IntSize aCbCrSize,
+                 StereoMode aStereoMode,
+                 TextureFlags aTextureFlags);
+
+  // Creates and allocates a BufferTextureClient (can beaccessed through raw
+  // pointers).
+  static TemporaryRef<BufferTextureClient>
+  CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
+                           gfx::SurfaceFormat aFormat,
+                           gfx::IntSize aSize,
+                           gfx::BackendType aMoz2dBackend,
+                           TextureFlags aTextureFlags,
+                           TextureAllocationFlags flags = ALLOC_DEFAULT);
 
   virtual TextureClientYCbCr* AsTextureClientYCbCr() { return nullptr; }
 
   /**
    * Locks the shared data, allowing the caller to get access to it.
    *
    * Please always lock/unlock when accessing the shared data.
    * If Lock() returns false, you should not attempt to access the shared data.
--- a/gfx/layers/client/TextureClientPool.cpp
+++ b/gfx/layers/client/TextureClientPool.cpp
@@ -52,21 +52,21 @@ TextureClientPool::GetTextureClient()
   // client, we may need to free a deferred-return TextureClient.
   ShrinkToMaximumSize();
 
   // No unused clients in the pool, create one
   if (gfxPrefs::ForceShmemTiles()) {
     // gfx::BackendType::NONE means use the content backend
     textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator,
       mFormat, TextureFlags::IMMEDIATE_UPLOAD, gfx::BackendType::NONE);
+    textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT);
   } else {
-    textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator,
-      mFormat, TextureFlags::IMMEDIATE_UPLOAD, gfx::BackendType::NONE, mSize);
+    textureClient = TextureClient::CreateForDrawing(mSurfaceAllocator,
+      mFormat, mSize, gfx::BackendType::NONE, TextureFlags::IMMEDIATE_UPLOAD);
   }
-  textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT);
 
   return textureClient;
 }
 
 void
 TextureClientPool::ReturnTextureClient(TextureClient *aClient)
 {
   if (!aClient) {
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -144,17 +144,19 @@ ParamTraits<MagicGrallocBufferHandle>::R
     fds[n] = fd.fd;
   }
 
   aResult->mRef.mOwner = owner;
   aResult->mRef.mKey = index;
   if (sameProcess) {
     aResult->mGraphicBuffer = SharedBufferManagerParent::GetGraphicBuffer(aResult->mRef);
   } else {
-    aResult->mGraphicBuffer = SharedBufferManagerChild::GetSingleton()->GetGraphicBuffer(index);
+    if (SharedBufferManagerChild::GetSingleton()->IsValidKey(index)) {
+      aResult->mGraphicBuffer = SharedBufferManagerChild::GetSingleton()->GetGraphicBuffer(index);
+    }
     MOZ_ASSERT(!aResult->mGraphicBuffer.get());
 
     // Deserialize GraphicBuffer
 #if ANDROID_VERSION >= 19
     sp<GraphicBuffer> buffer(new GraphicBuffer());
     const void* datap = (const void*)data;
     const int* fdsp = &fds[0];
     if (NO_ERROR != buffer->unflatten(datap, nbytes, fdsp, nfds)) {
--- a/gfx/layers/ipc/SharedBufferManagerChild.cpp
+++ b/gfx/layers/ipc/SharedBufferManagerChild.cpp
@@ -340,10 +340,21 @@ SharedBufferManagerChild::GetGraphicBuff
   if (mBuffers.count(key) == 0) {
     printf_stderr("SharedBufferManagerChild::GetGraphicBuffer -- invalid key");
     return nullptr;
   }
   return mBuffers[key];
 }
 #endif
 
+bool
+SharedBufferManagerChild::IsValidKey(int64_t key)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  if (mBuffers.count(key) != 1) {
+    return false;
+  }
+#endif
+  return true;
+}
+
 } /* namespace layers */
 } /* namespace mozilla */
--- a/gfx/layers/ipc/SharedBufferManagerChild.h
+++ b/gfx/layers/ipc/SharedBufferManagerChild.h
@@ -102,19 +102,21 @@ public:
    * and decrease the reference count on both side.
    */
   void
   DeallocGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer);
 
   virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
 
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
-  android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t index);
+  android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t key);
 #endif
 
+  bool IsValidKey(int64_t key);
+
   base::Thread* GetThread() const;
 
   MessageLoop* GetMessageLoop() const;
 
   static bool IsCreated();
 
   static base::Thread* sSharedBufferManagerChildThread;
   static SharedBufferManagerChild* sSharedBufferManagerChildSingleton;
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -24,17 +24,16 @@ namespace mozilla {
 namespace layers {
 
 using namespace mozilla::ipc;
 
 SharedPlanarYCbCrImage::SharedPlanarYCbCrImage(ImageClient* aCompositable)
 : PlanarYCbCrImage(nullptr)
 , mCompositable(aCompositable)
 {
-  mTextureClient = aCompositable->CreateBufferTextureClient(gfx::SurfaceFormat::YUV);
   MOZ_COUNT_CTOR(SharedPlanarYCbCrImage);
 }
 
 SharedPlanarYCbCrImage::~SharedPlanarYCbCrImage() {
   MOZ_COUNT_DTOR(SharedPlanarYCbCrImage);
 
   if (mCompositable->GetAsyncID() != 0 &&
       !InImageBridgeChildThread()) {
@@ -64,84 +63,73 @@ uint8_t*
 SharedPlanarYCbCrImage::GetBuffer()
 {
   return mTextureClient->GetBuffer();
 }
 
 TemporaryRef<gfx::SourceSurface>
 SharedPlanarYCbCrImage::GetAsSourceSurface()
 {
-  if (!mTextureClient->IsAllocated()) {
+  if (!mTextureClient) {
     NS_WARNING("Can't get as surface");
     return nullptr;
   }
   return PlanarYCbCrImage::GetAsSourceSurface();
 }
 
 void
 SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
 {
-  // If mShmem has not been allocated (through Allocate(aData)), allocate it.
-  // This code path is slower than the one used when Allocate has been called
-  // since it will trigger a full copy.
-  if (!mTextureClient->IsAllocated()) {
-    Data data = aData;
-    if (!Allocate(data)) {
-      NS_WARNING("SharedPlanarYCbCrImage::SetData failed to allocate");
-      return;
-    }
+  // If mTextureClient has not already been allocated (through Allocate(aData))
+  // allocate it. This code path is slower than the one used when Allocate has
+  // been called since it will trigger a full copy.
+  PlanarYCbCrData data = aData;
+  if (!mTextureClient && !Allocate(data)) {
+    return;
   }
 
   MOZ_ASSERT(mTextureClient->AsTextureClientYCbCr());
   if (!mTextureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
     MOZ_ASSERT(false, "Failed to lock the texture.");
     return;
   }
   TextureClientAutoUnlock unlock(mTextureClient);
   if (!mTextureClient->AsTextureClientYCbCr()->UpdateYCbCr(aData)) {
     MOZ_ASSERT(false, "Failed to copy YCbCr data into the TextureClient");
     return;
   }
-  // do not set mBuffer like in PlanarYCbCrImage because the later
-  // will try to manage this memory without knowing it belongs to a
-  // shmem.
-  mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
-                                                               mData.mCbCrSize);
-  mSize = mData.mPicSize;
-
-  YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize());
-  mData.mYChannel = serializer.GetYData();
-  mData.mCbChannel = serializer.GetCbData();
-  mData.mCrChannel = serializer.GetCrData();
   mTextureClient->MarkImmutable();
 }
 
 // needs to be overriden because the parent class sets mBuffer which we
 // do not want to happen.
 uint8_t*
 SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
 {
-  NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(), "This image already has allocated data");
+  NS_ABORT_IF_FALSE(!mTextureClient, "This image already has allocated data");
   size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aSize);
 
+  mTextureClient = mCompositable->CreateBufferTextureClient(gfx::SurfaceFormat::YUV);
   // get new buffer _without_ setting mBuffer.
   if (!mTextureClient->Allocate(size)) {
+    mTextureClient = nullptr;
     return nullptr;
   }
 
   // update buffer size
   mBufferSize = size;
 
   YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize());
   return serializer.GetData();
 }
 
 void
 SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
 {
+  NS_ABORT_IF_FALSE(mTextureClient, "This Image should have already allocated data");
   mData = aData;
   mSize = aData.mPicSize;
   /* SetDataNoCopy is used to update YUV plane offsets without (re)allocating
    * memory previously allocated with AllocateAndGetNewBuffer().
    * serializer.GetData() returns the address of the memory previously allocated
    * with AllocateAndGetNewBuffer(), that we subtract from the Y, Cb, Cr
    * channels to compute 0-based offsets to pass to InitializeBufferInfo.
    */
@@ -158,39 +146,43 @@ SharedPlanarYCbCrImage::SetDataNoCopy(co
                                   aData.mYSize,
                                   aData.mCbCrSize,
                                   aData.mStereoMode);
 }
 
 uint8_t*
 SharedPlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
 {
-  NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(),
+  NS_ABORT_IF_FALSE(!mTextureClient,
                     "This image already has allocated data");
+  mTextureClient = mCompositable->CreateBufferTextureClient(gfx::SurfaceFormat::YUV);
   if (!mTextureClient->Allocate(aSize)) {
+    mTextureClient = nullptr;
     return nullptr;
   }
   return mTextureClient->GetBuffer();
 }
 
 bool
 SharedPlanarYCbCrImage::IsValid() {
-  return mTextureClient->IsAllocated();
+  return !!mTextureClient;
 }
 
 bool
 SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData)
 {
-  NS_ABORT_IF_FALSE(!mTextureClient->IsAllocated(),
+  NS_ABORT_IF_FALSE(!mTextureClient,
                     "This image already has allocated data");
 
-  size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aData.mYSize,
-                                                               aData.mCbCrSize);
-
-  if (AllocateBuffer(static_cast<uint32_t>(size)) == nullptr) {
+  mTextureClient = TextureClient::CreateForYCbCr(mCompositable->GetForwarder(),
+                                                 aData.mYSize, aData.mCbCrSize,
+                                                 aData.mStereoMode,
+                                                 mCompositable->GetTextureFlags());
+  if (!mTextureClient) {
+    NS_WARNING("SharedPlanarYCbCrImage::Allocate failed.");
     return false;
   }
 
   YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize());
   serializer.InitializeBufferInfo(aData.mYSize,
                                   aData.mCbCrSize,
                                   aData.mStereoMode);
   MOZ_ASSERT(serializer.IsValid());
@@ -212,13 +204,20 @@ SharedPlanarYCbCrImage::Allocate(PlanarY
   // those members are not always equal to aData's, due to potentially different
   // packing.
   mData.mYSkip = 0;
   mData.mCbSkip = 0;
   mData.mCrSkip = 0;
   mData.mYStride = mData.mYSize.width;
   mData.mCbCrStride = mData.mCbCrSize.width;
 
+  // do not set mBuffer like in PlanarYCbCrImage because the later
+  // will try to manage this memory without knowing it belongs to a
+  // shmem.
+  mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
+                                                               mData.mCbCrSize);
+  mSize = mData.mPicSize;
+
   return true;
 }
 
 } // namespace
 } // namespace
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -75,39 +75,19 @@ private:
     mozilla::AlignedStorage2<mozilla::gfx::ColorPattern> mColorPattern;
     mozilla::AlignedStorage2<mozilla::gfx::SurfacePattern> mSurfacePattern;
   };
 
   gfxContext *mContext;
   Pattern *mPattern;
 };
 
-gfxContext::gfxContext(gfxASurface *surface)
-  : mRefCairo(nullptr)
-  , mSurface(surface)
-{
-  MOZ_COUNT_CTOR(gfxContext);
-
-  mCairo = cairo_create(surface->CairoSurface());
-  mFlags = surface->GetDefaultContextFlags();
-  if (mSurface->GetRotateForLandscape()) {
-    // Rotate page 90 degrees to draw landscape page on portrait paper
-    gfxIntSize size = mSurface->GetSize();
-    Translate(gfxPoint(0, size.width));
-    gfxMatrix matrix(0, -1,
-                      1,  0,
-                      0,  0);
-    Multiply(matrix);
-  }
-}
-
 gfxContext::gfxContext(DrawTarget *aTarget, const Point& aDeviceOffset)
   : mPathIsRect(false)
   , mTransformChanged(false)
-  , mCairo(nullptr)
   , mRefCairo(nullptr)
   , mSurface(nullptr)
   , mFlags(0)
   , mDT(aTarget)
   , mOriginalDT(aTarget)
 {
   MOZ_COUNT_CTOR(gfxContext);
 
@@ -123,19 +103,16 @@ gfxContext::ContextForDrawTarget(DrawTar
   Matrix transform = aTarget->GetTransform();
   nsRefPtr<gfxContext> result = new gfxContext(aTarget);
   result->SetMatrix(ThebesMatrix(transform));
   return result.forget();
 }
 
 gfxContext::~gfxContext()
 {
-  if (mCairo) {
-    cairo_destroy(mCairo);
-  }
   if (mRefCairo) {
     cairo_destroy(mRefCairo);
   }
   if (mDT) {
     for (int i = mStateStack.Length() - 1; i >= 0; i--) {
       for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
         mDT->PopClip();
       }
@@ -147,17 +124,17 @@ gfxContext::~gfxContext()
     mDT->Flush();
   }
   MOZ_COUNT_DTOR(gfxContext);
 }
 
 gfxASurface *
 gfxContext::OriginalSurface()
 {
-    if (mCairo || mSurface) {
+    if (mSurface) {
         return mSurface;
     }
 
     if (mOriginalDT && mOriginalDT->GetBackendType() == BackendType::CAIRO) {
         cairo_surface_t *s =
             (cairo_surface_t*)mOriginalDT->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE);
         if (s) {
             mSurface = gfxASurface::Wrap(s);
@@ -165,56 +142,38 @@ gfxContext::OriginalSurface()
         }
     }
     return nullptr;
 }
 
 already_AddRefed<gfxASurface>
 gfxContext::CurrentSurface(gfxFloat *dx, gfxFloat *dy)
 {
-  if (mCairo) {
-    cairo_surface_t *s = cairo_get_group_target(mCairo);
-    if (s == mSurface->CairoSurface()) {
-        if (dx && dy)
-            cairo_surface_get_device_offset(s, dx, dy);
-        nsRefPtr<gfxASurface> ret = mSurface;
-        return ret.forget();
+  if (mDT->GetBackendType() == BackendType::CAIRO) {
+    cairo_surface_t *s =
+    (cairo_surface_t*)mDT->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE);
+    if (s) {
+      if (dx && dy) {
+        *dx = -CurrentState().deviceOffset.x;
+        *dy = -CurrentState().deviceOffset.y;
+      }
+      return gfxASurface::Wrap(s);
     }
+  }
 
-    if (dx && dy)
-        cairo_surface_get_device_offset(s, dx, dy);
-    return gfxASurface::Wrap(s);
-  } else {
-    if (mDT->GetBackendType() == BackendType::CAIRO) {
-        cairo_surface_t *s =
-            (cairo_surface_t*)mDT->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE);
-        if (s) {
-            if (dx && dy) {
-                *dx = -CurrentState().deviceOffset.x;
-                *dy = -CurrentState().deviceOffset.y;
-            }
-            return gfxASurface::Wrap(s);
-        }
-    }
-
-    if (dx && dy) {
-      *dx = *dy = 0;
-    }
-    // An Azure context doesn't have a surface backing it.
-    return nullptr;
+  if (dx && dy) {
+    *dx = *dy = 0;
   }
+  // An Azure context doesn't have a surface backing it.
+  return nullptr;
 }
 
 cairo_t *
 gfxContext::GetCairo()
 {
-  if (mCairo) {
-    return mCairo;
-  }
-
   if (mDT->GetBackendType() == BackendType::CAIRO) {
     cairo_t *ctx =
       (cairo_t*)mDT->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT);
     if (ctx) {
       return ctx;
     }
   }
 
@@ -226,629 +185,377 @@ gfxContext::GetCairo()
   mRefCairo = cairo_create(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->CairoSurface()); 
 
   return mRefCairo;
 }
 
 void
 gfxContext::Save()
 {
-  if (mCairo) {
-    cairo_save(mCairo);
-  } else {
-    CurrentState().transform = mTransform;
-    mStateStack.AppendElement(AzureState(CurrentState()));
-    CurrentState().clipWasReset = false;
-    CurrentState().pushedClips.Clear();
-  }
+  CurrentState().transform = mTransform;
+  mStateStack.AppendElement(AzureState(CurrentState()));
+  CurrentState().clipWasReset = false;
+  CurrentState().pushedClips.Clear();
 }
 
 void
 gfxContext::Restore()
 {
-  if (mCairo) {
-    cairo_restore(mCairo);
-  } else {
-    for (unsigned int c = 0; c < CurrentState().pushedClips.Length(); c++) {
-      mDT->PopClip();
-    }
+  for (unsigned int c = 0; c < CurrentState().pushedClips.Length(); c++) {
+    mDT->PopClip();
+  }
 
-    if (CurrentState().clipWasReset &&
-        CurrentState().drawTarget == mStateStack[mStateStack.Length() - 2].drawTarget) {
-      PushClipsToDT(mDT);
-    }
+  if (CurrentState().clipWasReset &&
+      CurrentState().drawTarget == mStateStack[mStateStack.Length() - 2].drawTarget) {
+    PushClipsToDT(mDT);
+  }
 
-    mStateStack.RemoveElementAt(mStateStack.Length() - 1);
+  mStateStack.RemoveElementAt(mStateStack.Length() - 1);
 
-    mDT = CurrentState().drawTarget;
+  mDT = CurrentState().drawTarget;
 
-    ChangeTransform(CurrentState().transform, false);
-  }
+  ChangeTransform(CurrentState().transform, false);
 }
 
 // drawing
 void
 gfxContext::NewPath()
 {
-  if (mCairo) {
-    cairo_new_path(mCairo);
-  } else {
-    mPath = nullptr;
-    mPathBuilder = nullptr;
-    mPathIsRect = false;
-    mTransformChanged = false;
-  }
+  mPath = nullptr;
+  mPathBuilder = nullptr;
+  mPathIsRect = false;
+  mTransformChanged = false;
 }
 
 void
 gfxContext::ClosePath()
 {
-  if (mCairo) {
-    cairo_close_path(mCairo);
-  } else {
-    EnsurePathBuilder();
-    mPathBuilder->Close();
-  }
+  EnsurePathBuilder();
+  mPathBuilder->Close();
 }
 
 already_AddRefed<gfxPath> gfxContext::CopyPath()
 {
-  nsRefPtr<gfxPath> path;
-  if (mCairo) {
-    path = new gfxPath(cairo_copy_path(mCairo));
-  } else {
-    EnsurePath();
-    path = new gfxPath(mPath);
-  }
+  EnsurePath();
+  nsRefPtr<gfxPath> path = new gfxPath(mPath);
   return path.forget();
 }
 
 void gfxContext::SetPath(gfxPath* path)
 {
-  if (mCairo) {
-    cairo_new_path(mCairo);
-    if (path->mPath->status == CAIRO_STATUS_SUCCESS && path->mPath->num_data != 0)
-        cairo_append_path(mCairo, path->mPath);
-  } else {
-    MOZ_ASSERT(path->mMoz2DPath, "Can't mix cairo and azure paths!");
-    MOZ_ASSERT(path->mMoz2DPath->GetBackendType() == mDT->GetBackendType());
-    mPath = path->mMoz2DPath;
-    mPathBuilder = nullptr;
-    mPathIsRect = false;
-    mTransformChanged = false;
-  }
+  MOZ_ASSERT(path->mMoz2DPath, "Can't mix cairo and azure paths!");
+  MOZ_ASSERT(path->mMoz2DPath->GetBackendType() == mDT->GetBackendType());
+  mPath = path->mMoz2DPath;
+  mPathBuilder = nullptr;
+  mPathIsRect = false;
+  mTransformChanged = false;
 }
 
 gfxPoint
 gfxContext::CurrentPoint()
 {
-  if (mCairo) {
-    double x, y;
-    cairo_get_current_point(mCairo, &x, &y);
-    return gfxPoint(x, y);
-  } else {
-    EnsurePathBuilder();
-    return ThebesPoint(mPathBuilder->CurrentPoint());
-  }
+  EnsurePathBuilder();
+  return ThebesPoint(mPathBuilder->CurrentPoint());
 }
 
 void
 gfxContext::Stroke()
 {
-  if (mCairo) {
-    cairo_stroke_preserve(mCairo);
-  } else {
-    AzureState &state = CurrentState();
-    if (mPathIsRect) {
-      MOZ_ASSERT(!mTransformChanged);
+  AzureState &state = CurrentState();
+  if (mPathIsRect) {
+    MOZ_ASSERT(!mTransformChanged);
 
-      mDT->StrokeRect(mRect, GeneralPattern(this),
-                      state.strokeOptions,
-                      DrawOptions(1.0f, GetOp(), state.aaMode));
-    } else {
-      EnsurePath();
+    mDT->StrokeRect(mRect, GeneralPattern(this),
+                    state.strokeOptions,
+                    DrawOptions(1.0f, GetOp(), state.aaMode));
+  } else {
+    EnsurePath();
 
-      mDT->Stroke(mPath, GeneralPattern(this), state.strokeOptions,
-                  DrawOptions(1.0f, GetOp(), state.aaMode));
-    }
+    mDT->Stroke(mPath, GeneralPattern(this), state.strokeOptions,
+                DrawOptions(1.0f, GetOp(), state.aaMode));
   }
 }
 
 void
 gfxContext::Fill()
 {
   PROFILER_LABEL("gfxContext", "Fill",
     js::ProfileEntry::Category::GRAPHICS);
-
-  if (mCairo) {
-    cairo_fill_preserve(mCairo);
-  } else {
-    FillAzure(1.0f);
-  }
+  FillAzure(1.0f);
 }
 
 void
 gfxContext::FillWithOpacity(gfxFloat aOpacity)
 {
-  if (mCairo) {
-    // This method exists in the hope that one day cairo gets a direct
-    // API for this, and then we would change this method to use that
-    // API instead.
-    if (aOpacity != 1.0) {
-      gfxContextAutoSaveRestore saveRestore(this);
-      Clip();
-      Paint(aOpacity);
-    } else {
-      Fill();
-    }
-  } else {
-    FillAzure(Float(aOpacity));
-  }
+  FillAzure(Float(aOpacity));
 }
 
 void
 gfxContext::MoveTo(const gfxPoint& pt)
 {
-  if (mCairo) {
-    cairo_move_to(mCairo, pt.x, pt.y);
-  } else {
-    EnsurePathBuilder();
-    mPathBuilder->MoveTo(ToPoint(pt));
-  }
+  EnsurePathBuilder();
+  mPathBuilder->MoveTo(ToPoint(pt));
 }
 
 void
 gfxContext::NewSubPath()
 {
-  if (mCairo) {
-    cairo_new_sub_path(mCairo);
-  } else {
     // XXX - This has no users, we should kill it, it should be equivelant to a
     // MoveTo to the path's current point.
-  }
 }
 
 void
 gfxContext::LineTo(const gfxPoint& pt)
 {
-  if (mCairo) {
-    cairo_line_to(mCairo, pt.x, pt.y);
-  } else {
-    EnsurePathBuilder();
-    mPathBuilder->LineTo(ToPoint(pt));
-  }
+  EnsurePathBuilder();
+  mPathBuilder->LineTo(ToPoint(pt));
 }
 
 void
 gfxContext::CurveTo(const gfxPoint& pt1, const gfxPoint& pt2, const gfxPoint& pt3)
 {
-  if (mCairo) {
-    cairo_curve_to(mCairo, pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y);
-  } else {
-    EnsurePathBuilder();
-    mPathBuilder->BezierTo(ToPoint(pt1), ToPoint(pt2), ToPoint(pt3));
-  }
+  EnsurePathBuilder();
+  mPathBuilder->BezierTo(ToPoint(pt1), ToPoint(pt2), ToPoint(pt3));
 }
 
 void
 gfxContext::QuadraticCurveTo(const gfxPoint& pt1, const gfxPoint& pt2)
 {
-  if (mCairo) {
-    double cx, cy;
-    cairo_get_current_point(mCairo, &cx, &cy);
-    cairo_curve_to(mCairo,
-                   (cx + pt1.x * 2.0) / 3.0,
-                   (cy + pt1.y * 2.0) / 3.0,
-                   (pt1.x * 2.0 + pt2.x) / 3.0,
-                   (pt1.y * 2.0 + pt2.y) / 3.0,
-                   pt2.x,
-                   pt2.y);
-  } else {
-    EnsurePathBuilder();
-    mPathBuilder->QuadraticBezierTo(ToPoint(pt1), ToPoint(pt2));
-  }
+  EnsurePathBuilder();
+  mPathBuilder->QuadraticBezierTo(ToPoint(pt1), ToPoint(pt2));
 }
 
 void
 gfxContext::Arc(const gfxPoint& center, gfxFloat radius,
                 gfxFloat angle1, gfxFloat angle2)
 {
-  if (mCairo) {
-    cairo_arc(mCairo, center.x, center.y, radius, angle1, angle2);
-  } else {
-    EnsurePathBuilder();
-    mPathBuilder->Arc(ToPoint(center), Float(radius), Float(angle1), Float(angle2));
-  }
+  EnsurePathBuilder();
+  mPathBuilder->Arc(ToPoint(center), Float(radius), Float(angle1), Float(angle2));
 }
 
 void
 gfxContext::NegativeArc(const gfxPoint& center, gfxFloat radius,
                         gfxFloat angle1, gfxFloat angle2)
 {
-  if (mCairo) {
-    cairo_arc_negative(mCairo, center.x, center.y, radius, angle1, angle2);
-  } else {
-    EnsurePathBuilder();
-    mPathBuilder->Arc(ToPoint(center), Float(radius), Float(angle2), Float(angle1));
-  }
+  EnsurePathBuilder();
+  mPathBuilder->Arc(ToPoint(center), Float(radius), Float(angle2), Float(angle1));
 }
 
 void
 gfxContext::Line(const gfxPoint& start, const gfxPoint& end)
 {
-  if (mCairo) {
-    MoveTo(start);
-    LineTo(end);
-  } else {
-    EnsurePathBuilder();
-    mPathBuilder->MoveTo(ToPoint(start));
-    mPathBuilder->LineTo(ToPoint(end));
-  }
+  EnsurePathBuilder();
+  mPathBuilder->MoveTo(ToPoint(start));
+  mPathBuilder->LineTo(ToPoint(end));
 }
 
 // XXX snapToPixels is only valid when snapping for filled
 // rectangles and for even-width stroked rectangles.
 // For odd-width stroked rectangles, we need to offset x/y by
 // 0.5...
 void
 gfxContext::Rectangle(const gfxRect& rect, bool snapToPixels)
 {
-  if (mCairo) {
-    if (snapToPixels) {
-        gfxRect snappedRect(rect);
+  Rect rec = ToRect(rect);
 
-        if (UserToDevicePixelSnapped(snappedRect, true))
-        {
-            cairo_matrix_t mat;
-            cairo_get_matrix(mCairo, &mat);
-            cairo_identity_matrix(mCairo);
-            Rectangle(snappedRect);
-            cairo_set_matrix(mCairo, &mat);
+  if (snapToPixels) {
+    gfxRect newRect(rect);
+    if (UserToDevicePixelSnapped(newRect, true)) {
+      gfxMatrix mat = ThebesMatrix(mTransform);
+      mat.Invert();
 
-            return;
-        }
+      // We need the user space rect.
+      rec = ToRect(mat.TransformBounds(newRect));
     }
-
-    cairo_rectangle(mCairo, rect.X(), rect.Y(), rect.Width(), rect.Height());
-  } else {
-    Rect rec = ToRect(rect);
+  }
 
-    if (snapToPixels) {
-      gfxRect newRect(rect);
-      if (UserToDevicePixelSnapped(newRect, true)) {
-        gfxMatrix mat = ThebesMatrix(mTransform);
-        mat.Invert();
-
-        // We need the user space rect.
-        rec = ToRect(mat.TransformBounds(newRect));
-      }
-    }
+  if (!mPathBuilder && !mPathIsRect) {
+    mPathIsRect = true;
+    mRect = rec;
+    return;
+  }
 
-    if (!mPathBuilder && !mPathIsRect) {
-      mPathIsRect = true;
-      mRect = rec;
-      return;
-    }
+  EnsurePathBuilder();
 
-    EnsurePathBuilder();
-
-    mPathBuilder->MoveTo(rec.TopLeft());
-    mPathBuilder->LineTo(rec.TopRight());
-    mPathBuilder->LineTo(rec.BottomRight());
-    mPathBuilder->LineTo(rec.BottomLeft());
-    mPathBuilder->Close();
-  }
+  mPathBuilder->MoveTo(rec.TopLeft());
+  mPathBuilder->LineTo(rec.TopRight());
+  mPathBuilder->LineTo(rec.BottomRight());
+  mPathBuilder->LineTo(rec.BottomLeft());
+  mPathBuilder->Close();
 }
 
 void
 gfxContext::Ellipse(const gfxPoint& center, const gfxSize& dimensions)
 {
   gfxSize halfDim = dimensions / 2.0;
   gfxRect r(center - gfxPoint(halfDim.width, halfDim.height), dimensions);
   gfxCornerSizes c(halfDim, halfDim, halfDim, halfDim);
 
   RoundedRectangle (r, c);
 }
 
 void
 gfxContext::Polygon(const gfxPoint *points, uint32_t numPoints)
 {
-  if (mCairo) {
-    if (numPoints == 0)
-        return;
+  if (numPoints == 0) {
+    return;
+  }
 
-    cairo_move_to(mCairo, points[0].x, points[0].y);
-    for (uint32_t i = 1; i < numPoints; ++i) {
-        cairo_line_to(mCairo, points[i].x, points[i].y);
-    }
-  } else {
-    if (numPoints == 0) {
-      return;
-    }
+  EnsurePathBuilder();
 
-    EnsurePathBuilder();
-
-    mPathBuilder->MoveTo(ToPoint(points[0]));
-    for (uint32_t i = 1; i < numPoints; i++) {
-      mPathBuilder->LineTo(ToPoint(points[i]));
-    }
+  mPathBuilder->MoveTo(ToPoint(points[0]));
+  for (uint32_t i = 1; i < numPoints; i++) {
+    mPathBuilder->LineTo(ToPoint(points[i]));
   }
 }
 
 void
 gfxContext::DrawSurface(gfxASurface *surface, const gfxSize& size)
 {
-  if (mCairo) {
-    cairo_save(mCairo);
-    cairo_set_source_surface(mCairo, surface->CairoSurface(), 0, 0);
-    cairo_new_path(mCairo);
-
-    // pixel-snap this
-    Rectangle(gfxRect(gfxPoint(0.0, 0.0), size), true);
+  // Lifetime needs to be limited here since we may wrap surface's data.
+  RefPtr<SourceSurface> surf =
+    gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mDT, surface);
 
-    cairo_fill(mCairo);
-    cairo_restore(mCairo);
-  } else {
-    // Lifetime needs to be limited here since we may wrap surface's data.
-    RefPtr<SourceSurface> surf =
-      gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mDT, surface);
+  if (!surf) {
+    return;
+  }
 
-    if (!surf) {
-      return;
-    }
+  Rect rect(0, 0, Float(size.width), Float(size.height));
+  rect.Intersect(Rect(0, 0, Float(surf->GetSize().width), Float(surf->GetSize().height)));
 
-    Rect rect(0, 0, Float(size.width), Float(size.height));
-    rect.Intersect(Rect(0, 0, Float(surf->GetSize().width), Float(surf->GetSize().height)));
-
-    // XXX - Should fix pixel snapping.
-    mDT->DrawSurface(surf, rect, rect);
-  }
+  // XXX - Should fix pixel snapping.
+  mDT->DrawSurface(surf, rect, rect);
 }
 
 // transform stuff
 void
 gfxContext::Translate(const gfxPoint& pt)
 {
-  if (mCairo) {
-    cairo_translate(mCairo, pt.x, pt.y);
-  } else {
-    Matrix newMatrix = mTransform;
-
-    ChangeTransform(newMatrix.Translate(Float(pt.x), Float(pt.y)));
-  }
+  Matrix newMatrix = mTransform;
+  ChangeTransform(newMatrix.Translate(Float(pt.x), Float(pt.y)));
 }
 
 void
 gfxContext::Scale(gfxFloat x, gfxFloat y)
 {
-  if (mCairo) {
-    cairo_scale(mCairo, x, y);
-  } else {
-    Matrix newMatrix = mTransform;
-
-    ChangeTransform(newMatrix.Scale(Float(x), Float(y)));
-  }
+  Matrix newMatrix = mTransform;
+  ChangeTransform(newMatrix.Scale(Float(x), Float(y)));
 }
 
 void
 gfxContext::Rotate(gfxFloat angle)
 {
-  if (mCairo) {
-    cairo_rotate(mCairo, angle);
-  } else {
-    Matrix rotation = Matrix::Rotation(Float(angle));
-    ChangeTransform(rotation * mTransform);
-  }
+  Matrix rotation = Matrix::Rotation(Float(angle));
+  ChangeTransform(rotation * mTransform);
 }
 
 void
 gfxContext::Multiply(const gfxMatrix& matrix)
 {
-  if (mCairo) {
-    const cairo_matrix_t& mat = reinterpret_cast<const cairo_matrix_t&>(matrix);
-    cairo_transform(mCairo, &mat);
-  } else {
-    ChangeTransform(ToMatrix(matrix) * mTransform);
-  }
+  ChangeTransform(ToMatrix(matrix) * mTransform);
 }
 
 void
 gfxContext::MultiplyAndNudgeToIntegers(const gfxMatrix& matrix)
 {
-  if (mCairo) {
-    const cairo_matrix_t& mat = reinterpret_cast<const cairo_matrix_t&>(matrix);
-    cairo_transform(mCairo, &mat);
-    // XXX nudging to integers not currently supported for Thebes
-  } else {
-    Matrix transform = ToMatrix(matrix) * mTransform;
-    transform.NudgeToIntegers();
-    ChangeTransform(transform);
-  }
+  Matrix transform = ToMatrix(matrix) * mTransform;
+  transform.NudgeToIntegers();
+  ChangeTransform(transform);
 }
 
 void
 gfxContext::SetMatrix(const gfxMatrix& matrix)
 {
-  if (mCairo) {
-    const cairo_matrix_t& mat = reinterpret_cast<const cairo_matrix_t&>(matrix);
-    cairo_set_matrix(mCairo, &mat);
-  } else {
-    ChangeTransform(ToMatrix(matrix));
-  }
+  ChangeTransform(ToMatrix(matrix));
 }
 
 void
 gfxContext::IdentityMatrix()
 {
-  if (mCairo) {
-    cairo_identity_matrix(mCairo);
-  } else {
-    ChangeTransform(Matrix());
-  }
+  ChangeTransform(Matrix());
 }
 
 gfxMatrix
 gfxContext::CurrentMatrix() const
 {
-  if (mCairo) {
-    cairo_matrix_t mat;
-    cairo_get_matrix(mCairo, &mat);
-    return gfxMatrix(*reinterpret_cast<gfxMatrix*>(&mat));
-  } else {
-    return ThebesMatrix(mTransform);
-  }
+  return ThebesMatrix(mTransform);
 }
 
 void
 gfxContext::NudgeCurrentMatrixToIntegers()
 {
-  if (mCairo) {
-    cairo_matrix_t mat;
-    cairo_get_matrix(mCairo, &mat);
-    gfxMatrix(*reinterpret_cast<gfxMatrix*>(&mat)).NudgeToIntegers();
-    cairo_set_matrix(mCairo, &mat);
-  } else {
-    gfxMatrix matrix = ThebesMatrix(mTransform);
-    matrix.NudgeToIntegers();
-    ChangeTransform(ToMatrix(matrix));
-  }
+  gfxMatrix matrix = ThebesMatrix(mTransform);
+  matrix.NudgeToIntegers();
+  ChangeTransform(ToMatrix(matrix));
 }
 
 gfxPoint
 gfxContext::DeviceToUser(const gfxPoint& point) const
 {
-  if (mCairo) {
-    gfxPoint ret = point;
-    cairo_device_to_user(mCairo, &ret.x, &ret.y);
-    return ret;
-  } else {
-    Matrix matrix = mTransform;
-
-    matrix.Invert();
-
-    return ThebesPoint(matrix * ToPoint(point));
-  }
+  Matrix matrix = mTransform;
+  matrix.Invert();
+  return ThebesPoint(matrix * ToPoint(point));
 }
 
 gfxSize
 gfxContext::DeviceToUser(const gfxSize& size) const
 {
-  if (mCairo) {
-    gfxSize ret = size;
-    cairo_device_to_user_distance(mCairo, &ret.width, &ret.height);
-    return ret;
-  } else {
-    Matrix matrix = mTransform;
-
-    matrix.Invert();
-
-    return ThebesSize(matrix * ToSize(size));
-  }
+  Matrix matrix = mTransform;
+  matrix.Invert();
+  return ThebesSize(matrix * ToSize(size));
 }
 
 gfxRect
 gfxContext::DeviceToUser(const gfxRect& rect) const
 {
-  if (mCairo) {
-    gfxRect ret = rect;
-    cairo_device_to_user(mCairo, &ret.x, &ret.y);
-    cairo_device_to_user_distance(mCairo, &ret.width, &ret.height);
-    return ret;
-  } else {
-    Matrix matrix = mTransform;
-
-    matrix.Invert();
-
-    return ThebesRect(matrix.TransformBounds(ToRect(rect)));
-  }
+  Matrix matrix = mTransform;
+  matrix.Invert();
+  return ThebesRect(matrix.TransformBounds(ToRect(rect)));
 }
 
 gfxPoint
 gfxContext::UserToDevice(const gfxPoint& point) const
 {
-  if (mCairo) {
-    gfxPoint ret = point;
-    cairo_user_to_device(mCairo, &ret.x, &ret.y);
-    return ret;
-  } else {
-    return ThebesPoint(mTransform * ToPoint(point));
-  }
+  return ThebesPoint(mTransform * ToPoint(point));
 }
 
 gfxSize
 gfxContext::UserToDevice(const gfxSize& size) const
 {
-  if (mCairo) {
-    gfxSize ret = size;
-    cairo_user_to_device_distance(mCairo, &ret.width, &ret.height);
-    return ret;
-  } else {
-    const Matrix &matrix = mTransform;
+  const Matrix &matrix = mTransform;
 
-    gfxSize newSize;
-    newSize.width = size.width * matrix._11 + size.height * matrix._12;
-    newSize.height = size.width * matrix._21 + size.height * matrix._22;
-    return newSize;
-  }
+  gfxSize newSize;
+  newSize.width = size.width * matrix._11 + size.height * matrix._12;
+  newSize.height = size.width * matrix._21 + size.height * matrix._22;
+  return newSize;
 }
 
 gfxRect
 gfxContext::UserToDevice(const gfxRect& rect) const
 {
-  if (mCairo) {
-    double xmin = rect.X(), ymin = rect.Y(), xmax = rect.XMost(), ymax = rect.YMost();
-
-    double x[3], y[3];
-    x[0] = xmin;  y[0] = ymax;
-    x[1] = xmax;  y[1] = ymax;
-    x[2] = xmax;  y[2] = ymin;
-
-    cairo_user_to_device(mCairo, &xmin, &ymin);
-    xmax = xmin;
-    ymax = ymin;
-    for (int i = 0; i < 3; i++) {
-        cairo_user_to_device(mCairo, &x[i], &y[i]);
-        xmin = std::min(xmin, x[i]);
-        xmax = std::max(xmax, x[i]);
-        ymin = std::min(ymin, y[i]);
-        ymax = std::max(ymax, y[i]);
-    }
-
-    return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
-  } else {
-    const Matrix &matrix = mTransform;
-    return ThebesRect(matrix.TransformBounds(ToRect(rect)));
-  }
+  const Matrix &matrix = mTransform;
+  return ThebesRect(matrix.TransformBounds(ToRect(rect)));
 }
 
 bool
 gfxContext::UserToDevicePixelSnapped(gfxRect& rect, bool ignoreScale) const
 {
   if (GetFlags() & FLAG_DISABLE_SNAPPING)
       return false;
 
   // if we're not at 1.0 scale, don't snap, unless we're
   // ignoring the scale.  If we're not -just- a scale,
   // never snap.
   const gfxFloat epsilon = 0.0000001;
 #define WITHIN_E(a,b) (fabs((a)-(b)) < epsilon)
-  if (mCairo) {
-    cairo_matrix_t mat;
-    cairo_get_matrix(mCairo, &mat);
-    if (!ignoreScale &&
-        (!WITHIN_E(mat.xx,1.0) || !WITHIN_E(mat.yy,1.0) ||
-          !WITHIN_E(mat.xy,0.0) || !WITHIN_E(mat.yx,0.0)))
-        return false;
-  } else {
-    Matrix mat = mTransform;
-    if (!ignoreScale &&
-        (!WITHIN_E(mat._11,1.0) || !WITHIN_E(mat._22,1.0) ||
-          !WITHIN_E(mat._12,0.0) || !WITHIN_E(mat._21,0.0)))
-        return false;
-  }
+  Matrix mat = mTransform;
+  if (!ignoreScale &&
+      (!WITHIN_E(mat._11,1.0) || !WITHIN_E(mat._22,1.0) ||
+        !WITHIN_E(mat._12,0.0) || !WITHIN_E(mat._21,0.0)))
+      return false;
 #undef WITHIN_E
 
   gfxPoint p1 = UserToDevice(rect.TopLeft());
   gfxPoint p2 = UserToDevice(rect.TopRight());
   gfxPoint p3 = UserToDevice(rect.BottomRight());
 
   // Check that the rectangle is axis-aligned. For an axis-aligned rectangle,
   // two opposite corners define the entire rectangle. So check if
@@ -875,30 +582,21 @@ gfxContext::UserToDevicePixelSnapped(gfx
   if (GetFlags() & FLAG_DISABLE_SNAPPING)
       return false;
 
   // if we're not at 1.0 scale, don't snap, unless we're
   // ignoring the scale.  If we're not -just- a scale,
   // never snap.
   const gfxFloat epsilon = 0.0000001;
 #define WITHIN_E(a,b) (fabs((a)-(b)) < epsilon)
-  if (mCairo) {
-    cairo_matrix_t mat;
-    cairo_get_matrix(mCairo, &mat);
-    if (!ignoreScale &&
-        (!WITHIN_E(mat.xx,1.0) || !WITHIN_E(mat.yy,1.0) ||
-          !WITHIN_E(mat.xy,0.0) || !WITHIN_E(mat.yx,0.0)))
-        return false;
-  } else {
-    Matrix mat = mTransform;
-    if (!ignoreScale &&
-        (!WITHIN_E(mat._11,1.0) || !WITHIN_E(mat._22,1.0) ||
-          !WITHIN_E(mat._12,0.0) || !WITHIN_E(mat._21,0.0)))
-        return false;
-  }
+  Matrix mat = mTransform;
+  if (!ignoreScale &&
+      (!WITHIN_E(mat._11,1.0) || !WITHIN_E(mat._22,1.0) ||
+        !WITHIN_E(mat._12,0.0) || !WITHIN_E(mat._21,0.0)))
+      return false;
 #undef WITHIN_E
 
   pt = UserToDevice(pt);
   pt.Round();
   return true;
 }
 
 void
@@ -921,45 +619,30 @@ gfxContext::PixelSnappedRectangleAndSetP
   // same thing.
   Rectangle(r, true);
   SetPattern(pattern);
 }
 
 void
 gfxContext::SetAntialiasMode(AntialiasMode mode)
 {
-  if (mCairo) {
-    if (mode == MODE_ALIASED) {
-        cairo_set_antialias(mCairo, CAIRO_ANTIALIAS_NONE);
-    } else if (mode == MODE_COVERAGE) {
-        cairo_set_antialias(mCairo, CAIRO_ANTIALIAS_DEFAULT);
-    }
-  } else {
-    if (mode == MODE_ALIASED) {
-      CurrentState().aaMode = gfx::AntialiasMode::NONE;
-    } else if (mode == MODE_COVERAGE) {
-      CurrentState().aaMode = gfx::AntialiasMode::SUBPIXEL;
-    }
+  if (mode == MODE_ALIASED) {
+    CurrentState().aaMode = gfx::AntialiasMode::NONE;
+  } else if (mode == MODE_COVERAGE) {
+    CurrentState().aaMode = gfx::AntialiasMode::SUBPIXEL;
   }
 }
 
 gfxContext::AntialiasMode
 gfxContext::CurrentAntialiasMode() const
 {
-  if (mCairo) {
-    cairo_antialias_t aa = cairo_get_antialias(mCairo);
-    if (aa == CAIRO_ANTIALIAS_NONE)
-        return MODE_ALIASED;
-    return MODE_COVERAGE;
-  } else {
-    if (CurrentState().aaMode == gfx::AntialiasMode::NONE) {
-      return MODE_ALIASED;
-    }
-    return MODE_COVERAGE;
+  if (CurrentState().aaMode == gfx::AntialiasMode::NONE) {
+    return MODE_ALIASED;
   }
+  return MODE_COVERAGE;
 }
 
 void
 gfxContext::SetDash(gfxLineType ltype)
 {
   static double dash[] = {5.0, 5.0};
   static double dot[] = {1.0, 1.0};
 
@@ -975,561 +658,375 @@ gfxContext::SetDash(gfxLineType ltype)
           SetDash(nullptr, 0, 0.0);
           break;
   }
 }
 
 void
 gfxContext::SetDash(gfxFloat *dashes, int ndash, gfxFloat offset)
 {
-  if (mCairo) {
-    cairo_set_dash(mCairo, dashes, ndash, offset);
-  } else {
-    AzureState &state = CurrentState();
+  AzureState &state = CurrentState();
 
-    state.dashPattern.SetLength(ndash);
-    for (int i = 0; i < ndash; i++) {
-      state.dashPattern[i] = Float(dashes[i]);
-    }
-    state.strokeOptions.mDashLength = ndash;
-    state.strokeOptions.mDashOffset = Float(offset);
-    state.strokeOptions.mDashPattern = ndash ? state.dashPattern.Elements()
-                                             : nullptr;
+  state.dashPattern.SetLength(ndash);
+  for (int i = 0; i < ndash; i++) {
+    state.dashPattern[i] = Float(dashes[i]);
   }
+  state.strokeOptions.mDashLength = ndash;
+  state.strokeOptions.mDashOffset = Float(offset);
+  state.strokeOptions.mDashPattern = ndash ? state.dashPattern.Elements()
+                                           : nullptr;
 }
 
 bool
 gfxContext::CurrentDash(FallibleTArray<gfxFloat>& dashes, gfxFloat* offset) const
 {
-  if (mCairo) {
-    int count = cairo_get_dash_count(mCairo);
-    if (count <= 0 || !dashes.SetLength(count)) {
-        return false;
-    }
-    cairo_get_dash(mCairo, dashes.Elements(), offset);
-    return true;
-  } else {
-    const AzureState &state = CurrentState();
-    int count = state.strokeOptions.mDashLength;
+  const AzureState &state = CurrentState();
+  int count = state.strokeOptions.mDashLength;
+
+  if (count <= 0 || !dashes.SetLength(count)) {
+    return false;
+  }
 
-    if (count <= 0 || !dashes.SetLength(count)) {
-      return false;
-    }
+  for (int i = 0; i < count; i++) {
+    dashes[i] = state.dashPattern[i];
+  }
 
-    for (int i = 0; i < count; i++) {
-      dashes[i] = state.dashPattern[i];
-    }
+  *offset = state.strokeOptions.mDashOffset;
 
-    *offset = state.strokeOptions.mDashOffset;
-
-    return true;
-  }
+  return true;
 }
 
 gfxFloat
 gfxContext::CurrentDashOffset() const
 {
-  if (mCairo) {
-    if (cairo_get_dash_count(mCairo) <= 0) {
-        return 0.0;
-    }
-    gfxFloat offset;
-    cairo_get_dash(mCairo, nullptr, &offset);
-    return offset;
-  } else {
-    return CurrentState().strokeOptions.mDashOffset;
-  }
+  return CurrentState().strokeOptions.mDashOffset;
 }
 
 void
 gfxContext::SetLineWidth(gfxFloat width)
 {
-  if (mCairo) {
-    cairo_set_line_width(mCairo, width);
-  } else {
-    CurrentState().strokeOptions.mLineWidth = Float(width);
-  }
+  CurrentState().strokeOptions.mLineWidth = Float(width);
 }
 
 gfxFloat
 gfxContext::CurrentLineWidth() const
 {
-  if (mCairo) {
-    return cairo_get_line_width(mCairo);
-  } else {
-    return CurrentState().strokeOptions.mLineWidth;
-  }
+  return CurrentState().strokeOptions.mLineWidth;
 }
 
 void
 gfxContext::SetOperator(GraphicsOperator op)
 {
-  if (mCairo) {
-    if (mFlags & FLAG_SIMPLIFY_OPERATORS) {
-        if (op != OPERATOR_SOURCE &&
-            op != OPERATOR_CLEAR &&
-            op != OPERATOR_OVER)
-            op = OPERATOR_OVER;
-    }
-
-    cairo_set_operator(mCairo, (cairo_operator_t)op);
-  } else {
-    if (op == OPERATOR_CLEAR) {
-      CurrentState().opIsClear = true;
-      return;
-    }
-    CurrentState().opIsClear = false;
-    CurrentState().op = CompositionOpForOp(op);
+  if (op == OPERATOR_CLEAR) {
+    CurrentState().opIsClear = true;
+    return;
   }
+  CurrentState().opIsClear = false;
+  CurrentState().op = CompositionOpForOp(op);
 }
 
 gfxContext::GraphicsOperator
 gfxContext::CurrentOperator() const
 {
-  if (mCairo) {
-    return (GraphicsOperator)cairo_get_operator(mCairo);
-  } else {
-    return ThebesOp(CurrentState().op);
-  }
+  return ThebesOp(CurrentState().op);
 }
 
 void
 gfxContext::SetLineCap(GraphicsLineCap cap)
 {
-  if (mCairo) {
-    cairo_set_line_cap(mCairo, (cairo_line_cap_t)cap);
-  } else {
-    CurrentState().strokeOptions.mLineCap = ToCapStyle(cap);
-  }
+  CurrentState().strokeOptions.mLineCap = ToCapStyle(cap);
 }
 
 gfxContext::GraphicsLineCap
 gfxContext::CurrentLineCap() const
 {
-  if (mCairo) {
-    return (GraphicsLineCap)cairo_get_line_cap(mCairo);
-  } else {
-    return ThebesLineCap(CurrentState().strokeOptions.mLineCap);
-  }
+  return ThebesLineCap(CurrentState().strokeOptions.mLineCap);
 }
 
 void
 gfxContext::SetLineJoin(GraphicsLineJoin join)
 {
-  if (mCairo) {
-    cairo_set_line_join(mCairo, (cairo_line_join_t)join);
-  } else {
-    CurrentState().strokeOptions.mLineJoin = ToJoinStyle(join);
-  }
+  CurrentState().strokeOptions.mLineJoin = ToJoinStyle(join);
 }
 
 gfxContext::GraphicsLineJoin
 gfxContext::CurrentLineJoin() const
 {
-  if (mCairo) {
-    return (GraphicsLineJoin)cairo_get_line_join(mCairo);
-  } else {
-    return ThebesLineJoin(CurrentState().strokeOptions.mLineJoin);
-  }
+  return ThebesLineJoin(CurrentState().strokeOptions.mLineJoin);
 }
 
 void
 gfxContext::SetMiterLimit(gfxFloat limit)
 {
-  if (mCairo) {
-    cairo_set_miter_limit(mCairo, limit);
-  } else {
-    CurrentState().strokeOptions.mMiterLimit = Float(limit);
-  }
+  CurrentState().strokeOptions.mMiterLimit = Float(limit);
 }
 
 gfxFloat
 gfxContext::CurrentMiterLimit() const
 {
-  if (mCairo) {
-    return cairo_get_miter_limit(mCairo);
-  } else {
-    return CurrentState().strokeOptions.mMiterLimit;
-  }
+  return CurrentState().strokeOptions.mMiterLimit;
 }
 
 void
 gfxContext::SetFillRule(FillRule rule)
 {
-  if (mCairo) {
-    cairo_set_fill_rule(mCairo, (cairo_fill_rule_t)rule);
-  } else {
-    CurrentState().fillRule = rule == FILL_RULE_WINDING ? gfx::FillRule::FILL_WINDING : gfx::FillRule::FILL_EVEN_ODD;
-  }
+  CurrentState().fillRule = rule == FILL_RULE_WINDING ? gfx::FillRule::FILL_WINDING : gfx::FillRule::FILL_EVEN_ODD;
 }
 
 gfxContext::FillRule
 gfxContext::CurrentFillRule() const
 {
-  if (mCairo) {
-    return (FillRule)cairo_get_fill_rule(mCairo);
-  } else {
-    return FILL_RULE_WINDING;
-  }
+  return FILL_RULE_WINDING;
 }
 
 // clipping
 void
 gfxContext::Clip(const gfxRect& rect)
 {
-  if (mCairo) {
-    cairo_new_path(mCairo);
-    cairo_rectangle(mCairo, rect.X(), rect.Y(), rect.Width(), rect.Height());
-    cairo_clip(mCairo);
-  } else {
-    AzureState::PushedClip clip = { nullptr, ToRect(rect), mTransform };
-    CurrentState().pushedClips.AppendElement(clip);
-    mDT->PushClipRect(ToRect(rect));
-    NewPath();
-  }
+  AzureState::PushedClip clip = { nullptr, ToRect(rect), mTransform };
+  CurrentState().pushedClips.AppendElement(clip);
+  mDT->PushClipRect(ToRect(rect));
+  NewPath();
 }
 
 void
 gfxContext::Clip()
 {
-  if (mCairo) {
-    cairo_clip_preserve(mCairo);
-  } else {
-    if (mPathIsRect) {
-      MOZ_ASSERT(!mTransformChanged);
+  if (mPathIsRect) {
+    MOZ_ASSERT(!mTransformChanged);
 
-      AzureState::PushedClip clip = { nullptr, mRect, mTransform };
-      CurrentState().pushedClips.AppendElement(clip);
-      mDT->PushClipRect(mRect);
-    } else {
-      EnsurePath();
-      mDT->PushClip(mPath);
-      AzureState::PushedClip clip = { mPath, Rect(), mTransform };
-      CurrentState().pushedClips.AppendElement(clip);
-    }
+    AzureState::PushedClip clip = { nullptr, mRect, mTransform };
+    CurrentState().pushedClips.AppendElement(clip);
+    mDT->PushClipRect(mRect);
+  } else {
+    EnsurePath();
+    mDT->PushClip(mPath);
+    AzureState::PushedClip clip = { mPath, Rect(), mTransform };
+    CurrentState().pushedClips.AppendElement(clip);
   }
 }
 
 void
 gfxContext::ResetClip()
 {
-  if (mCairo) {
-    cairo_reset_clip(mCairo);
-  } else {
-    for (int i = mStateStack.Length() - 1; i >= 0; i--) {
-      for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
-        mDT->PopClip();
-      }
+  for (int i = mStateStack.Length() - 1; i >= 0; i--) {
+    for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
+      mDT->PopClip();
+    }
 
-      if (mStateStack[i].clipWasReset) {
-        break;
-      }
+    if (mStateStack[i].clipWasReset) {
+      break;
     }
-    CurrentState().pushedClips.Clear();
-    CurrentState().clipWasReset = true;
   }
+  CurrentState().pushedClips.Clear();
+  CurrentState().clipWasReset = true;
 }
 
 void
 gfxContext::UpdateSurfaceClip()
 {
-  if (mCairo) {
-    NewPath();
-    // we paint an empty rectangle to ensure the clip is propagated to
-    // the destination surface
-    SetDeviceColor(gfxRGBA(0,0,0,0));
-    Rectangle(gfxRect(0,1,1,0));
-    Fill();
-  }
 }
 
 gfxRect
 gfxContext::GetClipExtents()
 {
-  if (mCairo) {
-    double xmin, ymin, xmax, ymax;
-    cairo_clip_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
-    return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
-  } else {
-    Rect rect = GetAzureDeviceSpaceClipBounds();
+  Rect rect = GetAzureDeviceSpaceClipBounds();
+
+  if (rect.width == 0 || rect.height == 0) {
+    return gfxRect(0, 0, 0, 0);
+  }
 
-    if (rect.width == 0 || rect.height == 0) {
-      return gfxRect(0, 0, 0, 0);
-    }
+  Matrix mat = mTransform;
+  mat.Invert();
+  rect = mat.TransformBounds(rect);
 
-    Matrix mat = mTransform;
-    mat.Invert();
-    rect = mat.TransformBounds(rect);
-
-    return ThebesRect(rect);
-  }
+  return ThebesRect(rect);
 }
 
 bool
 gfxContext::ClipContainsRect(const gfxRect& aRect)
 {
-  if (mCairo) {
-    cairo_rectangle_list_t *clip =
-        cairo_copy_clip_rectangle_list(mCairo);
-
-    bool result = false;
+  unsigned int lastReset = 0;
+  for (int i = mStateStack.Length() - 2; i > 0; i--) {
+    if (mStateStack[i].clipWasReset) {
+      lastReset = i;
+      break;
+    }
+  }
 
-    if (clip->status == CAIRO_STATUS_SUCCESS) {
-        for (int i = 0; i < clip->num_rectangles; i++) {
-            gfxRect rect(clip->rectangles[i].x, clip->rectangles[i].y,
-                         clip->rectangles[i].width, clip->rectangles[i].height);
-            if (rect.Contains(aRect)) {
-                result = true;
-                break;
-            }
-        }
-    }
+  // Since we always return false when the clip list contains a
+  // non-rectangular clip or a non-rectilinear transform, our 'total' clip
+  // is always a rectangle if we hit the end of this function.
+  Rect clipBounds(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
 
-    cairo_rectangle_list_destroy(clip);
-    return result;
-  } else {
-    unsigned int lastReset = 0;
-    for (int i = mStateStack.Length() - 2; i > 0; i--) {
-      if (mStateStack[i].clipWasReset) {
-        lastReset = i;
-        break;
+  for (unsigned int i = lastReset; i < mStateStack.Length(); i++) {
+    for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
+      AzureState::PushedClip &clip = mStateStack[i].pushedClips[c];
+      if (clip.path || !clip.transform.IsRectilinear()) {
+        // Cairo behavior is we return false if the clip contains a non-
+        // rectangle.
+        return false;
+      } else {
+        Rect clipRect = mTransform.TransformBounds(clip.rect);
+
+        clipBounds.IntersectRect(clipBounds, clipRect);
       }
     }
-
-    // Since we always return false when the clip list contains a
-    // non-rectangular clip or a non-rectilinear transform, our 'total' clip
-    // is always a rectangle if we hit the end of this function.
-    Rect clipBounds(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
+  }
 
-    for (unsigned int i = lastReset; i < mStateStack.Length(); i++) {
-      for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
-        AzureState::PushedClip &clip = mStateStack[i].pushedClips[c];
-        if (clip.path || !clip.transform.IsRectilinear()) {
-          // Cairo behavior is we return false if the clip contains a non-
-          // rectangle.
-          return false;
-        } else {
-          Rect clipRect = mTransform.TransformBounds(clip.rect);
-
-          clipBounds.IntersectRect(clipBounds, clipRect);
-        }
-      }
-    }
-
-    return clipBounds.Contains(ToRect(aRect));
-  }
+  return clipBounds.Contains(ToRect(aRect));
 }
 
 // rendering sources
 
 void
 gfxContext::SetColor(const gfxRGBA& c)
 {
-  if (mCairo) {
-    if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
+  CurrentState().pattern = nullptr;
+  CurrentState().sourceSurfCairo = nullptr;
+  CurrentState().sourceSurface = nullptr;
 
-        gfxRGBA cms;
-        qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
-        if (transform)
-          gfxPlatform::TransformPixel(c, cms, transform);
+  if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
 
-        // Use the original alpha to avoid unnecessary float->byte->float
-        // conversion errors
-        cairo_set_source_rgba(mCairo, cms.r, cms.g, cms.b, c.a);
-    }
-    else
-        cairo_set_source_rgba(mCairo, c.r, c.g, c.b, c.a);
-  } else {
-    CurrentState().pattern = nullptr;
-    CurrentState().sourceSurfCairo = nullptr;
-    CurrentState().sourceSurface = nullptr;
-
-    if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
+      gfxRGBA cms;
+      qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
+      if (transform)
+        gfxPlatform::TransformPixel(c, cms, transform);
 
-        gfxRGBA cms;
-        qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
-        if (transform)
-          gfxPlatform::TransformPixel(c, cms, transform);
-
-        // Use the original alpha to avoid unnecessary float->byte->float
-        // conversion errors
-        CurrentState().color = ToColor(cms);
-    }
-    else
-        CurrentState().color = ToColor(c);
+      // Use the original alpha to avoid unnecessary float->byte->float
+      // conversion errors
+      CurrentState().color = ToColor(cms);
   }
+  else
+      CurrentState().color = ToColor(c);
 }
 
 void
 gfxContext::SetDeviceColor(const gfxRGBA& c)
 {
-  if (mCairo) {
-    cairo_set_source_rgba(mCairo, c.r, c.g, c.b, c.a);
-  } else {
-    CurrentState().pattern = nullptr;
-    CurrentState().sourceSurfCairo = nullptr;
-    CurrentState().sourceSurface = nullptr;
-    CurrentState().color = ToColor(c);
-  }
+  CurrentState().pattern = nullptr;
+  CurrentState().sourceSurfCairo = nullptr;
+  CurrentState().sourceSurface = nullptr;
+  CurrentState().color = ToColor(c);
 }
 
 bool
 gfxContext::GetDeviceColor(gfxRGBA& c)
 {
-  if (mCairo) {
-    return cairo_pattern_get_rgba(cairo_get_source(mCairo),
-                                  &c.r,
-                                  &c.g,
-                                  &c.b,
-                                  &c.a) == CAIRO_STATUS_SUCCESS;
-  } else {
-    if (CurrentState().sourceSurface) {
-      return false;
-    }
-    if (CurrentState().pattern) {
-      gfxRGBA color;
-      return CurrentState().pattern->GetSolidColor(c);
-    }
+  if (CurrentState().sourceSurface) {
+    return false;
+  }
+  if (CurrentState().pattern) {
+    gfxRGBA color;
+    return CurrentState().pattern->GetSolidColor(c);
+  }
 
-    c = ThebesRGBA(CurrentState().color);
-    return true;
-  }
+  c = ThebesRGBA(CurrentState().color);
+  return true;
 }
 
 void
 gfxContext::SetSource(gfxASurface *surface, const gfxPoint& offset)
 {
-  if (mCairo) {
-    NS_ASSERTION(surface->GetAllowUseAsSource(), "Surface not allowed to be used as source!");
-    cairo_set_source_surface(mCairo, surface->CairoSurface(), offset.x, offset.y);
-  } else {
-    CurrentState().surfTransform = Matrix(1.0f, 0, 0, 1.0f, Float(offset.x), Float(offset.y));
-    CurrentState().pattern = nullptr;
-    CurrentState().patternTransformChanged = false;
-    // Keep the underlying cairo surface around while we keep the
-    // sourceSurface.
-    CurrentState().sourceSurfCairo = surface;
-    CurrentState().sourceSurface =
-      gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mDT, surface);
-    CurrentState().color = Color(0, 0, 0, 0);
-  }
+  CurrentState().surfTransform = Matrix(1.0f, 0, 0, 1.0f, Float(offset.x), Float(offset.y));
+  CurrentState().pattern = nullptr;
+  CurrentState().patternTransformChanged = false;
+  // Keep the underlying cairo surface around while we keep the
+  // sourceSurface.
+  CurrentState().sourceSurfCairo = surface;
+  CurrentState().sourceSurface =
+  gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mDT, surface);
+  CurrentState().color = Color(0, 0, 0, 0);
 }
 
 void
 gfxContext::SetPattern(gfxPattern *pattern)
 {
-  if (mCairo) {
-    MOZ_ASSERT(!pattern->IsAzure());
-    cairo_set_source(mCairo, pattern->CairoPattern());
-  } else {
-    CurrentState().sourceSurfCairo = nullptr;
-    CurrentState().sourceSurface = nullptr;
-    CurrentState().patternTransformChanged = false;
-    CurrentState().pattern = pattern;
-  }
+  CurrentState().sourceSurfCairo = nullptr;
+  CurrentState().sourceSurface = nullptr;
+  CurrentState().patternTransformChanged = false;
+  CurrentState().pattern = pattern;
 }
 
 already_AddRefed<gfxPattern>
 gfxContext::GetPattern()
 {
-  if (mCairo) {
-    cairo_pattern_t *pat = cairo_get_source(mCairo);
-    NS_ASSERTION(pat, "I was told this couldn't be null");
+  nsRefPtr<gfxPattern> pat;
 
-    nsRefPtr<gfxPattern> wrapper;
-    if (pat)
-        wrapper = new gfxPattern(pat);
-    else
-        wrapper = new gfxPattern(gfxRGBA(0,0,0,0));
-
-    return wrapper.forget();
+  AzureState &state = CurrentState();
+  if (state.pattern) {
+    pat = state.pattern;
+  } else if (state.sourceSurface) {
+    NS_ASSERTION(false, "Ugh, this isn't good.");
   } else {
-    nsRefPtr<gfxPattern> pat;
-    
-    AzureState &state = CurrentState();
-    if (state.pattern) {
-      pat = state.pattern;
-    } else if (state.sourceSurface) {
-      NS_ASSERTION(false, "Ugh, this isn't good.");
-    } else {
-      pat = new gfxPattern(ThebesRGBA(state.color));
-    }
-    return pat.forget();
+    pat = new gfxPattern(ThebesRGBA(state.color));
   }
+  return pat.forget();
 }
 
 
 // masking
 void
 gfxContext::Mask(gfxPattern *pattern)
 {
-  if (mCairo) {
-    MOZ_ASSERT(!pattern->IsAzure());
-    cairo_mask(mCairo, pattern->CairoPattern());
-  } else {
-    if (pattern->Extend() == gfxPattern::EXTEND_NONE) {
-      // In this situation the mask will be fully transparent (i.e. nothing
-      // will be drawn) outside of the bounds of the surface. We can support
-      // that by clipping out drawing to that area.
-      Point offset;
-      if (pattern->IsAzure()) {
-        // This is an Azure pattern. i.e. this was the result of a PopGroup and
-        // then the extend mode was changed to EXTEND_NONE.
-        // XXX - We may need some additional magic here in theory to support
-        // device offsets in these patterns, but no problems have been observed
-        // yet because of this. And it would complicate things a little further.
-        offset = Point(0.f, 0.f);
-      } else if (pattern->GetType() == gfxPattern::PATTERN_SURFACE) {
-        nsRefPtr<gfxASurface> asurf = pattern->GetSurface();
-        gfxPoint deviceOffset = asurf->GetDeviceOffset();
-        offset = Point(-deviceOffset.x, -deviceOffset.y);
+  if (pattern->Extend() == gfxPattern::EXTEND_NONE) {
+    // In this situation the mask will be fully transparent (i.e. nothing
+    // will be drawn) outside of the bounds of the surface. We can support
+    // that by clipping out drawing to that area.
+    Point offset;
+    if (pattern->IsAzure()) {
+      // This is an Azure pattern. i.e. this was the result of a PopGroup and
+      // then the extend mode was changed to EXTEND_NONE.
+      // XXX - We may need some additional magic here in theory to support
+      // device offsets in these patterns, but no problems have been observed
+      // yet because of this. And it would complicate things a little further.
+      offset = Point(0.f, 0.f);
+    } else if (pattern->GetType() == gfxPattern::PATTERN_SURFACE) {
+      nsRefPtr<gfxASurface> asurf = pattern->GetSurface();
+      gfxPoint deviceOffset = asurf->GetDeviceOffset();
+      offset = Point(-deviceOffset.x, -deviceOffset.y);
 
-        // this lets GetAzureSurface work
-        pattern->GetPattern(mDT);
-      }
+      // this lets GetAzureSurface work
+      pattern->GetPattern(mDT);
+    }
 
-      if (pattern->IsAzure() || pattern->GetType() == gfxPattern::PATTERN_SURFACE) {
-        RefPtr<SourceSurface> mask = pattern->GetAzureSurface();
-        Matrix mat = ToMatrix(pattern->GetInverseMatrix());
-        Matrix old = mTransform;
-        // add in the inverse of the pattern transform so that when we
-        // MaskSurface we are transformed to the place matching the pattern transform
-        mat = mat * mTransform;
+    if (pattern->IsAzure() || pattern->GetType() == gfxPattern::PATTERN_SURFACE) {
+      RefPtr<SourceSurface> mask = pattern->GetAzureSurface();
+      Matrix mat = ToMatrix(pattern->GetInverseMatrix());
+      Matrix old = mTransform;
+      // add in the inverse of the pattern transform so that when we
+      // MaskSurface we are transformed to the place matching the pattern transform
+      mat = mat * mTransform;
 
-        ChangeTransform(mat);
-        mDT->MaskSurface(GeneralPattern(this), mask, offset, DrawOptions(1.0f, CurrentState().op, CurrentState().aaMode));
-        ChangeTransform(old);
-        return;
-      }
+      ChangeTransform(mat);
+      mDT->MaskSurface(GeneralPattern(this), mask, offset, DrawOptions(1.0f, CurrentState().op, CurrentState().aaMode));
+      ChangeTransform(old);
+      return;
     }
-    mDT->Mask(GeneralPattern(this), *pattern->GetPattern(mDT), DrawOptions(1.0f, CurrentState().op, CurrentState().aaMode));
   }
+  mDT->Mask(GeneralPattern(this), *pattern->GetPattern(mDT), DrawOptions(1.0f, CurrentState().op, CurrentState().aaMode));
 }
 
 void
 gfxContext::Mask(gfxASurface *surface, const gfxPoint& offset)
 {
   PROFILER_LABEL("gfxContext", "Mask",
     js::ProfileEntry::Category::GRAPHICS);
 
-  if (mCairo) {
-    cairo_mask_surface(mCairo, surface->CairoSurface(), offset.x, offset.y);
-  } else {
-    // Lifetime needs to be limited here as we may simply wrap surface's data.
-    RefPtr<SourceSurface> sourceSurf =
-      gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mDT, surface);
+  // Lifetime needs to be limited here as we may simply wrap surface's data.
+  RefPtr<SourceSurface> sourceSurf =
+  gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mDT, surface);
 
-    if (!sourceSurf) {
-      return;
-    }
+  if (!sourceSurf) {
+    return;
+  }
 
-    gfxPoint pt = surface->GetDeviceOffset();
+  gfxPoint pt = surface->GetDeviceOffset();
 
-    Mask(sourceSurf, Point(offset.x - pt.x, offset.y - pt.y));
-  }
+  Mask(sourceSurf, Point(offset.x - pt.x, offset.y - pt.y));
 }
 
 void
 gfxContext::Mask(SourceSurface *surface, const Point& offset)
 {
   MOZ_ASSERT(mDT);
 
 
@@ -1541,290 +1038,198 @@ gfxContext::Mask(SourceSurface *surface,
 }
 
 void
 gfxContext::Paint(gfxFloat alpha)
 {
   PROFILER_LABEL("gfxContext", "Paint",
     js::ProfileEntry::Category::GRAPHICS);
 
-  if (mCairo) {
-    cairo_paint_with_alpha(mCairo, alpha);
-  } else {
-    AzureState &state = CurrentState();
+  AzureState &state = CurrentState();
 
-    if (state.sourceSurface && !state.sourceSurfCairo &&
-        !state.patternTransformChanged && !state.opIsClear)
-    {
-      // This is the case where a PopGroupToSource has been done and this
-      // paint is executed without changing the transform or the source.
-      Matrix oldMat = mDT->GetTransform();
+  if (state.sourceSurface && !state.sourceSurfCairo &&
+      !state.patternTransformChanged && !state.opIsClear)
+  {
+    // This is the case where a PopGroupToSource has been done and this
+    // paint is executed without changing the transform or the source.
+    Matrix oldMat = mDT->GetTransform();
 
-      IntSize surfSize = state.sourceSurface->GetSize();
+    IntSize surfSize = state.sourceSurface->GetSize();
 
-      Matrix mat;
-      mat.Translate(-state.deviceOffset.x, -state.deviceOffset.y);
-      mDT->SetTransform(mat);
+    Matrix mat;
+    mat.Translate(-state.deviceOffset.x, -state.deviceOffset.y);
+    mDT->SetTransform(mat);
 
-      mDT->DrawSurface(state.sourceSurface,
-                       Rect(state.sourceSurfaceDeviceOffset, Size(surfSize.width, surfSize.height)),
-                       Rect(Point(), Size(surfSize.width, surfSize.height)),
-                       DrawSurfaceOptions(), DrawOptions(alpha, GetOp()));
-      mDT->SetTransform(oldMat);
-      return;
-    }
+    mDT->DrawSurface(state.sourceSurface,
+                     Rect(state.sourceSurfaceDeviceOffset, Size(surfSize.width, surfSize.height)),
+                     Rect(Point(), Size(surfSize.width, surfSize.height)),
+                     DrawSurfaceOptions(), DrawOptions(alpha, GetOp()));
+    mDT->SetTransform(oldMat);
+    return;
+  }
 
-    Matrix mat = mDT->GetTransform();
-    mat.Invert();
-    Rect paintRect = mat.TransformBounds(Rect(Point(0, 0), Size(mDT->GetSize())));
+  Matrix mat = mDT->GetTransform();
+  mat.Invert();
+  Rect paintRect = mat.TransformBounds(Rect(Point(0, 0), Size(mDT->GetSize())));
 
-    if (state.opIsClear) {
-      mDT->ClearRect(paintRect);
-    } else {
-      mDT->FillRect(paintRect, GeneralPattern(this),
-                    DrawOptions(Float(alpha), GetOp()));
-    }
+  if (state.opIsClear) {
+    mDT->ClearRect(paintRect);
+  } else {
+    mDT->FillRect(paintRect, GeneralPattern(this),
+                  DrawOptions(Float(alpha), GetOp()));
   }
 }
 
 // groups
 
 void
 gfxContext::PushGroup(gfxContentType content)
 {
-  if (mCairo) {
-    cairo_push_group_with_content(mCairo, (cairo_content_t)(int) content);
-  } else {
-    PushNewDT(content);
+  PushNewDT(content);
 
-    PushClipsToDT(mDT);
-    mDT->SetTransform(GetDTTransform());
-  }
+  PushClipsToDT(mDT);
+  mDT->SetTransform(GetDTTransform());
 }
 
 static gfxRect
 GetRoundOutDeviceClipExtents(gfxContext* aCtx)
 {
   gfxContextMatrixAutoSaveRestore save(aCtx);
   aCtx->IdentityMatrix();
   gfxRect r = aCtx->GetClipExtents();
   r.RoundOut();
   return r;
 }
 
-/**
- * Copy the contents of aSrc to aDest, translated by aTranslation.
- */
-static void
-CopySurface(gfxASurface* aSrc, gfxASurface* aDest, const gfxPoint& aTranslation)
-{
-  cairo_t *cr = cairo_create(aDest->CairoSurface());
-  cairo_set_source_surface(cr, aSrc->CairoSurface(), aTranslation.x, aTranslation.y);
-  cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
-  cairo_paint(cr);
-  cairo_destroy(cr);
-}
-
 void
 gfxContext::PushGroupAndCopyBackground(gfxContentType content)
 {
-  if (mCairo) {
-    if (content == gfxContentType::COLOR_ALPHA &&
-      !(GetFlags() & FLAG_DISABLE_COPY_BACKGROUND)) {
-      nsRefPtr<gfxASurface> s = CurrentSurface();
-      if ((s->GetAllowUseAsSource() || s->GetType() == gfxSurfaceType::Tee) &&
-          (s->GetContentType() == gfxContentType::COLOR ||
-              s->GetOpaqueRect().Contains(GetRoundOutDeviceClipExtents(this)))) {
-        cairo_push_group_with_content(mCairo, CAIRO_CONTENT_COLOR);
-        nsRefPtr<gfxASurface> d = CurrentSurface();
+  IntRect clipExtents;
+  if (mDT->GetFormat() != SurfaceFormat::B8G8R8X8) {
+    gfxRect clipRect = GetRoundOutDeviceClipExtents(this);
+    clipExtents = IntRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
+  }
+  if ((mDT->GetFormat() == SurfaceFormat::B8G8R8X8 ||
+       mDT->GetOpaqueRect().Contains(clipExtents)) &&
+      !mDT->GetUserData(&sDontUseAsSourceKey)) {
+    DrawTarget *oldDT = mDT;
+    RefPtr<SourceSurface> source = mDT->Snapshot();
+    Point oldDeviceOffset = CurrentState().deviceOffset;
+
+    PushNewDT(gfxContentType::COLOR);
 
-        if (d->GetType() == gfxSurfaceType::Tee) {
-          NS_ASSERTION(s->GetType() == gfxSurfaceType::Tee, "Mismatched types");
-          nsAutoTArray<nsRefPtr<gfxASurface>,2> ss;
-          nsAutoTArray<nsRefPtr<gfxASurface>,2> ds;
-          static_cast<gfxTeeSurface*>(s.get())->GetSurfaces(&ss);
-          static_cast<gfxTeeSurface*>(d.get())->GetSurfaces(&ds);
-          NS_ASSERTION(ss.Length() == ds.Length(), "Mismatched lengths");
-          gfxPoint translation = d->GetDeviceOffset() - s->GetDeviceOffset();
-          for (uint32_t i = 0; i < ss.Length(); ++i) {
-              CopySurface(ss[i], ds[i], translation);
-          }
-        } else {
-          CopySurface(s, d, gfxPoint(0, 0));
-        }
-        d->SetOpaqueRect(s->GetOpaqueRect());
-        return;
-      }
-    }
-  } else {
-    IntRect clipExtents;
-    if (mDT->GetFormat() != SurfaceFormat::B8G8R8X8) {
-      gfxRect clipRect = GetRoundOutDeviceClipExtents(this);
-      clipExtents = IntRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
-    }
-    if ((mDT->GetFormat() == SurfaceFormat::B8G8R8X8 ||
-         mDT->GetOpaqueRect().Contains(clipExtents)) &&
-        !mDT->GetUserData(&sDontUseAsSourceKey)) {
-      DrawTarget *oldDT = mDT;
-      RefPtr<SourceSurface> source = mDT->Snapshot();
-      Point oldDeviceOffset = CurrentState().deviceOffset;
+    Point offset = CurrentState().deviceOffset - oldDeviceOffset;
+    Rect surfRect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
+    Rect sourceRect = surfRect;
+    sourceRect.x += offset.x;
+    sourceRect.y += offset.y;
 
-      PushNewDT(gfxContentType::COLOR);
-
-      Point offset = CurrentState().deviceOffset - oldDeviceOffset;
-      Rect surfRect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
-      Rect sourceRect = surfRect;
-      sourceRect.x += offset.x;
-      sourceRect.y += offset.y;
+    mDT->SetTransform(Matrix());
+    mDT->DrawSurface(source, surfRect, sourceRect);
+    mDT->SetOpaqueRect(oldDT->GetOpaqueRect());
 
-      mDT->SetTransform(Matrix());
-      mDT->DrawSurface(source, surfRect, sourceRect);
-      mDT->SetOpaqueRect(oldDT->GetOpaqueRect());
-
-      PushClipsToDT(mDT);
-      mDT->SetTransform(GetDTTransform());
-      return;
-    }
+    PushClipsToDT(mDT);
+    mDT->SetTransform(GetDTTransform());
+    return;
   }
   PushGroup(content);
 }
 
 already_AddRefed<gfxPattern>
 gfxContext::PopGroup()
 {
-  if (mCairo) {
-    cairo_pattern_t *pat = cairo_pop_group(mCairo);
-    nsRefPtr<gfxPattern> wrapper = new gfxPattern(pat);
-    cairo_pattern_destroy(pat);
-    return wrapper.forget();
-  } else {
-    RefPtr<SourceSurface> src = mDT->Snapshot();
-    Point deviceOffset = CurrentState().deviceOffset;
+  RefPtr<SourceSurface> src = mDT->Snapshot();
+  Point deviceOffset = CurrentState().deviceOffset;
 
-    Restore();
+  Restore();
 
-    Matrix mat = mTransform;
-    mat.Invert();
+  Matrix mat = mTransform;
+  mat.Invert();
 
-    Matrix deviceOffsetTranslation;
-    deviceOffsetTranslation.Translate(deviceOffset.x, deviceOffset.y);
+  Matrix deviceOffsetTranslation;
+  deviceOffsetTranslation.Translate(deviceOffset.x, deviceOffset.y);
 
-    nsRefPtr<gfxPattern> pat = new gfxPattern(src, deviceOffsetTranslation * mat);
+  nsRefPtr<gfxPattern> pat = new gfxPattern(src, deviceOffsetTranslation * mat);
 
-    return pat.forget();
-  }
+  return pat.forget();
 }
 
 void
 gfxContext::PopGroupToSource()
 {
-  if (mCairo) {
-    cairo_pop_group_to_source(mCairo);
-  } else {
-    RefPtr<SourceSurface> src = mDT->Snapshot();
-    Point deviceOffset = CurrentState().deviceOffset;
-    Restore();
-    CurrentState().sourceSurfCairo = nullptr;
-    CurrentState().sourceSurface = src;
-    CurrentState().sourceSurfaceDeviceOffset = deviceOffset;
-    CurrentState().pattern = nullptr;
-    CurrentState().patternTransformChanged = false;
+  RefPtr<SourceSurface> src = mDT->Snapshot();
+  Point deviceOffset = CurrentState().deviceOffset;
+  Restore();
+  CurrentState().sourceSurfCairo = nullptr;
+  CurrentState().sourceSurface = src;
+  CurrentState().sourceSurfaceDeviceOffset = deviceOffset;
+  CurrentState().pattern = nullptr;
+  CurrentState().patternTransformChanged = false;
 
-    Matrix mat = mTransform;
-    mat.Invert();
+  Matrix mat = mTransform;
+  mat.Invert();
 
-    Matrix deviceOffsetTranslation;
-    deviceOffsetTranslation.Translate(deviceOffset.x, deviceOffset.y);
-    CurrentState().surfTransform = deviceOffsetTranslation * mat;
-  }
+  Matrix deviceOffsetTranslation;
+  deviceOffsetTranslation.Translate(deviceOffset.x, deviceOffset.y);
+  CurrentState().surfTransform = deviceOffsetTranslation * mat;
 }
 
 bool
 gfxContext::PointInFill(const gfxPoint& pt)
 {
-  if (mCairo) {
-    return cairo_in_fill(mCairo, pt.x, pt.y);
-  } else {
-    EnsurePath();
-    return mPath->ContainsPoint(ToPoint(pt), Matrix());
-  }
+  EnsurePath();
+  return mPath->ContainsPoint(ToPoint(pt), Matrix());
 }
 
 bool
 gfxContext::PointInStroke(const gfxPoint& pt)
 {
-  if (mCairo) {
-    return cairo_in_stroke(mCairo, pt.x, pt.y);
-  } else {
-    EnsurePath();
-    return mPath->StrokeContainsPoint(CurrentState().strokeOptions,
-                                      ToPoint(pt),
-                                      Matrix());
-  }
+  EnsurePath();
+  return mPath->StrokeContainsPoint(CurrentState().strokeOptions,
+                                    ToPoint(pt),
+                                    Matrix());
 }
 
 gfxRect
 gfxContext::GetUserPathExtent()
 {
-  if (mCairo) {
-    double xmin, ymin, xmax, ymax;
-    cairo_path_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
-    return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
-  } else {
-    if (mPathIsRect) {
-      return ThebesRect(mTransform.TransformBounds(mRect));
-    }
-    EnsurePath();
-    return ThebesRect(mPath->GetBounds());
+  if (mPathIsRect) {
+    return ThebesRect(mTransform.TransformBounds(mRect));
   }
+  EnsurePath();
+  return ThebesRect(mPath->GetBounds());
 }
 
 gfxRect
 gfxContext::GetUserFillExtent()
 {
-  if (mCairo) {
-    double xmin, ymin, xmax, ymax;
-    cairo_fill_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
-    return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
-  } else {
-    if (mPathIsRect) {
-      return ThebesRect(mTransform.TransformBounds(mRect));
-    }
-    EnsurePath();
-    return ThebesRect(mPath->GetBounds());
+  if (mPathIsRect) {
+    return ThebesRect(mTransform.TransformBounds(mRect));
   }
+  EnsurePath();
+  return ThebesRect(mPath->GetBounds());
 }
 
 gfxRect
 gfxContext::GetUserStrokeExtent()
 {
-  if (mCairo) {
-    double xmin, ymin, xmax, ymax;
-    cairo_stroke_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
-    return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
-  } else {
-    if (mPathIsRect) {
-      Rect rect = mRect;
-      rect.Inflate(CurrentState().strokeOptions.mLineWidth / 2);
-      return ThebesRect(mTransform.TransformBounds(rect));
-    }
-    EnsurePath();
-    return ThebesRect(mPath->GetStrokedBounds(CurrentState().strokeOptions, mTransform));
+  if (mPathIsRect) {
+    Rect rect = mRect;
+    rect.Inflate(CurrentState().strokeOptions.mLineWidth / 2);
+    return ThebesRect(mTransform.TransformBounds(rect));
   }
+  EnsurePath();
+  return ThebesRect(mPath->GetStrokedBounds(CurrentState().strokeOptions, mTransform));
 }
 
 bool
 gfxContext::HasError()
 {
-  if (mCairo) {
-    return cairo_status(mCairo) != CAIRO_STATUS_SUCCESS;
-  } else {
-    // As far as this is concerned, an Azure context is never in error.
-    return false;
-  }
+  // As far as this is concerned, an Azure context is never in error.
+  return false;
 }
 
 void
 gfxContext::RoundedRectangle(const gfxRect& rect,
                              const gfxCornerSizes& corners,
                              bool draw_clockwise)
 {
     //
@@ -1892,83 +1297,22 @@ gfxContext::RoundedRectangle(const gfxRe
     // follows different constraints, and Goldapp's expression for
     // 'alpha' gives much smaller radial error, even for very flat
     // ellipses, than Maisonobe's equivalent.
     //
     // For the various corners and for each axis, the sign of this
     // constant changes, or it might be 0 -- it's multiplied by the
     // appropriate multiplier from the list before using.
 
-  if (mCairo) {
-    const gfxFloat alpha = 0.55191497064665766025;
-
-    typedef struct { gfxFloat a, b; } twoFloats;
-
-    twoFloats cwCornerMults[4] = { { -1,  0 },
-                                   {  0, -1 },
-                                   { +1,  0 },
-                                   {  0, +1 } };
-    twoFloats ccwCornerMults[4] = { { +1,  0 },
-                                    {  0, -1 },
-                                    { -1,  0 },
-                                    {  0, +1 } };
-
-    twoFloats *cornerMults = draw_clockwise ? cwCornerMults : ccwCornerMults;
-
-    gfxPoint pc, p0, p1, p2, p3;
-
-    if (draw_clockwise)
-        cairo_move_to(mCairo, rect.X() + corners[NS_CORNER_TOP_LEFT].width, rect.Y());
-    else
-        cairo_move_to(mCairo, rect.X() + rect.Width() - corners[NS_CORNER_TOP_RIGHT].width, rect.Y());
-
-    NS_FOR_CSS_CORNERS(i) {
-        // the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw)
-        mozilla::css::Corner c = mozilla::css::Corner(draw_clockwise ? ((i+1) % 4) : ((4-i) % 4));
-
-        // i+2 and i+3 respectively.  These are used to index into the corner
-        // multiplier table, and were deduced by calculating out the long form
-        // of each corner and finding a pattern in the signs and values.
-        int i2 = (i+2) % 4;
-        int i3 = (i+3) % 4;
-
-        pc = rect.AtCorner(c);
-
-        if (corners[c].width > 0.0 && corners[c].height > 0.0) {
-            p0.x = pc.x + cornerMults[i].a * corners[c].width;
-            p0.y = pc.y + cornerMults[i].b * corners[c].height;
-
-            p3.x = pc.x + cornerMults[i3].a * corners[c].width;
-            p3.y = pc.y + cornerMults[i3].b * corners[c].height;
-
-            p1.x = p0.x + alpha * cornerMults[i2].a * corners[c].width;
-            p1.y = p0.y + alpha * cornerMults[i2].b * corners[c].height;
-
-            p2.x = p3.x - alpha * cornerMults[i3].a * corners[c].width;
-            p2.y = p3.y - alpha * cornerMults[i3].b * corners[c].height;
-
-            cairo_line_to (mCairo, p0.x, p0.y);
-            cairo_curve_to (mCairo,
-                            p1.x, p1.y,
-                            p2.x, p2.y,
-                            p3.x, p3.y);
-        } else {
-            cairo_line_to (mCairo, pc.x, pc.y);
-        }
-    }
-
-    cairo_close_path (mCairo);
-  } else {
-    EnsurePathBuilder();
-    Size radii[] = { ToSize(corners[NS_CORNER_TOP_LEFT]),
-                     ToSize(corners[NS_CORNER_TOP_RIGHT]),
-                     ToSize(corners[NS_CORNER_BOTTOM_RIGHT]),
-                     ToSize(corners[NS_CORNER_BOTTOM_LEFT]) };
-    AppendRoundedRectToPath(mPathBuilder, ToRect(rect), radii, draw_clockwise);
-  }
+  EnsurePathBuilder();
+  Size radii[] = { ToSize(corners[NS_CORNER_TOP_LEFT]),
+                   ToSize(corners[NS_CORNER_TOP_RIGHT]),
+                   ToSize(corners[NS_CORNER_BOTTOM_RIGHT]),
+                   ToSize(corners[NS_CORNER_BOTTOM_LEFT]) };
+  AppendRoundedRectToPath(mPathBuilder, ToRect(rect), radii, draw_clockwise);
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
 gfxContext::WriteAsPNG(const char* aFile)
 {
   if (mDT) {
     gfxUtils::WriteAsPNG(mDT, aFile);
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -36,20 +36,16 @@ template <typename T> class FallibleTArr
  *
  * Note that the gfxContext takes coordinates in device pixels,
  * as opposed to app units.
  */
 class gfxContext MOZ_FINAL {
     NS_INLINE_DECL_REFCOUNTING(gfxContext)
 
 public:
-    /**
-     * Initialize this context from a surface.
-     */
-    gfxContext(gfxASurface *surface);
 
     /**
      * Initialize this context from a DrawTarget.
      * Strips any transform from aTarget.
      * aTarget will be flushed in the gfxContext's destructor.
      */
     gfxContext(mozilla::gfx::DrawTarget *aTarget,
                const mozilla::gfx::Point& aDeviceOffset = mozilla::gfx::Point());
@@ -684,18 +680,16 @@ public:
          */
         FLAG_DISABLE_COPY_BACKGROUND = (1 << 2)
     };
 
     void SetFlag(int32_t aFlag) { mFlags |= aFlag; }
     void ClearFlag(int32_t aFlag) { mFlags &= ~aFlag; }
     int32_t GetFlags() const { return mFlags; }
 
-    bool IsCairo() const { return !mDT; }
-
     // Work out whether cairo will snap inter-glyph spacing to pixels.
     void GetRoundOffsetsToPixels(bool *aRoundX, bool *aRoundY);
 
 #ifdef MOZ_DUMP_PAINTING
     /**
      * Debug functions to encode the current surface as a PNG and export it.
      */
 
@@ -793,17 +787,16 @@ private:
   mozilla::RefPtr<PathBuilder> mPathBuilder;
   mozilla::RefPtr<Path> mPath;
   Matrix mTransform;
   nsTArray<AzureState> mStateStack;
 
   AzureState &CurrentState() { return mStateStack[mStateStack.Length() - 1]; }
   const AzureState &CurrentState() const { return mStateStack[mStateStack.Length() - 1]; }
 
-  cairo_t *mCairo;
   cairo_t *mRefCairo;
   nsRefPtr<gfxASurface> mSurface;
   int32_t mFlags;
 
   mozilla::RefPtr<DrawTarget> mDT;
   mozilla::RefPtr<DrawTarget> mOriginalDT;
 };
 
@@ -960,29 +953,19 @@ private:
 };
 
 
 class gfxContextAutoDisableSubpixelAntialiasing {
 public:
     gfxContextAutoDisableSubpixelAntialiasing(gfxContext *aContext, bool aDisable)
     {
         if (aDisable) {
-            if (aContext->IsCairo()) {
-                mSurface = aContext->CurrentSurface();
-                if (!mSurface) {
-                  return;
-                }
-                mSubpixelAntialiasingEnabled = mSurface->GetSubpixelAntialiasingEnabled();
-                mSurface->SetSubpixelAntialiasingEnabled(false);
-            } else {
-                mDT = aContext->GetDrawTarget();
-
-                mSubpixelAntialiasingEnabled = mDT->GetPermitSubpixelAA();
-                mDT->SetPermitSubpixelAA(false);
-            }
+            mDT = aContext->GetDrawTarget();
+            mSubpixelAntialiasingEnabled = mDT->GetPermitSubpixelAA();
+            mDT->SetPermitSubpixelAA(false);
         }
     }
     ~gfxContextAutoDisableSubpixelAntialiasing()
     {
         if (mSurface) {
             mSurface->SetSubpixelAntialiasingEnabled(mSubpixelAntialiasingEnabled);
         } else if (mDT) {
             mDT->SetPermitSubpixelAA(mSubpixelAntialiasingEnabled);
--- a/gfx/thebes/gfxDrawable.cpp
+++ b/gfx/thebes/gfxDrawable.cpp
@@ -125,24 +125,18 @@ bool
 gfxSurfaceDrawable::Draw(gfxContext* aContext,
                          const gfxRect& aFillRect,
                          bool aRepeat,
                          const GraphicsFilter& aFilter,
                          const gfxMatrix& aTransform)
 {
     nsRefPtr<gfxPattern> pattern;
     if (mDrawTarget) {
-      if (aContext->IsCairo()) {
-        nsRefPtr<gfxASurface> source =
-          gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
-        pattern = new gfxPattern(source);
-      } else {
-        RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
-        pattern = new gfxPattern(source, Matrix());
-      }
+      RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
+      pattern = new gfxPattern(source, Matrix());
     } else if (mSourceSurface) {
       pattern = new gfxPattern(mSourceSurface, Matrix());
     } else {
       pattern = new gfxPattern(mSurface);
     }
     if (aRepeat) {
         pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
         pattern->SetFilter(aFilter);
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -3154,17 +3154,16 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint
     if (aStart >= aEnd)
         return;
 
     const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
     const int32_t appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
     const double devUnitsPerAppUnit = 1.0/double(appUnitsPerDevUnit);
     bool isRTL = aTextRun->IsRightToLeft();
     double direction = aTextRun->GetDirection();
-    gfxMatrix globalMatrix = aContext->CurrentMatrix();
 
     bool haveSVGGlyphs = GetFontEntry()->TryGetSVGData(this);
     bool haveColorGlyphs = GetFontEntry()->TryGetColorGlyphs();
     nsAutoPtr<gfxTextContextPaint> contextPaint;
     if (haveSVGGlyphs && !aContextPaint) {
         // If no pattern is specified for fill, use the current pattern
         NS_ASSERTION((int(aDrawMode) & int(DrawMode::GLYPH_STROKE)) == 0, "no pattern supplied for stroking text");
         nsRefPtr<gfxPattern> fillPattern = aContext->GetPattern();
@@ -3186,212 +3185,22 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint
         }
     }
 
     uint32_t i;
     // Current position in appunits
     double x = aPt->x;
     double y = aPt->y;
 
-    cairo_t *cr = aContext->GetCairo();
     RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
 
     bool paintSVGGlyphs = !aCallbacks || aCallbacks->mShouldPaintSVGGlyphs;
     bool emittedGlyphs = false;
 
-    if (aContext->IsCairo()) {
-      bool success = SetupCairoFont(aContext);
-      if (MOZ_UNLIKELY(!success))
-          return;
-
-      ::GlyphBuffer glyphs;
-      cairo_glyph_t *glyph;
-
-      if (aSpacing) {
-          x += direction*aSpacing[0].mBefore;
-      }
-      for (i = aStart; i < aEnd; ++i) {
-          const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
-          if (glyphData->IsSimpleGlyph()) {
-              double advance = glyphData->GetSimpleAdvance();
-              double glyphX;
-              if (isRTL) {
-                  x -= advance;
-                  glyphX = x;
-              } else {
-                  glyphX = x;
-                  x += advance;
-              }
-
-              if (haveSVGGlyphs) {
-                  if (!paintSVGGlyphs) {
-                      continue;
-                  }
-                  gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
-                                 ToDeviceUnits(y, devUnitsPerAppUnit));
-                  DrawMode mode = ForcePaintingDrawMode(aDrawMode);
-                  if (RenderSVGGlyph(aContext, point, mode,
-                                     glyphData->GetSimpleGlyph(), aContextPaint,
-                                     aCallbacks, emittedGlyphs)) {
-                      continue;
-                  }
-              }
-
-              if (haveColorGlyphs) {
-                  gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
-                                 ToDeviceUnits(y, devUnitsPerAppUnit));
-                  if (RenderColorGlyph(aContext, point, glyphData->GetSimpleGlyph())) {
-                      continue;
-                  }
-              }
-
-              // Perhaps we should put a scale in the cairo context instead of
-              // doing this scaling here...
-              // Multiplying by the reciprocal may introduce tiny error here,
-              // but we assume cairo is going to round coordinates at some stage
-              // and this is faster
-              glyph = glyphs.AppendGlyph();
-              glyph->index = glyphData->GetSimpleGlyph();
-              glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
-              glyph->y = ToDeviceUnits(y, devUnitsPerAppUnit);
-              glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
-            
-              // synthetic bolding by multi-striking with 1-pixel offsets
-              // at least once, more if there's room (large font sizes)
-              if (IsSyntheticBold()) {
-                  double strikeOffset = synBoldOnePixelOffset;
-                  int32_t strikeCount = strikes;
-                  do {
-                      cairo_glyph_t *doubleglyph;
-                      doubleglyph = glyphs.AppendGlyph();
-                      doubleglyph->index = glyph->index;
-                      doubleglyph->x =
-                          ToDeviceUnits(glyphX + strikeOffset * appUnitsPerDevUnit,
-                                        devUnitsPerAppUnit);
-                      doubleglyph->y = glyph->y;
-                      strikeOffset += synBoldOnePixelOffset;
-                      glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
-                  } while (--strikeCount > 0);
-              }
-              emittedGlyphs = true;
-          } else {
-              uint32_t glyphCount = glyphData->GetGlyphCount();
-              if (glyphCount > 0) {
-                  const gfxTextRun::DetailedGlyph *details =
-                      aTextRun->GetDetailedGlyphs(i);
-                  NS_ASSERTION(details, "detailedGlyph should not be missing!");
-                  double advance;
-                  for (uint32_t j = 0; j < glyphCount; ++j, ++details, x += direction * advance) {
-                      advance = details->mAdvance;
-                      if (glyphData->IsMissing()) {
-                          // default ignorable characters will have zero advance width.
-                          // we don't have to draw the hexbox for them
-                          if (aDrawMode != DrawMode::GLYPH_PATH && advance > 0) {
-                              double glyphX = x;
-                              if (isRTL) {
-                                  glyphX -= advance;
-                              }
-                              gfxPoint pt(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
-                                          ToDeviceUnits(y, devUnitsPerAppUnit));
-                              gfxFloat advanceDevUnits = ToDeviceUnits(advance, devUnitsPerAppUnit);
-                              gfxFloat height = GetMetrics().maxAscent;
-                              gfxRect glyphRect(pt.x, pt.y - height, advanceDevUnits, height);
-                              gfxFontMissingGlyphs::DrawMissingGlyph(aContext,
-                                                                     glyphRect,
-                                                                     details->mGlyphID,
-                                                                     appUnitsPerDevUnit);
-                          }
-                      } else {
-                          double glyphX = x + details->mXOffset;
-                          if (isRTL) {
-                              glyphX -= advance;
-                          }
-
-                          if (haveSVGGlyphs) {
-                              if (!paintSVGGlyphs) {
-                                  continue;
-                              }
-
-                              gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
-                                             ToDeviceUnits(y, devUnitsPerAppUnit));
-
-                              DrawMode mode = ForcePaintingDrawMode(aDrawMode);
-                              if (RenderSVGGlyph(aContext, point, mode,
-                                                  details->mGlyphID,
-                                                  aContextPaint, aCallbacks,
-                                                  emittedGlyphs)) {
-                                  continue;
-                              }
-                          }
-
-                          if (haveColorGlyphs) {
-                              gfxPoint point(ToDeviceUnits(glyphX,
-                                                           devUnitsPerAppUnit),
-                                             ToDeviceUnits(y + details->mYOffset,
-                                                           devUnitsPerAppUnit));
-                              if (RenderColorGlyph(aContext, point,
-                                                   details->mGlyphID)) {
-                                  continue;
-                              }
-                          }
-
-                          glyph = glyphs.AppendGlyph();
-                          glyph->index = details->mGlyphID;
-                          glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
-                          glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
-                          glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
-
-                          if (IsSyntheticBold()) {
-                              double strikeOffset = synBoldOnePixelOffset;
-                              int32_t strikeCount = strikes;
-                              do {
-                                  cairo_glyph_t *doubleglyph;
-                                  doubleglyph = glyphs.AppendGlyph();
-                                  doubleglyph->index = glyph->index;
-                                  doubleglyph->x =
-                                      ToDeviceUnits(glyphX + strikeOffset *
-                                              appUnitsPerDevUnit,
-                                              devUnitsPerAppUnit);
-                                  doubleglyph->y = glyph->y;
-                                  strikeOffset += synBoldOnePixelOffset;
-                                  glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix);
-                              } while (--strikeCount > 0);
-                          }
-                          emittedGlyphs = true;
-                      }
-                  }
-              }
-          }
-
-          if (aSpacing) {
-              double space = aSpacing[i - aStart].mAfter;
-              if (i + 1 < aEnd) {
-                  space += aSpacing[i + 1 - aStart].mBefore;
-              }
-              x += direction*space;
-          }
-      }
-
-      if (gfxFontTestStore::CurrentStore()) {
-          /* This assumes that the tests won't have anything that results
-           * in more than GLYPH_BUFFER_SIZE glyphs.  Do this before we
-           * flush, since that'll blow away the num_glyphs.
-           */
-          gfxFontTestStore::CurrentStore()->AddItem(GetName(),
-                                                    glyphs.mGlyphBuffer,
-                                                    glyphs.mNumGlyphs);
-      }
-
-      // draw any remaining glyphs
-      glyphs.Flush(cr, aDrawMode, isRTL, aContextPaint, globalMatrix, true);
-      if (aCallbacks && emittedGlyphs) {
-          aCallbacks->NotifyGlyphPathEmitted();
-      }
-
-    } else {
+    {
       RefPtr<ScaledFont> scaledFont = GetScaledFont(dt);
 
       if (!scaledFont) {
         return;
       }
 
       bool oldSubpixelAA = dt->GetPermitSubpixelAA();
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -822,30 +822,16 @@ gfxPlatform::GetScaledFontForFont(DrawTa
   nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
   nativeFont.mFont = aFont->GetCairoScaledFont();
   RefPtr<ScaledFont> scaledFont =
     Factory::CreateScaledFontForNativeFont(nativeFont,
                                            aFont->GetAdjustedSize());
   return scaledFont;
 }
 
-cairo_user_data_key_t kDrawSourceSurface;
-static void
-DataSourceSurfaceDestroy(void *dataSourceSurface)
-{
-  static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
-}
-
-cairo_user_data_key_t kDrawTargetForSurface;
-static void
-DataDrawTargetDestroy(void *aTarget)
-{
-  static_cast<DrawTarget*>(aTarget)->Release();
-}
-
 bool
 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
 {
   if (!aTarget) {
     return false;
   }
 
   return SupportsAzureContentForType(aTarget->GetBackendType());
@@ -921,59 +907,16 @@ gfxPlatform::PurgeSkiaCache()
 #ifdef USE_SKIA_GPU
   if (!mSkiaGlue)
       return;
 
   mSkiaGlue->GetGrContext()->freeGpuResources();
 #endif
 }
 
-already_AddRefed<gfxASurface>
-gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
-{
-  if (aTarget->GetBackendType() == BackendType::CAIRO) {
-    cairo_surface_t* csurf =
-      static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));
-    if (csurf) {
-      return gfxASurface::Wrap(csurf);
-    }
-  }
-
-  // The semantics of this part of the function are sort of weird. If we
-  // don't have direct support for the backend, we snapshot the first time
-  // and then return the snapshotted surface for the lifetime of the draw
-  // target. Sometimes it seems like this works out, but it seems like it
-  // might result in no updates ever.
-  RefPtr<SourceSurface> source = aTarget->Snapshot();
-  RefPtr<DataSourceSurface> data = source->GetDataSurface();
-
-  if (!data) {
-    return nullptr;
-  }
-
-  IntSize size = data->GetSize();
-  gfxImageFormat format = SurfaceFormatToImageFormat(data->GetFormat());
-
-
-  nsRefPtr<gfxASurface> surf =
-    new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
-                        data->Stride(), format);
-
-  if (surf->CairoStatus()) {
-    return nullptr;
-  }
-
-  surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
-  // keep the draw target alive as long as we need its data
-  aTarget->AddRef();
-  surf->SetData(&kDrawTargetForSurface, aTarget, DataDrawTargetDestroy);
-
-  return surf.forget();
-}
-
 TemporaryRef<DrawTarget>
 gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
 {
   // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
   // create the best offscreen surface for the current system and situation. We
   // can easily take advantage of this for the Cairo backend, so that's what we
   // do.
   // mozilla::gfx::Factory can get away without having all this knowledge for
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -217,19 +217,16 @@ public:
     static void ClearSourceSurfaceForSurface(gfxASurface *aSurface);
 
     static mozilla::TemporaryRef<DataSourceSurface>
         GetWrappedDataSourceSurface(gfxASurface *aSurface);
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
 
-    virtual already_AddRefed<gfxASurface>
-      GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
-
     mozilla::TemporaryRef<DrawTarget>
       CreateOffscreenContentDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
 
     mozilla::TemporaryRef<DrawTarget>
       CreateOffscreenCanvasDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
 
     virtual mozilla::TemporaryRef<DrawTarget>
       CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize, 
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -375,45 +375,16 @@ gfxPlatformMac::ReadAntiAliasingThreshol
             threshold = 0;
         }
         CFRelease(prefValue);
     }
 
     return threshold;
 }
 
-already_AddRefed<gfxASurface>
-gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
-{
-  if (aTarget->GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED) {
-    RefPtr<SourceSurface> source = aTarget->Snapshot();
-    RefPtr<DataSourceSurface> sourceData = source->GetDataSurface();
-    unsigned char* data = sourceData->GetData();
-    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(data, ThebesIntSize(sourceData->GetSize()), sourceData->Stride(),
-                                                         gfxImageFormat::ARGB32);
-    // We could fix this by telling gfxImageSurface it owns data.
-    nsRefPtr<gfxImageSurface> cpy = new gfxImageSurface(ThebesIntSize(sourceData->GetSize()), gfxImageFormat::ARGB32);
-    cpy->CopyFrom(surf);
-    return cpy.forget();
-  } else if (aTarget->GetBackendType() == BackendType::COREGRAPHICS) {
-    CGContextRef cg = static_cast<CGContextRef>(aTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT));
-
-    //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize
-    IntSize intSize = aTarget->GetSize();
-    gfxIntSize size(intSize.width, intSize.height);
-
-    nsRefPtr<gfxASurface> surf =
-      new gfxQuartzSurface(cg, size);
-
-    return surf.forget();
-  }
-
-  return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
-}
-
 bool
 gfxPlatformMac::UseAcceleratedCanvas()
 {
   // Lion or later is required
   return nsCocoaFeatures::OnLionOrLater() && Preferences::GetBool("gfx.canvas.azure.accelerated", false);
 }
 
 void
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -59,18 +59,16 @@ public:
                                         int32_t aRunScript,
                                         nsTArray<const char*>& aFontList);
 
     bool UseAcceleratedCanvas();
 
     // lower threshold on font anti-aliasing
     uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
 
-    virtual already_AddRefed<gfxASurface>
-    GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
 private:
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
 
     // read in the pref value for the lower threshold on font anti-aliasing
     static uint32_t ReadAntiAliasingThreshold();
 
     uint32_t mFontAntiAliasingThreshold;
 };
--- a/gfx/thebes/gfxQuartzNativeDrawing.cpp
+++ b/gfx/thebes/gfxQuartzNativeDrawing.cpp
@@ -22,23 +22,16 @@ gfxQuartzNativeDrawing::gfxQuartzNativeD
   mNativeRect.RoundOut();
 }
 
 CGContextRef
 gfxQuartzNativeDrawing::BeginNativeDrawing()
 {
   NS_ASSERTION(!mCGContext, "BeginNativeDrawing called when drawing already in progress");
 
-  if (mContext->IsCairo()) {
-    // We're past that now. Any callers that still supply a Cairo context
-    // don't deserve native theming.
-    NS_WARNING("gfxQuartzNativeDrawing being used with a gfxContext that is not backed by a DrawTarget");
-    return nullptr;
-  }
-
   DrawTarget *dt = mContext->GetDrawTarget();
   if (dt->GetBackendType() != BackendType::COREGRAPHICS || dt->IsDualDrawTarget()) {
     IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
                         NSToIntFloor(mNativeRect.height * mBackingScale));
 
     if (backingSize.IsEmpty()) {
       return nullptr;
     }
@@ -57,17 +50,16 @@ gfxQuartzNativeDrawing::BeginNativeDrawi
   MOZ_ASSERT(mCGContext);
   return mCGContext;
 }
 
 void
 gfxQuartzNativeDrawing::EndNativeDrawing()
 {
   NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");
-  MOZ_ASSERT(!mContext->IsCairo(), "BeginNativeDrawing succeeded with cairo context?");
 
   mBorrowedContext.Finish();
   if (mDrawTarget) {
     DrawTarget *dest = mContext->GetDrawTarget();
     RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
 
     IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
                         NSToIntFloor(mNativeRect.height * mBackingScale));
--- a/gfx/thebes/gfxWindowsNativeDrawing.cpp
+++ b/gfx/thebes/gfxWindowsNativeDrawing.cpp
@@ -178,19 +178,18 @@ gfxWindowsNativeDrawing::BeginNativeDraw
         NS_ERROR("Bogus render state!");
         return nullptr;
     }
 }
 
 bool
 gfxWindowsNativeDrawing::IsDoublePass()
 {
-    if (!mContext->IsCairo() &&
-        (mContext->GetDrawTarget()->GetBackendType() != mozilla::gfx::BackendType::CAIRO ||
-         mContext->GetDrawTarget()->IsDualDrawTarget())) {
+    if (mContext->GetDrawTarget()->GetBackendType() != mozilla::gfx::BackendType::CAIRO ||
+        mContext->GetDrawTarget()->IsDualDrawTarget()) {
       return true;
     }
 
     nsRefPtr<gfxASurface> surf = mContext->CurrentSurface(&mDeviceOffset.x, &mDeviceOffset.y);
     if (!surf || surf->CairoStatus())
         return false;
     if (surf->GetType() != gfxSurfaceType::Win32 &&
         surf->GetType() != gfxSurfaceType::Win32Printing) {
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -642,47 +642,16 @@ gfxWindowsPlatform::GetScaledFontForFont
       return Factory::CreateScaledFontWithCairo(nativeFont,
                                                 aFont->GetAdjustedSize(),
                                                 aFont->GetCairoScaledFont());
     }
 
     return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
 }
 
-already_AddRefed<gfxASurface>
-gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
-{
-#ifdef XP_WIN
-  if (aTarget->GetBackendType() == BackendType::DIRECT2D) {
-    if (!GetD2DDevice()) {
-      // We no longer have a D2D device, can't do this.
-      return nullptr;
-    }
-
-    RefPtr<ID3D10Texture2D> texture =
-      static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NativeSurfaceType::D3D10_TEXTURE));
-
-    if (!texture) {
-      return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
-    }
-
-    aTarget->Flush();
-
-    nsRefPtr<gfxASurface> surf =
-      new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat()));
-
-    // shouldn't this hold a reference?
-    surf->SetData(&kDrawTarget, aTarget, nullptr);
-    return surf.forget();
-  }
-#endif
-
-  return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
-}
-
 nsresult
 gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup,
                                 const nsACString& aGenericFamily,
                                 nsTArray<nsString>& aListOfFonts)
 {
     gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
 
     return NS_OK;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -55,17 +55,16 @@ struct IDXGIAdapter1;
 class nsIMemoryReporter;
 
 // Utility to get a Windows HDC from a thebes context,
 // used by both GDI and Uniscribe font shapers
 struct DCFromContext {
     DCFromContext(gfxContext *aContext) {
         dc = nullptr;
         nsRefPtr<gfxASurface> aSurface = aContext->CurrentSurface();
-        NS_ASSERTION(aSurface || !aContext->IsCairo(), "DCFromContext: null surface");
         if (aSurface &&
             (aSurface->GetType() == gfxSurfaceType::Win32 ||
              aSurface->GetType() == gfxSurfaceType::Win32Printing))
         {
             dc = static_cast<gfxWindowsSurface*>(aSurface.get())->GetDC();
             needsRelease = false;
             SaveDC(dc);
             cairo_scaled_font_t* scaled =
@@ -126,18 +125,16 @@ public:
     virtual gfxPlatformFontList* CreatePlatformFontList();
 
     virtual already_AddRefed<gfxASurface>
       CreateOffscreenSurface(const IntSize& size,
                              gfxContentType contentType) MOZ_OVERRIDE;
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
-    virtual already_AddRefed<gfxASurface>
-      GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
 
     enum RenderMode {
         /* Use GDI and windows surfaces */
         RENDER_GDI = 0,
 
         /* Use 32bpp image surfaces and call StretchDIBits */
         RENDER_IMAGE_STRETCH32,
 
--- a/gfx/thebes/gfxXlibNativeRenderer.cpp
+++ b/gfx/thebes/gfxXlibNativeRenderer.cpp
@@ -135,20 +135,16 @@ FINISH:
  * Try the direct path.
  * @return True if we took the direct path
  */
 bool
 gfxXlibNativeRenderer::DrawDirect(gfxContext *ctx, nsIntSize size,
                                   uint32_t flags,
                                   Screen *screen, Visual *visual)
 {
-    if (ctx->IsCairo()) {
-        return DrawCairo(ctx->GetCairo(), size, flags, screen, visual);
-    }
-
     // We need to actually borrow the context because we want to read out the
     // clip rectangles.
     BorrowedCairoContext borrowed(ctx->GetDrawTarget());
     if (!borrowed.mCairo) {
       return false;
     }
 
     bool direct = DrawCairo(borrowed.mCairo, size, flags, screen, visual);
@@ -524,29 +520,21 @@ gfxXlibNativeRenderer::Draw(gfxContext* 
                          int32_t(clipExtents.Y()),
                          int32_t(clipExtents.Width()),
                          int32_t(clipExtents.Height()));
     drawingRect.IntersectRect(drawingRect, intExtents);
 
     gfxPoint offset(drawingRect.x, drawingRect.y);
 
     DrawingMethod method;
-    cairo_surface_t* cairoTarget = nullptr;
-    DrawTarget* drawTarget = nullptr;
-    gfxPoint deviceTranslation;
-    if (ctx->IsCairo()) {
-        cairoTarget = cairo_get_group_target(ctx->GetCairo());
-        deviceTranslation = ctx->CurrentMatrix().GetTranslation();
-    } else {
-        drawTarget = ctx->GetDrawTarget();
-        Matrix dtTransform = drawTarget->GetTransform();
-        deviceTranslation = gfxPoint(dtTransform._31, dtTransform._32);
-        cairoTarget = static_cast<cairo_surface_t*>
+    DrawTarget* drawTarget = ctx->GetDrawTarget();
+    Matrix dtTransform = drawTarget->GetTransform();
+    gfxPoint deviceTranslation = gfxPoint(dtTransform._31, dtTransform._32);
+    cairo_surface_t* cairoTarget = static_cast<cairo_surface_t*>
             (drawTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));
-    }
 
     cairo_surface_t* tempXlibSurface =
         CreateTempXlibSurface(cairoTarget, drawTarget, size,
                               canDrawOverBackground, flags, screen, visual,
                               &method);
     if (!tempXlibSurface)
         return;
 
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -388,30 +388,16 @@ bool imgFrame::Draw(gfxContext *aContext
 
   bool doPadding = aPadding != nsIntMargin(0,0,0,0);
   bool doPartialDecode = !ImageComplete();
 
   if (mSinglePixel && !doPadding && !doPartialDecode) {
     if (mSinglePixelColor.a == 0.0) {
       return true;
     }
-
-    if (aContext->IsCairo()) {
-      gfxContext::GraphicsOperator op = aContext->CurrentOperator();
-      if (op == gfxContext::OPERATOR_OVER && mSinglePixelColor.a == 1.0) {
-        aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
-      }
-      aContext->SetDeviceColor(ThebesColor(mSinglePixelColor));
-      aContext->NewPath();
-      aContext->Rectangle(aFill);
-      aContext->Fill();
-      aContext->SetOperator(op);
-      aContext->SetDeviceColor(gfxRGBA(0,0,0,0));
-      return true;
-    }
     RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
     dt->FillRect(ToRect(aFill),
                  ColorPattern(mSinglePixelColor),
                  DrawOptions(1.0f,
                              CompositionOpForOp(aContext->CurrentOperator())));
     return true;
   }
 
--- a/ipc/chromium/Makefile.in
+++ b/ipc/chromium/Makefile.in
@@ -27,12 +27,14 @@ OS_CXXFLAGS += $(TK_CFLAGS)
 include $(topsrcdir)/config/rules.mk
 
 ifdef MOZ_NATIVE_LIBEVENT # {
 
 export-preqs = \
   $(call mkdir_deps,$(CURDIR)/third_party/libevent) \
   $(NULL)
 
-export:: $(export-preqs)
+export:: $(DIST)/third_party/libevent/event.h
+
+$(DIST)/third_party/libevent/event.h:: $(export-preqs)
 	echo '#include <event.h>' > $(CURDIR)/third_party/libevent/event.h
 
 endif # }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -328,16 +328,17 @@ static const char * const statementName[
     "try block",             /* TRY */
     js_finally_block_str,    /* FINALLY */
     js_finally_block_str,    /* SUBROUTINE */
     "do loop",               /* DO_LOOP */
     "for loop",              /* FOR_LOOP */
     "for/in loop",           /* FOR_IN_LOOP */
     "for/of loop",           /* FOR_OF_LOOP */
     "while loop",            /* WHILE_LOOP */
+    "spread",                /* SPREAD */
 };
 
 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT);
 
 static const char *
 StatementName(StmtInfoBCE *topStmt)
 {
     if (!topStmt)
@@ -598,16 +599,20 @@ NonLocalExitScope::prepareForNonLocalJum
             break;
 
           case STMT_FOR_IN_LOOP:
             FLUSH_POPS();
             if (!PopIterator(cx, bce))
                 return false;
             break;
 
+          case STMT_SPREAD:
+            MOZ_ASSERT_UNREACHABLE("can't break/continue/return from inside a spread");
+            break;
+
           case STMT_SUBROUTINE:
             /*
              * There's a [exception or hole, retsub pc-index] pair on the
              * stack that we need to pop.
              */
             npops += 2;
             break;
 
@@ -701,23 +706,27 @@ PushLoopStatement(BytecodeEmitter *bce, 
             break;
         }
     }
 
     stmt->stackDepth = bce->stackDepth;
     stmt->loopDepth = downLoop ? downLoop->loopDepth + 1 : 1;
 
     int loopSlots;
-    if (type == STMT_FOR_OF_LOOP)
+    if (type == STMT_SPREAD)
+        loopSlots = 3;
+    else if (type == STMT_FOR_OF_LOOP)
         loopSlots = 2;
     else if (type == STMT_FOR_IN_LOOP)
         loopSlots = 1;
     else
         loopSlots = 0;
 
+    MOZ_ASSERT(loopSlots <= stmt->stackDepth);
+
     if (downLoop)
         stmt->canIonOsr = (downLoop->canIonOsr &&
                            stmt->stackDepth == downLoop->stackDepth + loopSlots);
     else
         stmt->canIonOsr = stmt->stackDepth == loopSlots;
 }
 
 /*
@@ -4431,147 +4440,191 @@ EmitIterator(ExclusiveContext *cx, Bytec
     if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // @@ITERATOR OBJ
         return false;
     if (EmitCall(cx, bce, JSOP_CALL, 0) < 0)                   // ITER
         return false;
     CheckTypeSet(cx, bce, JSOP_CALL);
     return true;
 }
 
+/**
+ * If type is STMT_FOR_OF_LOOP, it emits bytecode for for-of loop.
+ * pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
+ *
+ * If type is STMT_SPREAD, it emits bytecode for spread operator.
+ * pn should be nullptr.
+ * Please refer the comment above EmitSpread for additional information about
+ * stack convention.
+ */
 static bool
-EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
-{
-    ParseNode *forHead = pn->pn_left;
-    ParseNode *forBody = pn->pn_right;
-
-    ParseNode *pn1 = forHead->pn_kid1;
+EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode *pn, ptrdiff_t top)
+{
+    JS_ASSERT(type == STMT_FOR_OF_LOOP || type == STMT_SPREAD);
+    JS_ASSERT_IF(type == STMT_FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
+    JS_ASSERT_IF(type == STMT_SPREAD, !pn);
+
+    ParseNode *forHead = pn ? pn->pn_left : nullptr;
+    ParseNode *forBody = pn ? pn->pn_right : nullptr;
+
+    ParseNode *pn1 = forHead ? forHead->pn_kid1 : nullptr;
     bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
     JS_ASSERT_IF(letDecl, pn1->isLet());
 
     // If the left part is 'var x', emit code to define x if necessary using a
     // prolog opcode, but do not emit a pop.
     if (pn1) {
         ParseNode *decl = letDecl ? pn1->pn_expr : pn1;
         JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET));
         bce->emittingForInit = true;
         if (!EmitVariables(cx, bce, decl, DefineVars))
             return false;
         bce->emittingForInit = false;
     }
 
-    // For-of loops run with two values on the stack: the iterator and the
-    // current result object.
-
-    // Compile the object expression to the right of 'of'.
-    if (!EmitTree(cx, bce, forHead->pn_kid3))
-        return false;
-
-    if (!EmitIterator(cx, bce))
-        return false;
-
-    // Push a dummy result so that we properly enter iteration midstream.
-    if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)                    // ITER RESULT
-        return false;
+    if (type == STMT_FOR_OF_LOOP) {
+        // For-of loops run with two values on the stack: the iterator and the
+        // current result object.
+
+        // Compile the object expression to the right of 'of'.
+        if (!EmitTree(cx, bce, forHead->pn_kid3))
+            return false;
+        if (!EmitIterator(cx, bce))
+            return false;
+
+        // Push a dummy result so that we properly enter iteration midstream.
+        if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)                // ITER RESULT
+            return false;
+    } else {
+        // If type is STMT_SPREAD, it expects that iterator to be already on
+        // the stack.
+        if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)      // I ITER ARR
+            return false;
+        if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)      // ITER ARR I
+            return false;
+    }
 
     // Enter the block before the loop body, after evaluating the obj.
     StmtInfoBCE letStmt(cx);
     if (letDecl) {
         if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 0))
             return false;
     }
 
     LoopStmtInfo stmtInfo(cx);
-    PushLoopStatement(bce, &stmtInfo, STMT_FOR_OF_LOOP, top);
+    PushLoopStatement(bce, &stmtInfo, type, top);
 
     // Jump down to the loop condition to minimize overhead assuming at least
     // one iteration, as the other loop forms do.  Annotate so IonMonkey can
     // find the loop-closing jump.
     int noteIndex = NewSrcNote(cx, bce, SRC_FOR_OF);
     if (noteIndex < 0)
         return false;
     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
     if (jmp < 0)
         return false;
 
     top = bce->offset();
     SET_STATEMENT_TOP(&stmtInfo, top);
     if (EmitLoopHead(cx, bce, nullptr) < 0)
         return false;
 
+    if (type == STMT_SPREAD)
+        bce->stackDepth++;
+
 #ifdef DEBUG
     int loopDepth = bce->stackDepth;
 #endif
 
     // Emit code to assign result.value to the iteration variable.
-    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // ITER RESULT RESULT
-        return false;
-    if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // ITER RESULT VALUE
-        return false;
-    if (!EmitAssignment(cx, bce, forHead->pn_kid2, JSOP_NOP, nullptr)) // ITER RESULT VALUE
-        return false;
-    if (Emit1(cx, bce, JSOP_POP) < 0)                          // ITER RESULT
-        return false;
-
-    // The stack should be balanced around the assignment opcode sequence.
-    JS_ASSERT(bce->stackDepth == loopDepth);
-
-    // Emit code for the loop body.
-    if (!EmitTree(cx, bce, forBody))
-        return false;
-
-    // Set loop and enclosing "update" offsets, for continue.
-    StmtInfoBCE *stmt = &stmtInfo;
-    do {
-        stmt->update = bce->offset();
-    } while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
+    if (type == STMT_FOR_OF_LOOP) {
+        if (Emit1(cx, bce, JSOP_DUP) < 0)                      // ITER RESULT RESULT
+            return false;
+    }
+    if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // ... RESULT VALUE
+        return false;
+    if (type == STMT_FOR_OF_LOOP) {
+        if (!EmitAssignment(cx, bce, forHead->pn_kid2, JSOP_NOP, nullptr)) // ITER RESULT VALUE
+            return false;
+        if (Emit1(cx, bce, JSOP_POP) < 0)                      // ITER RESULT
+            return false;
+
+        // The stack should be balanced around the assignment opcode sequence.
+        JS_ASSERT(bce->stackDepth == loopDepth);
+
+        // Emit code for the loop body.
+        if (!EmitTree(cx, bce, forBody))
+            return false;
+
+        // Set loop and enclosing "update" offsets, for continue.
+        StmtInfoBCE *stmt = &stmtInfo;
+        do {
+            stmt->update = bce->offset();
+        } while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
+    } else {
+        if (Emit1(cx, bce, JSOP_INITELEM_INC) < 0)             // ITER ARR (I+1)
+            return false;
+
+        JS_ASSERT(bce->stackDepth == loopDepth - 1);
+
+        // STMT_SPREAD never contain continue, so do not set "update" offset.
+    }
 
     // COME FROM the beginning of the loop to here.
     SetJumpOffsetAt(bce, jmp);
     if (!EmitLoopEntry(cx, bce, nullptr))
         return false;
 
-    if (Emit1(cx, bce, JSOP_POP) < 0)                          // ITER
-        return false;
-    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // ITER ITER
-        return false;
-    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // ITER ITER ITER
-        return false;
-    if (!EmitAtomOp(cx, cx->names().next, JSOP_CALLPROP, bce)) // ITER ITER NEXT
-        return false;
-    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // ITER NEXT ITER
-        return false;
-    if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)                    // ITER NEXT ITER UNDEFINED
-        return false;
-    if (EmitCall(cx, bce, JSOP_CALL, 1, forHead) < 0)          // ITER RESULT
+    if (type == STMT_FOR_OF_LOOP) {
+        if (Emit1(cx, bce, JSOP_POP) < 0)                      // ITER
+            return false;
+        if (Emit1(cx, bce, JSOP_DUP) < 0)                      // ITER ITER
+            return false;
+    } else {
+        if (!EmitDupAt(cx, bce, bce->stackDepth - 1 - 2))      // ITER ARR I ITER
+            return false;
+    }
+    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // ... ITER ITER
+        return false;
+    if (!EmitAtomOp(cx, cx->names().next, JSOP_CALLPROP, bce)) // ... ITER NEXT
+        return false;
+    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // ... NEXT ITER
+        return false;
+    if (EmitCall(cx, bce, JSOP_CALL, 0, forHead) < 0)          // ... RESULT
         return false;
     CheckTypeSet(cx, bce, JSOP_CALL);
-    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // ITER RESULT RESULT
-        return false;
-    if (!EmitAtomOp(cx, cx->names().done, JSOP_GETPROP, bce))  // ITER RESULT DONE?
-        return false;
-
-    ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, top - bce->offset()); // ITER RESULT
+    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // ... RESULT RESULT
+        return false;
+    if (!EmitAtomOp(cx, cx->names().done, JSOP_GETPROP, bce))  // ... RESULT DONE?
+        return false;
+
+    ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, top - bce->offset()); // ... RESULT
     if (beq < 0)
         return false;
 
     JS_ASSERT(bce->stackDepth == loopDepth);
 
     // Let Ion know where the closing jump of this loop is.
     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, beq - jmp))
         return false;
 
     // Fixup breaks and continues.
+    // For STMT_SPREAD, just pop pc->topStmt.
     if (!PopStatementBCE(cx, bce))
         return false;
 
     if (letDecl) {
         if (!LeaveNestedScope(cx, bce, &letStmt))
             return false;
     }
 
+    if (type == STMT_SPREAD) {
+        if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0)      // ARR I RESULT ITER
+            return false;
+    }
+
     // Pop the result and the iter.
     EMIT_UINT16_IMM_OP(JSOP_POPN, 2);
 
     return true;
 }
 
 static bool
 EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
@@ -4851,17 +4904,17 @@ EmitNormalFor(ExclusiveContext *cx, Byte
 
 static inline bool
 EmitFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
     if (pn->pn_left->isKind(PNK_FORIN))
         return EmitForIn(cx, bce, pn, top);
 
     if (pn->pn_left->isKind(PNK_FOROF))
-        return EmitForOf(cx, bce, pn, top);
+        return EmitForOf(cx, bce, STMT_FOR_OF_LOOP, pn, top);
 
     JS_ASSERT(pn->pn_left->isKind(PNK_FORHEAD));
     return EmitNormalFor(cx, bce, pn, top);
 }
 
 static MOZ_NEVER_INLINE bool
 EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
@@ -6074,16 +6127,29 @@ EmitArrayComp(ExclusiveContext *cx, Byte
     if (!EmitTree(cx, bce, pn->pn_head))
         return false;
     bce->arrayCompDepth = saveDepth;
 
     /* Emit the usual op needed for decompilation. */
     return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
 }
 
+/**
+ * EmitSpread expects the iterator, the current index (I) of the array, and the
+ * array itself to be on the stack in that order (iterator on the top). It will
+ * pop the iterator and I, then iterate over the iterator by calling |.next()|
+ * and put the results into the I-th element of array with incrementing I, then
+ * push the result I (it will be original I + iteration count).
+ */
+static bool
+EmitSpread(ExclusiveContext *cx, BytecodeEmitter *bce)
+{
+    return EmitForOf(cx, bce, STMT_SPREAD, nullptr, -1);
+}
+
 static bool
 EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t count)
 {
     /*
      * Emit code for [a, b, c] that is equivalent to constructing a new
      * array and in source order evaluating each element value and adding
      * it to the array, without invoking latent setters.  We use the
      * JSOP_NEWINIT and JSOP_INITELEM_ARRAY bytecodes to ignore setters and
@@ -6124,17 +6190,17 @@ EmitArray(ExclusiveContext *cx, Bytecode
         } else {
             ParseNode *expr = pn2->isKind(PNK_SPREAD) ? pn2->pn_kid : pn2;
             if (!EmitTree(cx, bce, expr))
                 return false;
         }
         if (pn2->isKind(PNK_SPREAD)) {
             if (!EmitIterator(cx, bce))
                 return false;
-            if (Emit1(cx, bce, JSOP_SPREAD) < 0)
+            if (!EmitSpread(cx, bce))
                 return false;
         } else if (afterSpread) {
             if (Emit1(cx, bce, JSOP_INITELEM_INC) < 0)
                 return false;
         } else {
             off = EmitN(cx, bce, JSOP_INITELEM_ARRAY, 3);
             if (off < 0)
                 return false;
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -354,16 +354,17 @@ enum StmtType {
     STMT_TRY,                   /* try block */
     STMT_FINALLY,               /* finally block */
     STMT_SUBROUTINE,            /* gosub-target subroutine body */
     STMT_DO_LOOP,               /* do/while loop statement */
     STMT_FOR_LOOP,              /* for loop statement */
     STMT_FOR_IN_LOOP,           /* for/in loop statement */
     STMT_FOR_OF_LOOP,           /* for/of loop statement */
     STMT_WHILE_LOOP,            /* while loop statement */
+    STMT_SPREAD,                /* spread operator (pseudo for/of) */
     STMT_LIMIT
 };
 
 /*
  * A comment on the encoding of the js::StmtType enum and StmtInfoBase
  * type-testing methods:
  *
  * StmtInfoBase::maybeScope() tells whether a statement type is always, or may
--- a/js/src/jit-test/tests/for-of/next-arity.js
+++ b/js/src/jit-test/tests/for-of/next-arity.js
@@ -2,17 +2,17 @@
 
 load(libdir + 'iteration.js')
 
 var log = '';
 
 function Iter() {
     function next() {
         log += 'n';
-        assertEq(arguments.length, 1)
+        assertEq(arguments.length, 0)
         assertEq(arguments[0], undefined)
         return { get value() { throw 42; }, done: true }
     }
 
     this[std_iterator] = function () { return this; }
     this.next = next;
 }
 
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2365,44 +2365,16 @@ BaselineCompiler::emit_JSOP_INITELEM_INC
     frame.pop();
 
     // Increment index
     Address indexAddr = frame.addressOfStackValue(frame.peek(-1));
     masm.incrementInt32Value(indexAddr);
     return true;
 }
 
-typedef bool (*SpreadFn)(JSContext *, HandleObject, HandleValue,
-                         HandleValue, MutableHandleValue);
-static const VMFunction SpreadInfo = FunctionInfo<SpreadFn>(js::SpreadOperation);
-
-bool
-BaselineCompiler::emit_JSOP_SPREAD()
-{
-    // Load index and iterator in R0 and R1, but keep values on the stack for
-    // the decompiler.
-    frame.syncStack(0);
-    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
-    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
-
-    prepareVMCall();
-
-    pushArg(R1);
-    pushArg(R0);
-    masm.extractObject(frame.addressOfStackValue(frame.peek(-3)), R0.scratchReg());
-    pushArg(R0.scratchReg());
-
-    if (!callVM(SpreadInfo))
-        return false;
-
-    frame.popn(2);
-    frame.push(R0);
-    return true;
-}
-
 bool
 BaselineCompiler::emit_JSOP_GETLOCAL()
 {
     frame.pushLocal(GET_LOCALNO(pc));
     return true;
 }
 
 bool
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -93,17 +93,16 @@ namespace jit {
     _(JSOP_NEWARRAY)           \
     _(JSOP_INITELEM_ARRAY)     \
     _(JSOP_NEWOBJECT)          \
     _(JSOP_NEWINIT)            \
     _(JSOP_INITELEM)           \
     _(JSOP_INITELEM_GETTER)    \
     _(JSOP_INITELEM_SETTER)    \
     _(JSOP_INITELEM_INC)       \
-    _(JSOP_SPREAD)             \
     _(JSOP_MUTATEPROTO)        \
     _(JSOP_INITPROP)           \
     _(JSOP_INITPROP_GETTER)    \
     _(JSOP_INITPROP_SETTER)    \
     _(JSOP_ENDINIT)            \
     _(JSOP_ARRAYPUSH)          \
     _(JSOP_GETELEM)            \
     _(JSOP_SETELEM)            \
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5380,16 +5380,59 @@ JS_GetTwoByteStringCharsAndLength(JSCont
     JSLinearString *linear = str->ensureLinear(cx);
     if (!linear)
         return nullptr;
     *plength = linear->length();
     return linear->twoByteChars(nogc);
 }
 
 JS_PUBLIC_API(const jschar *)
+JS_GetTwoByteExternalStringChars(JSString *str)
+{
+    return str->asExternal().twoByteChars();
+}
+
+JS_PUBLIC_API(bool)
+JS_GetStringCharAt(JSContext *cx, JSString *str, size_t index, jschar *res)
+{
+    AssertHeapIsIdleOrStringIsFlat(cx, str);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, str);
+
+    JSLinearString *linear = str->ensureLinear(cx);
+    if (!linear)
+        return false;
+
+    *res = linear->latin1OrTwoByteChar(index);
+    return true;
+}
+
+JS_PUBLIC_API(jschar)
+JS_GetFlatStringCharAt(JSFlatString *str, size_t index)
+{
+    return str->latin1OrTwoByteChar(index);
+}
+
+JS_PUBLIC_API(bool)
+JS_CopyStringChars(JSContext *cx, mozilla::Range<jschar> dest, JSString *str)
+{
+    AssertHeapIsIdleOrStringIsFlat(cx, str);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, str);
+
+    JSLinearString *linear = str->ensureLinear(cx);
+    if (!linear)
+        return false;
+
+    MOZ_ASSERT(linear->length() <= dest.length());
+    CopyChars(dest.start().get(), *linear);
+    return true;
+}
+
+JS_PUBLIC_API(const jschar *)
 JS_GetInternedStringChars(JSString *str)
 {
     JS_ASSERT(str->isAtom());
     JSFlatString *flat = str->ensureFlat(nullptr);
     if (!flat)
         return nullptr;
     return flat->chars();
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -6,16 +6,17 @@
 
 /* JavaScript API. */
 
 #ifndef jsapi_h
 #define jsapi_h
 
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Range.h"
 #include "mozilla/RangedPtr.h"
 #include "mozilla/TypedEnum.h"
 
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
 
@@ -4176,16 +4177,28 @@ JS_GetStringCharsAndLength(JSContext *cx
 extern JS_PUBLIC_API(const JS::Latin1Char *)
 JS_GetLatin1StringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
                                  size_t *length);
 
 extern JS_PUBLIC_API(const jschar *)
 JS_GetTwoByteStringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
                                   size_t *length);
 
+extern JS_PUBLIC_API(bool)
+JS_GetStringCharAt(JSContext *cx, JSString *str, size_t index, jschar *res);
+
+extern JS_PUBLIC_API(jschar)
+JS_GetFlatStringCharAt(JSFlatString *str, size_t index);
+
+extern JS_PUBLIC_API(const jschar *)
+JS_GetTwoByteExternalStringChars(JSString *str);
+
+extern JS_PUBLIC_API(bool)
+JS_CopyStringChars(JSContext *cx, mozilla::Range<jschar> dest, JSString *str);
+
 extern JS_PUBLIC_API(const jschar *)
 JS_GetInternedStringChars(JSString *str);
 
 extern JS_PUBLIC_API(const jschar *)
 JS_GetInternedStringCharsAndLength(JSString *str, size_t *length);
 
 extern JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsZ(JSContext *cx, JSString *str);
--- a/js/src/tests/ecma_6/Array/for_of_1.js
+++ b/js/src/tests/ecma_6/Array/for_of_1.js
@@ -1,18 +1,16 @@
 // Test corner cases of for-of iteration over Arrays.
-// The current spidermonky JSOP_SPREAD implementation for function calls
-// with '...rest' arguments uses a ForOfIterator to extract values from
-// the array, so we use that mechanism to test ForOfIterator here.
-
+// The current SetObject::construct method uses a ForOfIterator to extract
+// values from the array, so we use that mechanism to test ForOfIterator here.
 
 // Test the properties and prototype of a generator object.
 function TestManySmallArrays() {
     function doIter(f, arr) {
-        return f(...arr)
+        return f(...new Set(arr));
     }
 
     function fun(a, b, c) {
         var result = 0;
         for (var i = 0; i < arguments.length; i++)
             result += arguments[i];
         return result;
     }
@@ -32,17 +30,17 @@ function TestManySmallArrays() {
     }
     assertEq(sum, TRUE_SUM);
 }
 TestManySmallArrays();
 
 // Test the properties and prototype of a generator object.
 function TestSingleSmallArray() {
     function doIter(f, arr) {
-        return f(...arr)
+        return f(...new Set(arr));
     }
 
     function fun(a, b, c) {
         var result = 0;
         for (var i = 0; i < arguments.length; i++)
             result += arguments[i];
         return result;
     }
@@ -64,17 +62,17 @@ function TestSingleSmallArray() {
     }
     assertEq(sum, TRUE_SUM);
 }
 TestSingleSmallArray();
 
 
 function TestChangeArrayPrototype() {
     function doIter(f, arr) {
-        return f(...arr)
+        return f(...new Set(arr));
     }
 
     function fun(a, b, c) {
         var result = 0;
         for (var i = 0; i < arguments.length; i++)
             result += arguments[i];
         return result;
     }
@@ -101,17 +99,17 @@ function TestChangeArrayPrototype() {
     }
     assertEq(sum, TRUE_SUM);
 }
 TestChangeArrayPrototype();
 
 
 function TestChangeManyArrayShape() {
     function doIter(f, arr) {
-        return f(...arr)
+        return f(...new Set(arr));
     }
 
     function fun(a, b, c) {
         var result = 0;
         for (var i = 0; i < arguments.length; i++)
             result += arguments[i];
         return result;
     }
--- a/js/src/tests/ecma_6/Array/for_of_2.js
+++ b/js/src/tests/ecma_6/Array/for_of_2.js
@@ -1,19 +1,18 @@
 // Test corner cases of for-of iteration over Arrays.
-// The current spidermonky JSOP_SPREAD implementation for function calls
-// with '...rest' arguments uses a ForOfIterator to extract values from
-// the array, so we use that mechanism to test ForOfIterator here.
+// The current SetObject::construct method uses a ForOfIterator to extract
+// values from the array, so we use that mechanism to test ForOfIterator here.
 
 //
 // Check case where ArrayIterator.prototype.next changes in the middle of iteration.
 //
 function TestChangeArrayIteratorNext() {
     function doIter(f, arr) {
-        return f(...arr)
+        return f(...new Set(arr));
     }
 
     function fun(a, b, c) {
         var result = 0;
         for (var i = 0; i < arguments.length; i++)
             result += arguments[i];
         return result;
     }
--- a/js/src/tests/ecma_6/Array/for_of_3.js
+++ b/js/src/tests/ecma_6/Array/for_of_3.js
@@ -1,19 +1,18 @@
 // Test corner cases of for-of iteration over Arrays.
-// The current spidermonkey JSOP_SPREAD implementation for function calls
-// with '...rest' arguments uses a ForOfIterator to extract values from
-// the array, so we use that mechanism to test ForOfIterator here.
+// The current SetObject::construct method uses a ForOfIterator to extract
+// values from the array, so we use that mechanism to test ForOfIterator here.
 
 //
 // Check array length increases changes during iteration.
 //
 function TestIncreaseArrayLength() {
     function doIter(f, arr) {
-        return f(...arr)
+        return f(...new Set(arr));
     }
 
     function fun(a, b, c) {
         var result = 0;
         for (var i = 0; i < arguments.length; i++)
             result += arguments[i];
         return result;
     }
--- a/js/src/tests/ecma_6/Array/for_of_4.js
+++ b/js/src/tests/ecma_6/Array/for_of_4.js
@@ -1,19 +1,18 @@
 // Test corner cases of for-of iteration over Arrays.
-// The current spidermonkey JSOP_SPREAD implementation for function calls
-// with '...rest' arguments uses a ForOfIterator to extract values from
-// the array, so we use that mechanism to test ForOfIterator here.
+// The current SetObject::construct method uses a ForOfIterator to extract
+// values from the array, so we use that mechanism to test ForOfIterator here.
 
 //
 // Check array length decreases changes during iteration.
 //
 function TestDecreaseArrayLength() {
     function doIter(f, arr) {
-        return f(...arr)
+        return f(...new Set(arr));
     }
 
     function fun(a, b, c) {
         var result = 0;
         for (var i = 0; i < arguments.length; i++)
             result += arguments[i];
         return result;
     }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1592,16 +1592,17 @@ CASE(JSOP_UNUSED45)
 CASE(JSOP_UNUSED46)
 CASE(JSOP_UNUSED47)
 CASE(JSOP_UNUSED48)
 CASE(JSOP_UNUSED49)
 CASE(JSOP_UNUSED50)
 CASE(JSOP_UNUSED51)
 CASE(JSOP_UNUSED52)
 CASE(JSOP_UNUSED57)
+CASE(JSOP_UNUSED83)
 CASE(JSOP_UNUSED101)
 CASE(JSOP_UNUSED102)
 CASE(JSOP_UNUSED103)
 CASE(JSOP_UNUSED104)
 CASE(JSOP_UNUSED105)
 CASE(JSOP_UNUSED107)
 CASE(JSOP_UNUSED124)
 CASE(JSOP_UNUSED125)
@@ -3173,31 +3174,16 @@ CASE(JSOP_INITELEM_INC)
     if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val))
         goto error;
 
     REGS.sp[-2].setInt32(index + 1);
     REGS.sp--;
 }
 END_CASE(JSOP_INITELEM_INC)
 
-CASE(JSOP_SPREAD)
-{
-    HandleValue countVal = REGS.stackHandleAt(-2);
-    RootedObject &arr = rootObject0;
-    arr = &REGS.sp[-3].toObject();
-    HandleValue iterator = REGS.stackHandleAt(-1);
-    MutableHandleValue resultCountVal = REGS.stackHandleAt(-2);
-
-    if (!SpreadOperation(cx, arr, countVal, iterator, resultCountVal))
-        goto error;
-
-    REGS.sp--;
-}
-END_CASE(JSOP_SPREAD)
-
 CASE(JSOP_GOSUB)
 {
     PUSH_BOOLEAN(false);
     int32_t i = script->pcToOffset(REGS.pc) + JSOP_GOSUB_LENGTH;
     int32_t len = GET_JUMP_OFFSET(REGS.pc);
     PUSH_INT32(i);
     ADVANCE_AND_DISPATCH(len);
 }
@@ -3893,44 +3879,16 @@ js::InitGetterSetterOperation(JSContext 
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, idval, &id))
         return false;
 
     return InitGetterSetterOperation(cx, pc, obj, id, val);
 }
 
 bool
-js::SpreadOperation(JSContext *cx, HandleObject arr, HandleValue countVal,
-                    HandleValue iterator, MutableHandleValue resultCountVal)
-{
-    int32_t count = countVal.toInt32();
-    ForOfIterator iter(cx);
-    RootedValue iterVal(cx, iterator);
-    if (!iter.initWithIterator(iterVal))
-        return false;
-    while (true) {
-        bool done;
-        if (!iter.next(&iterVal, &done))
-            return false;
-        if (done)
-            break;
-        if (count == INT32_MAX) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
-                                 JSMSG_SPREAD_TOO_LARGE);
-            return false;
-        }
-        if (!JSObject::defineElement(cx, arr, count++, iterVal, nullptr, nullptr,
-                                     JSPROP_ENUMERATE))
-            return false;
-    }
-    resultCountVal.setInt32(count);
-    return true;
-}
-
-bool
 js::SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue thisv,
                         HandleValue callee, HandleValue arr, MutableHandleValue res)
 {
     RootedObject aobj(cx, &arr.toObject());
     uint32_t length = aobj->as<ArrayObject>().length();
     JSOp op = JSOp(*pc);
 
     if (length > ARGS_LENGTH_MAX) {
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -458,20 +458,16 @@ bool
 EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val, HandleObject staticWith);
 
 
 bool
 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
                           HandleObject val);
 
 bool
-SpreadOperation(JSContext *cx, HandleObject arr, HandleValue countVal,
-                HandleValue iterable, MutableHandleValue resultCountVal);
-
-bool
 SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue thisv,
                     HandleValue callee, HandleValue arr, MutableHandleValue res);
 
 inline bool
 SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
 {
     return JSObject::defineProperty(cx, varobj, name, rval,
                                     JS_PropertyStub, JS_StrictPropertyStub,
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -685,30 +685,18 @@ 1234567890123456789012345678901234567890
      * value onto the stack.
      *   Category: Statements
      *   Type: Function
      *   Operands: uint16_t argc
      *   Stack: callee, this, args[0], ..., args[argc-1] => rval
      *   nuses: (argc+2)
      */ \
     macro(JSOP_NEW,       82, js_new_str,   NULL,         3, -1,  1,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
-    /*
-     * Pops the top three values on the stack as 'iterator', 'index' and 'obj',
-     * iterates over 'iterator' and stores the iteration values as 'index + i'
-     * elements of 'obj', pushes 'obj' and 'index + iteration count' onto the
-     * stack.
-     *
-     * This opcode is used in Array literals with spread and spreadcall
-     * arguments as well as in destructing assignment with rest element.
-     *   Category: Literals
-     *   Type: Array
-     *   Operands:
-     *   Stack: obj, index, iterator => obj, (index + iteration count)
-     */ \
-    macro(JSOP_SPREAD,    83, "spread",     NULL,         1,  3,  2,  JOF_BYTE|JOF_ELEM|JOF_SET) \
+    \
+    macro(JSOP_UNUSED83,  83, "unused83",   NULL,         1,  0,  0,  JOF_BYTE) \
     \
     /*
      * Fast get op for function arguments and local variables.
      *
      * Pushes 'arguments[argno]' onto the stack.
      *   Category: Variables and Scopes
      *   Type: Arguments
      *   Operands: uint16_t argno
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -948,16 +948,24 @@ class JSExternalString : public JSFlatSt
     static inline JSExternalString *new_(JSContext *cx, const jschar *chars, size_t length,
                                          const JSStringFinalizer *fin);
 
     const JSStringFinalizer *externalFinalizer() const {
         JS_ASSERT(JSString::isExternal());
         return d.s.u3.externalFinalizer;
     }
 
+    /*
+     * External chars are never allocated inline or in the nursery, so we can
+     * safely expose this without requiring an AutoCheckCannotGC argument.
+     */
+    const jschar *twoByteChars() const {
+        return rawTwoByteChars();
+    }
+
     /* Only called by the GC for strings with the FINALIZE_EXTERNAL_STRING kind. */
 
     inline void finalize(js::FreeOp *fop);
 };
 
 JS_STATIC_ASSERT(sizeof(JSExternalString) == sizeof(JSString));
 
 class JSUndependedString : public JSFlatString
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -23,17 +23,17 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 175);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 176);
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext *cx)
       : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
 
     JSContext *cx() const {
         return context;
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -33,16 +33,17 @@
 #include "nsIObserverService.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIFileURL.h"
 #include "nsIJARURI.h"
 #include "nsNetUtil.h"
 #include "nsDOMBlobBuilder.h"
 #include "jsprf.h"
 #include "nsJSPrincipals.h"
+#include "nsJSUtils.h"
 #include "xpcprivate.h"
 #include "xpcpublic.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "WrapperFactory.h"
 
 #include "mozilla/AddonPathService.h"
 #include "mozilla/scache/StartupCache.h"
@@ -106,36 +107,36 @@ static PRLogModuleInfo *gJSCLLog;
 static bool
 Dump(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0)
         return true;
 
-    JSString *str = JS::ToString(cx, args[0]);
+    RootedString str(cx, JS::ToString(cx, args[0]));
     if (!str)
         return false;
 
-    size_t length;
-    const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
-    if (!chars)
+    JSAutoByteString utf8str;
+    if (!utf8str.encodeUtf8(cx, str))
         return false;
 
-    NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const char16_t*>(chars),
-                                  length);
 #ifdef ANDROID
-    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
+    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.ptr());
 #endif
 #ifdef XP_WIN
     if (IsDebuggerPresent()) {
-      OutputDebugStringW(reinterpret_cast<const wchar_t*>(chars));
+        nsAutoJSString wstr;
+        if (!wstr.init(cx, str))
+            return false;
+        OutputDebugStringW(wstr.get());
     }
 #endif
-    fputs(utf8str.get(), stdout);
+    fputs(utf8str.ptr(), stdout);
     fflush(stdout);
     return true;
 }
 
 static bool
 Debug(JSContext *cx, unsigned argc, jsval *vp)
 {
 #ifdef DEBUG
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -93,23 +93,18 @@ SandboxDump(JSContext *cx, unsigned argc
 
     if (args.length() == 0)
         return true;
 
     RootedString str(cx, ToString(cx, args[0]));
     if (!str)
         return false;
 
-    size_t length;
-    const jschar *chars = JS_GetStringCharsZAndLength(cx, str, &length);
-    if (!chars)
-        return false;
-
-    nsDependentString wstr(chars, length);
-    char *cstr = ToNewUTF8String(wstr);
+    JSAutoByteString utf8str;
+    char *cstr = utf8str.encodeUtf8(cx, str);
     if (!cstr)
         return false;
 
 #if defined(XP_MACOSX)
     // Be nice and convert all \r to \n.
     char *c = cstr, *cEnd = cstr + strlen(cstr);
     while (c < cEnd) {
         if (*c == '\r')
@@ -118,17 +113,16 @@ SandboxDump(JSContext *cx, unsigned argc
     }
 #endif
 #ifdef ANDROID
     __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
 #endif
 
     fputs(cstr, stdout);
     fflush(stdout);
-    NS_Free(cstr);
     args.rval().setBoolean(true);
     return true;
 }
 
 static bool
 SandboxDebug(JSContext *cx, unsigned argc, jsval *vp)
 {
 #ifdef DEBUG
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -27,16 +27,17 @@
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsJSPrincipals.h"
 #include "xpcpublic.h"
 #include "BackstagePass.h"
 #include "nsCxPusher.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
+#include "nsJSUtils.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
@@ -252,36 +253,33 @@ ReadLine(JSContext *cx, unsigned argc, j
 
 static bool
 Print(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setUndefined();
 
     RootedString str(cx);
-    nsAutoCString utf8str;
-    size_t length;
-    const jschar *chars;
+    nsAutoCString utf8output;
 
     for (unsigned i = 0; i < args.length(); i++) {
         str = ToString(cx, args[i]);
         if (!str)
             return false;
-        chars = JS_GetStringCharsAndLength(cx, str, &length);
-        if (!chars)
+
+        JSAutoByteString utf8str;
+        if (!utf8str.encodeUtf8(cx, str))
             return false;
 
         if (i)
-            utf8str.Append(' ');
-        AppendUTF16toUTF8(Substring(reinterpret_cast<const char16_t*>(chars),
-                                    length),
-                          utf8str);
+            utf8output.Append(' ');
+        utf8output.Append(utf8str.ptr(), utf8str.length());
     }
-    utf8str.Append('\n');
-    fputs(utf8str.get(), gOutFile);
+    utf8output.Append('\n');
+    fputs(utf8output.get(), gOutFile);
     fflush(gOutFile);
     return true;
 }
 
 static bool
 Dump(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -289,32 +287,32 @@ Dump(JSContext *cx, unsigned argc, jsval
 
     if (!args.length())
          return true;
 
     RootedString str(cx, ToString(cx, args[0]));
     if (!str)
         return false;
 
-    size_t length;
-    const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
-    if (!chars)
+    JSAutoByteString utf8str;
+    if (!utf8str.encodeUtf8(cx, str))
         return false;
 
-    NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const char16_t*>(chars),
-                                  length);
 #ifdef ANDROID
-    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
+    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.ptr());
 #endif
 #ifdef XP_WIN
     if (IsDebuggerPresent()) {
-      OutputDebugStringW(reinterpret_cast<const wchar_t*>(chars));
+        nsAutoJSString wstr;
+        if (!wstr.init(cx, str))
+            return false;
+        OutputDebugStringW(wstr.get());
     }
 #endif
-    fputs(utf8str.get(), gOutFile);
+    fputs(utf8str.ptr(), gOutFile);
     fflush(gOutFile);
     return true;
 }
 
 static bool
 Load(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_bug1034262.js
@@ -0,0 +1,9 @@
+const Cu = Components.utils;
+function run_test() {
+  var sb1 = Cu.Sandbox('http://www.example.com', { wantXrays: true });
+  var sb2 = Cu.Sandbox('http://www.example.com', { wantXrays: false });
+  sb2.f = Cu.evalInSandbox('x => typeof x', sb1);
+  do_check_eq(Cu.evalInSandbox('f(dump)', sb2), 'function');
+  do_check_eq(Cu.evalInSandbox('f.call(null, dump)', sb2), 'function');
+  do_check_eq(Cu.evalInSandbox('f.apply(null, [dump])', sb2), 'function');
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -41,16 +41,17 @@ support-files =
 [test_bug885800.js]
 [test_bug961054.js]
 [test_bug976151.js]
 [test_bug1001094.js]
 [test_bug1021312.js]
 [test_bug1033253.js]
 [test_bug1033920.js]
 [test_bug1033927.js]
+[test_bug1034262.js]
 [test_bug_442086.js]
 [test_file.js]
 [test_blob.js]
 [test_blob2.js]
 [test_file2.js]
 [test_import.js]
 [test_import_fail.js]
 [test_isModuleLoaded.js]
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -86,40 +86,40 @@ AccessCheck::isChrome(JSObject *obj)
 
 nsIPrincipal *
 AccessCheck::getPrincipal(JSCompartment *compartment)
 {
     return GetCompartmentPrincipal(compartment);
 }
 
 #define NAME(ch, str, cases)                                                  \
-    case ch: if (!strcmp(name, str)) switch (propChars[0]) { cases }; break;
+    case ch: if (!strcmp(name, str)) switch (propChar0) { cases }; break;
 #define PROP(ch, actions) case ch: { actions }; break;
 #define RW(str) if (JS_FlatStringEqualsAscii(prop, str)) return true;
 #define R(str) if (!set && JS_FlatStringEqualsAscii(prop, str)) return true;
 #define W(str) if (set && JS_FlatStringEqualsAscii(prop, str)) return true;
 
 // Hardcoded policy for cross origin property access. This was culled from the
 // preferences file (all.js). We don't want users to overwrite highly sensitive
 // security policies.
 static bool
 IsPermitted(const char *name, JSFlatString *prop, bool set)
 {
-    size_t propLength;
-    const jschar *propChars =
-        JS_GetInternedStringCharsAndLength(JS_FORGET_STRING_FLATNESS(prop), &propLength);
+    size_t propLength = JS_GetStringLength(JS_FORGET_STRING_FLATNESS(prop));
     if (!propLength)
         return false;
+
+    jschar propChar0 = JS_GetFlatStringCharAt(prop, 0);
     switch (name[0]) {
         NAME('L', "Location",
              PROP('h', W("href"))
              PROP('r', R("replace")))
         case 'W':
             if (!strcmp(name, "Window"))
-                return dom::WindowBinding::IsPermitted(prop, propChars[0], set);
+                return dom::WindowBinding::IsPermitted(prop, propChar0, set);
             break;
     }
     return false;
 }
 
 #undef NAME
 #undef RW
 #undef R
@@ -287,24 +287,25 @@ ExposedPropertiesOnly::check(JSContext *
     if (!desc.object() || !desc.isEnumerable())
         return false;
 
     if (!desc.value().isString()) {
         EnterAndThrow(cx, wrapper, "property must be a string");
         return false;
     }
 
-    JSString *str = desc.value().toString();
-    size_t length;
-    const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
-    if (!chars)
+    JSFlatString *flat = JS_FlattenString(cx, desc.value().toString());
+    if (!flat)
         return false;
 
+    size_t length = JS_GetStringLength(JS_FORGET_STRING_FLATNESS(flat));
+
     for (size_t i = 0; i < length; ++i) {
-        switch (chars[i]) {
+        jschar ch = JS_GetFlatStringCharAt(flat, i);
+        switch (ch) {
         case 'r':
             if (access & READ) {
                 EnterAndThrow(cx, wrapper, "duplicate 'readable' property flag");
                 return false;
             }
             access = Access(access | READ);
             break;
 
--- a/js/xpconnect/wrappers/AccessCheck.h
+++ b/js/xpconnect/wrappers/AccessCheck.h
@@ -51,35 +51,16 @@ struct OpaqueWithCall : public Policy {
     static bool deny(js::Wrapper::Action act, JS::HandleId id) {
         return false;
     }
     static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl) {
         return false;
     }
 };
 
-// This policy is designed to protect privileged callers from untrusted non-
-// Xrayable objects. Nothing is allowed, and nothing throws.
-struct GentlyOpaque : public Policy {
-    static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
-        return false;
-    }
-    static bool deny(js::Wrapper::Action act, JS::HandleId id) {
-        return true;
-    }
-    static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl) {
-        // We allow nativeCall here because the alternative is throwing (which
-        // happens in SecurityWrapper::nativeCall), which we don't want. There's
-        // unlikely to be too much harm to letting this through, because this
-        // wrapper is only used to wrap less-privileged objects in more-privileged
-        // scopes, so unwrapping here only drops privileges.
-        return true;
-    }
-};
-
 // This policy only permits access to properties that are safe to be used
 // across origins.
 struct CrossOriginAccessiblePropertiesOnly : public Policy {
     static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
         return AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act);
     }
     static bool deny(js::Wrapper::Action act, JS::HandleId id) {
         // Silently fail for enumerate-like operations.
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -136,32 +136,16 @@ FilteringWrapper<Base, Policy>::nativeCa
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::defaultValue(JSContext *cx, HandleObject obj,
                                              JSType hint, MutableHandleValue vp) const
 {
     return Base::defaultValue(cx, obj, hint, vp);
 }
 
-// With our entirely-opaque wrapper, the DefaultValue algorithm throws,
-// causing spurious exceptions. Manually implement something benign.
-template<>
-bool
-FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
-                ::defaultValue(JSContext *cx, HandleObject obj,
-                               JSType hint, MutableHandleValue vp) const
-{
-    JSString *str = JS_NewStringCopyZ(cx, "[Opaque]");
-    if (!str)
-        return false;
-    vp.set(JS::StringValue(str));
-    return true;
-}
-
-
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::enter(JSContext *cx, HandleObject wrapper,
                                       HandleId id, Wrapper::Action act, bool *bp) const
 {
     // This is a super ugly hacky to get around Xray Resolve wonkiness.
     //
     // Basically, XPCWN Xrays sometimes call into the Resolve hook of the
@@ -185,23 +169,20 @@ FilteringWrapper<Base, Policy>::enter(JS
     *bp = true;
     return true;
 }
 
 #define XOW FilteringWrapper<SecurityXrayXPCWN, CrossOriginAccessiblePropertiesOnly>
 #define DXOW   FilteringWrapper<SecurityXrayDOM, CrossOriginAccessiblePropertiesOnly>
 #define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
 #define NNXOWC FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>
-#define GO FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
+
 template<> const XOW XOW::singleton(0);
 template<> const DXOW DXOW::singleton(0);
 template<> const NNXOW NNXOW::singleton(0);
 template<> const NNXOWC NNXOWC::singleton(0);
 
-template<> const GO GO::singleton(0);
-
 template class XOW;
 template class DXOW;
 template class NNXOW;
 template class NNXOWC;
 template class ChromeObjectWrapperBase;
-template class GO;
 }
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -116,29 +116,33 @@ WrapperFactory::DoubleWrap(JSContext *cx
     if (flags & WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG) {
         JSAutoCompartment ac(cx, obj);
         return WaiveXray(cx, obj);
     }
     return obj;
 }
 
 // In general, we're trying to deprecate COWs incrementally as we introduce
-// Xrays to the corresponding object types. But switching off COWs for Object
-// and Array instances would be too tumultuous at present, so we punt on that
-// for later.
+// Xrays to the corresponding object types. But switching off COWs for certain
+// things would be too tumultuous at present, so we punt on them for later.
 static bool
 ForceCOWBehavior(JSObject *obj)
 {
     JSProtoKey key = IdentifyStandardInstanceOrPrototype(obj);
     if (key == JSProto_Object || key == JSProto_Array || key == JSProto_Function) {
         MOZ_ASSERT(GetXrayType(obj) == XrayForJSObject,
                    "We should use XrayWrappers for standard ES Object, Array, and Function "
                    "instances modulo this hack");
         return true;
     }
+    // Proxies get OpaqueXrayTraits, but we still need COWs to them for now to
+    // let the SpecialPowers wrapper work.
+    if (key == JSProto_Proxy)
+        return true;
+
     return false;
 }
 
 JSObject *
 WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope,
                                    HandleObject objArg, unsigned flags)
 {
     RootedObject obj(cx, objArg);
@@ -326,20 +330,16 @@ WrapperFactory::PrepareForWrapping(JSCon
 #ifdef DEBUG
 static void
 DEBUG_CheckUnwrapSafety(HandleObject obj, const js::Wrapper *handler,
                         JSCompartment *origin, JSCompartment *target)
 {
     if (AccessCheck::isChrome(target) || xpc::IsUniversalXPConnectEnabled(target)) {
         // If the caller is chrome (or effectively so), unwrap should always be allowed.
         MOZ_ASSERT(!handler->hasSecurityPolicy());
-    } else if (handler == &FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>::singleton) {
-        // We explicitly use a SecurityWrapper to protect privileged callers from
-        // less-privileged objects that they should never see. Skip the check in
-        // this case.
     } else {
         // Otherwise, it should depend on whether the target subsumes the origin.
         MOZ_ASSERT(handler->hasSecurityPolicy() == !AccessCheck::subsumesConsideringDomain(target, origin));
     }
 }
 #else
 #define DEBUG_CheckUnwrapSafety(obj, handler, origin, target) {}
 #endif
@@ -416,17 +416,16 @@ WrapperFactory::Rewrap(JSContext *cx, Ha
     bool targetIsChrome = AccessCheck::isChrome(target);
     bool originSubsumesTarget = AccessCheck::subsumesConsideringDomain(origin, target);
     bool targetSubsumesOrigin = AccessCheck::subsumesConsideringDomain(target, origin);
     bool sameOrigin = targetSubsumesOrigin && originSubsumesTarget;
     XrayType xrayType = GetXrayType(obj);
     bool waiveXrayFlag = flags & WAIVE_XRAY_WRAPPER_FLAG;
 
     const Wrapper *wrapper;
-    CompartmentPrivate *targetdata = CompartmentPrivate::Get(target);
 
     //
     // First, handle the special cases.
     //
 
     // If UniversalXPConnect is enabled, this is just some dumb mochitest. Use
     // a vanilla CCW.
     if (xpc::IsUniversalXPConnectEnabled(target)) {
@@ -450,17 +449,17 @@ WrapperFactory::Rewrap(JSContext *cx, Ha
     // a bit too entrenched to change for content-chrome, but we can at least fix
     // it for XBL scopes.
     //
     // See bug 843829.
     else if (targetSubsumesOrigin && !originSubsumesTarget &&
              !waiveXrayFlag && xrayType == NotXray &&
              IsContentXBLScope(target))
     {
-        wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>::singleton;
+        wrapper = &PermissiveXrayOpaque::singleton;
     }
 
     //
     // Now, handle the regular cases.
     //
     // These are wrappers we can compute using a rule-based approach. In order
     // to do so, we need to compute some parameters.
     //
@@ -471,17 +470,19 @@ WrapperFactory::Rewrap(JSContext *cx, Ha
         bool securityWrapper = !targetSubsumesOrigin;
 
         // Xrays are warranted if either the target or the origin don't trust
         // each other. This is generally the case, unless the two are same-origin
         // and the caller has not requested same-origin Xrays.
         //
         // Xrays are a bidirectional protection, since it affords clarity to the
         // caller and privacy to the callee.
-        bool wantXrays = !(sameOrigin && !targetdata->wantXrays);
+        bool sameOriginXrays = CompartmentPrivate::Get(origin)->wantXrays ||
+                               CompartmentPrivate::Get(target)->wantXrays;
+        bool wantXrays = !sameOrigin || sameOriginXrays;
 
         // If Xrays are warranted, the caller may waive them for non-security
         // wrappers.
         bool waiveXrays = wantXrays && !securityWrapper && waiveXrayFlag;
 
         // We have slightly different behavior for the case when the object
         // being wrapped is in an XBL scope.
         bool originIsContentXBLScope = IsContentXBLScope(origin);
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -189,16 +189,20 @@ public:
                                     HandleObject wrapper, HandleObject holder,
                                     HandleId id, MutableHandle<JSPropertyDescriptor> desc);
 
     bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) {
         *bp = true;
         return true;
     }
 
+    static const char *className(JSContext *cx, HandleObject wrapper, const js::Wrapper& baseInstance) {
+        return baseInstance.className(cx, wrapper);
+    }
+
     virtual void preserveWrapper(JSObject *target) = 0;
 
     static bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver, HandleId id,
                     bool strict, MutableHandleValue vp);
 
     JSObject* getExpandoObject(JSContext *cx, HandleObject target,
                                HandleObject consumer);
     JSObject* ensureExpandoObject(JSContext *cx, HandleObject wrapper,
@@ -449,16 +453,101 @@ public:
 
 const JSClass JSXrayTraits::HolderClass = {
     "JSXrayHolder", JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
     JS_PropertyStub, JS_DeletePropertyStub,
     JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
 };
 
+// These traits are used when the target is not Xrayable and we therefore want
+// to make it opaque modulo the usual Xray machinery (like expandos and
+// .wrappedJSObject).
+class OpaqueXrayTraits : public XrayTraits
+{
+public:
+    enum {
+        HasPrototype = 1
+    };
+    static const XrayType Type = XrayForOpaqueObject;
+
+    virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
+                                       HandleObject holder, HandleId id,
+                                       MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE
+    {
+        MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
+    }
+
+    bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
+                        MutableHandle<JSPropertyDescriptor> desc,
+                        Handle<JSPropertyDescriptor> existingDesc, bool *defined)
+    {
+        *defined = false;
+        return true;
+    }
+
+    virtual bool enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
+                                AutoIdVector &props)
+    {
+        return true;
+    }
+
+    static bool call(JSContext *cx, HandleObject wrapper,
+                     const JS::CallArgs &args, const js::Wrapper& baseInstance)
+    {
+        RootedValue v(cx, ObjectValue(*wrapper));
+        js_ReportIsNotFunction(cx, v);
+        return false;
+    }
+
+    static bool construct(JSContext *cx, HandleObject wrapper,
+                          const JS::CallArgs &args, const js::Wrapper& baseInstance)
+    {
+        RootedValue v(cx, ObjectValue(*wrapper));
+        js_ReportIsNotFunction(cx, v);
+        return false;
+    }
+
+    static bool isResolving(JSContext *cx, JSObject *holder, jsid id)
+    {
+        return false;
+    }
+
+    typedef ResolvingIdDummy ResolvingIdImpl;
+
+    bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
+                               JS::HandleObject target,
+                               JS::MutableHandleObject protop)
+    {
+        // Opaque wrappers just get targetGlobal.Object.prototype as their
+        // prototype. This is preferable to using a null prototype because it
+        // lets things like |toString| and |__proto__| work.
+        {
+            JSAutoCompartment ac(cx, target);
+            if (!JS_GetClassPrototype(cx, JSProto_Object, protop))
+                return false;
+        }
+        return JS_WrapObject(cx, protop);
+    }
+
+    static const char *className(JSContext *cx, HandleObject wrapper, const js::Wrapper& baseInstance) {
+        return "Opaque";
+    }
+
+    virtual void preserveWrapper(JSObject *target) MOZ_OVERRIDE { }
+
+    virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE
+    {
+        RootedObject global(cx, JS_GetGlobalForObject(cx, wrapper));
+        return JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), global);
+    }
+
+    static OpaqueXrayTraits singleton;
+};
+
 inline bool
 SilentFailure(JSContext *cx, HandleId id, const char *reason)
 {
 #ifdef DEBUG
     nsAutoJSString name;
     if (!name.init(cx, id))
         return false;
     AutoFilename filename;
@@ -501,17 +590,18 @@ bool JSXrayTraits::getOwnPropertyFromTar
         RootedObject propObj(cx, js::UncheckedUnwrap(&desc.value().toObject()));
         JSAutoCompartment ac(cx, propObj);
 
         // Disallow non-subsumed objects.
         if (!AccessCheck::subsumes(target, propObj))
             return SilentFailure(cx, id, "Value not same-origin with target");
 
         // Disallow non-Xrayable objects.
-        if (GetXrayType(propObj) == NotXray)
+        XrayType xrayType = GetXrayType(propObj);
+        if (xrayType == NotXray || xrayType == XrayForOpaqueObject)
             return SilentFailure(cx, id, "Value not Xrayable");
 
         // Disallow callables.
         if (JS_ObjectIsCallable(cx, propObj))
             return SilentFailure(cx, id, "Value is callable");
     }
 
     // Disallow any property that shadows something on its (Xrayed)
@@ -944,27 +1034,30 @@ JSXrayTraits::createHolder(JSContext *cx
     }
 
     return holder;
 }
 
 XPCWrappedNativeXrayTraits XPCWrappedNativeXrayTraits::singleton;
 DOMXrayTraits DOMXrayTraits::singleton;
 JSXrayTraits JSXrayTraits::singleton;
+OpaqueXrayTraits OpaqueXrayTraits::singleton;
 
 XrayTraits*
 GetXrayTraits(JSObject *obj)
 {
     switch (GetXrayType(obj)) {
       case XrayForDOMObject:
         return &DOMXrayTraits::singleton;
       case XrayForWrappedNative:
         return &XPCWrappedNativeXrayTraits::singleton;
       case XrayForJSObject:
         return &JSXrayTraits::singleton;
+      case XrayForOpaqueObject:
+        return &OpaqueXrayTraits::singleton;
       default:
         return nullptr;
     }
 }
 
 /*
  * Xray expando handling.
  *
@@ -2601,16 +2694,23 @@ bool
 XrayWrapper<Base, Traits>::construct(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args) const
 {
     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::CALL);
     // Hard cast the singleton since SecurityWrapper doesn't have one.
     return Traits::construct(cx, wrapper, args, Base::singleton);
 }
 
 template <typename Base, typename Traits>
+const char *
+XrayWrapper<Base, Traits>::className(JSContext *cx, HandleObject wrapper) const
+{
+    return Traits::className(cx, wrapper, Base::singleton);
+}
+
+template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::defaultValue(JSContext *cx, HandleObject wrapper,
                                         JSType hint, MutableHandleValue vp) const
 {
     // Even if this isn't a security wrapper, Xray semantics dictate that we
     // run the DefaultValue algorithm directly on the Xray wrapper.
     //
     // NB: We don't have to worry about things with special [[DefaultValue]]
@@ -2697,16 +2797,20 @@ template<>
 const SecurityXrayDOM SecurityXrayDOM::singleton(0);
 template class SecurityXrayDOM;
 
 template<>
 const PermissiveXrayJS PermissiveXrayJS::singleton(0);
 template class PermissiveXrayJS;
 
 template<>
+const PermissiveXrayOpaque PermissiveXrayOpaque::singleton(0);
+template class PermissiveXrayOpaque;
+
+template<>
 const SCSecurityXrayXPCWN SCSecurityXrayXPCWN::singleton(0);
 template class SCSecurityXrayXPCWN;
 
 static nsQueryInterface
 do_QueryInterfaceNative(JSContext* cx, HandleObject wrapper)
 {
     nsISupports* nativeSupports;
     if (IsWrapper(wrapper) && WrapperFactory::IsXrayWrapper(wrapper)) {
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -44,22 +44,24 @@ bool
 HasNativeProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id,
                   bool *hasProp);
 }
 
 class XrayTraits;
 class XPCWrappedNativeXrayTraits;
 class DOMXrayTraits;
 class JSXrayTraits;
+class OpaqueXrayTraits;
 
 
 enum XrayType {
     XrayForDOMObject,
     XrayForWrappedNative,
     XrayForJSObject,
+    XrayForOpaqueObject,
     NotXray
 };
 
 XrayType GetXrayType(JSObject *obj);
 XrayTraits* GetXrayTraits(JSObject *obj);
 
 // NB: Base *must* derive from JSProxyHandler
 template <typename Base, typename Traits = XPCWrappedNativeXrayTraits >
@@ -97,16 +99,17 @@ class XrayWrapper : public Base {
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
                          JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
 
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       const JS::CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            const JS::CallArgs &args) const MOZ_OVERRIDE;
 
+    virtual const char *className(JSContext *cx, JS::HandleObject proxy) const MOZ_OVERRIDE;
     virtual bool defaultValue(JSContext *cx, JS::HandleObject wrapper,
                               JSType hint, JS::MutableHandleValue vp)
                               const MOZ_OVERRIDE;
 
     virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
                                 JS::MutableHandleObject protop) const MOZ_OVERRIDE;
     virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
                                 JS::HandleObject proto, bool *bp) const MOZ_OVERRIDE;
@@ -139,16 +142,17 @@ class XrayWrapper : public Base {
                    JS::AutoIdVector &props) const;
 };
 
 #define PermissiveXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::XPCWrappedNativeXrayTraits>
 #define SecurityXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::XPCWrappedNativeXrayTraits>
 #define PermissiveXrayDOM xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::DOMXrayTraits>
 #define SecurityXrayDOM xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::DOMXrayTraits>
 #define PermissiveXrayJS xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::JSXrayTraits>
+#define PermissiveXrayOpaque xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::OpaqueXrayTraits>
 #define SCSecurityXrayXPCWN xpc::XrayWrapper<js::SameCompartmentSecurityWrapper, xpc::XPCWrappedNativeXrayTraits>
 
 class SandboxProxyHandler : public js::Wrapper {
 public:
     SandboxProxyHandler() : js::Wrapper(0)
     {
     }
 
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3746,17 +3746,16 @@ FrameLayerBuilder::PaintItems(nsTArray<C
 /**
  * Returns true if it is preferred to draw the list of display
  * items separately for each rect in the visible region rather
  * than clipping to a complex region.
  */
 static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
 {
   if (!gfxPrefs::LayoutPaintRectsSeparately() ||
-      aContext->IsCairo() ||
       aClip == DrawRegionClip::CLIP_NONE) {
     return false;
   }
 
   DrawTarget *dt = aContext->GetDrawTarget();
   return dt->GetBackendType() == BackendType::DIRECT2D;
 }
 
--- a/layout/base/TouchCaret.cpp
+++ b/layout/base/TouchCaret.cpp
@@ -460,17 +460,16 @@ TouchCaret::HandleEvent(WidgetEvent* aEv
   if (!touchCaretElement) {
     return nsEventStatus_eIgnore;
   }
 
   nsEventStatus status = nsEventStatus_eIgnore;
 
   switch (aEvent->message) {
     case NS_TOUCH_START:
-    case NS_TOUCH_ENTER:
       status = HandleTouchDownEvent(aEvent->AsTouchEvent());
       break;
     case NS_MOUSE_BUTTON_DOWN:
       status = HandleMouseDownEvent(aEvent->AsMouseEvent());
       break;
     case NS_TOUCH_END:
       status = HandleTouchUpEvent(aEvent->AsTouchEvent());
       break;
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -2523,44 +2523,33 @@ nsCSSRendering::PaintGradient(nsPresCont
       stops.AppendElement(ColorStop(firstStop, firstColor));
     }
     stops.AppendElement(ColorStop(firstStop, lastColor));
   }
 
   bool isRepeat = aGradient->mRepeating || forceRepeatToCoverTiles;
 
   // Now set normalized color stops in pattern.
-  if (!ctx->IsCairo()) {
-    // Offscreen gradient surface cache (not a tile):
-    // On some backends (e.g. D2D), the GradientStops object holds an offscreen surface
-    // which is a lookup table used to evaluate the gradient. This surface can use
-    // much memory (ram and/or GPU ram) and can be expensive to create. So we cache it.
-    // The cache key correlates 1:1 with the arguments for CreateGradientStops (also the implied backend type)
-    // Note that GradientStop is a simple struct with a stop value (while GradientStops has the surface).
-    nsTArray<gfx::GradientStop> rawStops(stops.Length());
-    rawStops.SetLength(stops.Length());
-    for(uint32_t i = 0; i < stops.Length(); i++) {
-      rawStops[i].color = gfx::Color(stops[i].mColor.r, stops[i].mColor.g, stops[i].mColor.b, stops[i].mColor.a);
-      rawStops[i].offset = stopScale * (stops[i].mPosition - stopOrigin);
-    }
-    mozilla::RefPtr<mozilla::gfx::GradientStops> gs =
-      gfxGradientCache::GetOrCreateGradientStops(ctx->GetDrawTarget(),
-                                                 rawStops,
-                                                 isRepeat ? gfx::ExtendMode::REPEAT : gfx::ExtendMode::CLAMP);
-    gradientPattern->SetColorStops(gs);
-  } else {
-    for (uint32_t i = 0; i < stops.Length(); i++) {
-      double pos = stopScale*(stops[i].mPosition - stopOrigin);
-      gradientPattern->AddColorStop(pos, stops[i].mColor);
-    }
-    // Set repeat mode. Default cairo extend mode is PAD.
-    if (isRepeat) {
-      gradientPattern->SetExtend(gfxPattern::EXTEND_REPEAT);
-    }
+  // Offscreen gradient surface cache (not a tile):
+  // On some backends (e.g. D2D), the GradientStops object holds an offscreen surface
+  // which is a lookup table used to evaluate the gradient. This surface can use
+  // much memory (ram and/or GPU ram) and can be expensive to create. So we cache it.
+  // The cache key correlates 1:1 with the arguments for CreateGradientStops (also the implied backend type)
+  // Note that GradientStop is a simple struct with a stop value (while GradientStops has the surface).
+  nsTArray<gfx::GradientStop> rawStops(stops.Length());
+  rawStops.SetLength(stops.Length());
+  for(uint32_t i = 0; i < stops.Length(); i++) {
+    rawStops[i].color = gfx::Color(stops[i].mColor.r, stops[i].mColor.g, stops[i].mColor.b, stops[i].mColor.a);
+    rawStops[i].offset = stopScale * (stops[i].mPosition - stopOrigin);
   }
+  mozilla::RefPtr<mozilla::gfx::GradientStops> gs =
+    gfxGradientCache::GetOrCreateGradientStops(ctx->GetDrawTarget(),
+                                               rawStops,
+                                               isRepeat ? gfx::ExtendMode::REPEAT : gfx::ExtendMode::CLAMP);
+  gradientPattern->SetColorStops(gs);
 
   // Paint gradient tiles. This isn't terribly efficient, but doing it this
   // way is simple and sure to get pixel-snapping right. We could speed things
   // up by drawing tiles into temporary surfaces and copying those to the
   // destination, but after pixel-snapping tiles may not all be the same size.
   nsRect dirty;
   if (!dirty.IntersectRect(aDirtyRect, aFillArea))
     return;
--- a/layout/base/nsCSSRenderingBorders.cpp
+++ b/layout/base/nsCSSRenderingBorders.cpp
@@ -1063,31 +1063,19 @@ nsCSSBorderRenderer::CreateCornerGradien
     mBorderWidths[cornerHeight[aCorner]] * gradientCoeff[aCorner].a;
   pat1.y = cornerOrigin.y +
     mBorderWidths[cornerWidth[aCorner]]  * gradientCoeff[aCorner].b;
   pat2.x = cornerOrigin.x -
     mBorderWidths[cornerHeight[aCorner]] * gradientCoeff[aCorner].a;
   pat2.y = cornerOrigin.y -
     mBorderWidths[cornerWidth[aCorner]]  * gradientCoeff[aCorner].b;
 
-  float gradientOffset;
-  
-  if (mContext->IsCairo() &&
-      (mContext->OriginalSurface()->GetType() == gfxSurfaceType::D2D ||
-       mContext->OriginalSurface()->GetType() == gfxSurfaceType::Quartz))
-  {
-    // On quarz this doesn't do exactly the right thing, but it does do what
-    // most other browsers do and doing the 'right' thing seems to be
-    // hard with the quartz cairo backend.
-    gradientOffset = 0;
-  } else {
-    // When cairo/Azure does the gradient drawing this gives us pretty nice behavior!
-    gradientOffset = 0.25 / sqrt(pow(mBorderWidths[cornerHeight[aCorner]], 2) +
-                                 pow(mBorderWidths[cornerHeight[aCorner]], 2));
-  }
+  float gradientOffset =
+    0.25 / sqrt(pow(mBorderWidths[cornerHeight[aCorner]], 2) +
+                pow(mBorderWidths[cornerHeight[aCorner]], 2));
 
   nsRefPtr<gfxPattern> pattern = new gfxPattern(pat1.x, pat1.y, pat2.x, pat2.y);
   pattern->AddColorStop(0.5 - gradientOffset, gfxRGBA(aFirstColor));
   pattern->AddColorStop(0.5 + gradientOffset, gfxRGBA(aSecondColor));
 
   return pattern.forget();
 }
 
@@ -1184,164 +1172,16 @@ nsCSSBorderRenderer::DrawSingleWidthSoli
     mContext->LineTo(secondCorner);
     mContext->Stroke();
   }
 }
 
 void
 nsCSSBorderRenderer::DrawNoCompositeColorSolidBorder()
 {
-  const gfxFloat alpha = 0.55191497064665766025;
-
-  const twoFloats cornerMults[4] = { { -1,  0 },
-                                      {  0, -1 },
-                                      { +1,  0 },
-                                      {  0, +1 } };
-
-  const twoFloats centerAdjusts[4] = { { 0, +0.5 },
-                                        { -0.5, 0 },
-                                        { 0, -0.5 },
-                                        { +0.5, 0 } };
-
-  gfxPoint pc, pci, p0, p1, p2, p3, pd, p3i;
-
-  gfxCornerSizes innerRadii;
-  ComputeInnerRadii(mBorderRadii, mBorderWidths, &innerRadii);
-
-  gfxRect strokeRect = mOuterRect;
-  strokeRect.Deflate(gfxMargin(mBorderWidths[0] / 2.0, mBorderWidths[1] / 2.0,
-                               mBorderWidths[2] / 2.0, mBorderWidths[3] / 2.0));
-
-  NS_FOR_CSS_CORNERS(i) {
-      // the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw)
-    mozilla::css::Corner c = mozilla::css::Corner((i+1) % 4);
-    mozilla::css::Corner prevCorner = mozilla::css::Corner(i);
-
-    // i+2 and i+3 respectively.  These are used to index into the corner
-    // multiplier table, and were deduced by calculating out the long form
-    // of each corner and finding a pattern in the signs and values.
-    int i1 = (i+1) % 4;
-    int i2 = (i+2) % 4;
-    int i3 = (i+3) % 4;
-
-    pc = mOuterRect.AtCorner(c);
-    pci = mInnerRect.AtCorner(c);
-    mContext->SetLineWidth(mBorderWidths[i]);
-
-    nscolor firstColor, secondColor;
-    if (IsVisible(mBorderStyles[i]) && IsVisible(mBorderStyles[i1])) {
-      firstColor = mBorderColors[i];
-      secondColor = mBorderColors[i1];
-    } else if (IsVisible(mBorderStyles[i])) {
-      firstColor = mBorderColors[i];
-      secondColor = mBorderColors[i];
-    } else {
-      firstColor = mBorderColors[i1];
-      secondColor = mBorderColors[i1];
-    }
-
-    mContext->NewPath();
-
-    gfxPoint strokeStart, strokeEnd;
-
-    strokeStart.x = mOuterRect.AtCorner(prevCorner).x +
-      mBorderCornerDimensions[prevCorner].width * cornerMults[i2].a;
-    strokeStart.y = mOuterRect.AtCorner(prevCorner).y +
-      mBorderCornerDimensions[prevCorner].height * cornerMults[i2].b;
-
-    strokeEnd.x = pc.x + mBorderCornerDimensions[c].width * cornerMults[i].a;
-    strokeEnd.y = pc.y + mBorderCornerDimensions[c].height * cornerMults[i].b;
-
-    strokeStart.x += centerAdjusts[i].a * mBorderWidths[i];
-    strokeStart.y += centerAdjusts[i].b * mBorderWidths[i];
-    strokeEnd.x += centerAdjusts[i].a * mBorderWidths[i];
-    strokeEnd.y += centerAdjusts[i].b * mBorderWidths[i];
-
-    mContext->MoveTo(strokeStart);
-    mContext->LineTo(strokeEnd);
-    mContext->SetColor(gfxRGBA(mBorderColors[i]));
-    mContext->Stroke();
-
-    if (firstColor != secondColor) {
-      nsRefPtr<gfxPattern> pattern =
-        CreateCornerGradient(c, firstColor, secondColor);
-      mContext->SetPattern(pattern);
-    } else {
-      mContext->SetColor(firstColor);
-    }     
-    
-    if (mBorderRadii[c].width > 0 && mBorderRadii[c].height > 0) {
-      p0.x = pc.x + cornerMults[i].a * mBorderRadii[c].width;
-      p0.y = pc.y + cornerMults[i].b * mBorderRadii[c].height;
-
-      p3.x = pc.x + cornerMults[i3].a * mBorderRadii[c].width;
-      p3.y = pc.y + cornerMults[i3].b * mBorderRadii[c].height;
-
-      p1.x = p0.x + alpha * cornerMults[i2].a * mBorderRadii[c].width;
-      p1.y = p0.y + alpha * cornerMults[i2].b * mBorderRadii[c].height;
-
-      p2.x = p3.x - alpha * cornerMults[i3].a * mBorderRadii[c].width;
-      p2.y = p3.y - alpha * cornerMults[i3].b * mBorderRadii[c].height;
-
-      mContext->NewPath();
-            
-      gfxPoint cornerStart;
-      cornerStart.x = pc.x + cornerMults[i].a * mBorderCornerDimensions[c].width;
-      cornerStart.y = pc.y + cornerMults[i].b * mBorderCornerDimensions[c].height;
-
-      mContext->MoveTo(cornerStart);
-      mContext->LineTo(p0);
-
-      mContext->CurveTo(p1, p2, p3);
-            
-      gfxPoint outerCornerEnd;
-      outerCornerEnd.x = pc.x + cornerMults[i3].a * mBorderCornerDimensions[c].width;
-      outerCornerEnd.y = pc.y + cornerMults[i3].b * mBorderCornerDimensions[c].height;
-
-      mContext->LineTo(outerCornerEnd);
-
-      p0.x = pci.x + cornerMults[i].a * innerRadii[c].width;
-      p0.y = pci.y + cornerMults[i].b * innerRadii[c].height;
-
-      p3i.x = pci.x + cornerMults[i3].a * innerRadii[c].width;
-      p3i.y = pci.y + cornerMults[i3].b * innerRadii[c].height;
-
-      p1.x = p0.x + alpha * cornerMults[i2].a * innerRadii[c].width;
-      p1.y = p0.y + alpha * cornerMults[i2].b * innerRadii[c].height;
-
-      p2.x = p3i.x - alpha * cornerMults[i3].a * innerRadii[c].width;
-      p2.y = p3i.y - alpha * cornerMults[i3].b * innerRadii[c].height;
-      mContext->LineTo(p3i);
-      mContext->CurveTo(p2, p1, p0);
-      mContext->ClosePath();
-      mContext->Fill();
-    } else {
-      gfxPoint c1, c2, c3, c4;
-
-      c1.x = pc.x + cornerMults[i].a * mBorderCornerDimensions[c].width;
-      c1.y = pc.y + cornerMults[i].b * mBorderCornerDimensions[c].height;
-      c2 = pc;
-      c3.x = pc.x + cornerMults[i3].a * mBorderCornerDimensions[c].width;
-      c3.y = pc.y + cornerMults[i3].b * mBorderCornerDimensions[c].height;
-
-      mContext->NewPath();
-      mContext->MoveTo(c1);
-      mContext->LineTo(c2);
-      mContext->LineTo(c3);
-      mContext->LineTo(pci);
-      mContext->ClosePath();
-
-      mContext->Fill();
-    }
-  }
-}
-
-void
-nsCSSBorderRenderer::DrawNoCompositeColorSolidBorderAzure()
-{
   DrawTarget *dt = mContext->GetDrawTarget();
 
   const gfxFloat alpha = 0.55191497064665766025;
 
   const twoFloats cornerMults[4] = { { -1,  0 },
                                      {  0, -1 },
                                      { +1,  0 },
                                      {  0, +1 } };
@@ -1709,21 +1549,17 @@ nsCSSBorderRenderer::DrawBorders()
   {
     DrawSingleWidthSolidBorder();
     return;
   }
 
   if (allBordersSolid && !hasCompositeColors &&
       !mAvoidStroke)
   {
-    if (mContext->IsCairo()) {
-      DrawNoCompositeColorSolidBorder();
-    } else {
-      DrawNoCompositeColorSolidBorderAzure();
-    }
+    DrawNoCompositeColorSolidBorder();
     return;
   }
 
   if (allBordersSolid &&
       allBordersSameWidth &&
       mNoBorderRadius &&
       !mAvoidStroke)
   {
--- a/layout/base/nsCSSRenderingBorders.h
+++ b/layout/base/nsCSSRenderingBorders.h
@@ -198,19 +198,16 @@ struct nsCSSBorderRenderer {
                        mozilla::gfx::Point &aPoint1, mozilla::gfx::Point &aPoint2);
 
   // Draw a solid color border that is uniformly the same width.
   void DrawSingleWidthSolidBorder();
 
   // Draw any border which is solid on all sides and does not use
   // CompositeColors.
   void DrawNoCompositeColorSolidBorder();
-  // Draw any border which is solid on all sides and does not use
-  // CompositeColors. Using Azure.
-  void DrawNoCompositeColorSolidBorderAzure();
 
   // Draw a solid border that has no border radius (i.e. is rectangular) and
   // uses CompositeColors.
   void DrawRectangularCompositeColors();
 
   // draw the entire border
   void DrawBorders ();
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -7174,16 +7174,19 @@ PresShell::HandleEvent(nsIFrame* aFrame,
     if (aEvent->eventStructType == NS_POINTER_EVENT &&
         aEvent->message != NS_POINTER_DOWN) {
       if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
         uint32_t pointerId = pointerEvent->pointerId;
         nsIContent* pointerCapturingContent = GetPointerCapturingContent(pointerId);
 
         if (pointerCapturingContent) {
           if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) {
+            // If pointer capture is set, we should suppress pointerover/pointerenter events
+            // for all elements except element which have pointer capture. (Code in EventStateManager)
+            pointerEvent->retargetedByPointerCapture = (frame != capturingFrame);
             frame = capturingFrame;
           }
 
           if (pointerEvent->message == NS_POINTER_UP ||
               pointerEvent->message == NS_POINTER_CANCEL) {
             // Implicitly releasing capture for given pointer.
             // LOST_POINTER_CAPTURE should be send after NS_POINTER_UP or NS_POINTER_CANCEL.
             releasePointerCaptureCaller.SetTarget(pointerId, pointerCapturingContent);
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug976963_inner.html
@@ -0,0 +1,243 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=976963
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 976963</title>
+  <meta name="author" content="Maksim Lebedev" />
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style>
+    div#listener {
+      background: yellow;
+      position: absolute;
+      top: -100px;
+    }
+    div#middler {
+      background: yellow;
+      margin: 10px;
+    }
+    div#target {
+      background: yellow;
+    }
+  </style>
+  <script type="application/javascript">
+    /** Test for Bug 976963 **/
+    var All_Pointer_Events = ["pointerover",        "pointerenter",
+                              "pointermove",
+                              "pointerdown",        "pointerup",
+                              "pointerout",         "pointerleave",
+                              "pointercancel",
+                              "gotpointercapture",  "lostpointercapture"];
+
+    function on_event(object, event, callback) {
+      object.addEventListener(event, callback, false);
+    }
+    function ok(check, msg) {
+      parent.ok(check, msg);
+    }
+    function is(a, b, msg) {
+      parent.is(a, b, msg);
+    }
+
+    var listener = undefined;
+    var middler = undefined;
+    var target = undefined;
+
+    var test_ListenerGotCapture = 0;
+    var test_ListenerUnwanted = 0;
+    var test_ListenerLostCapture = 0;
+    var test_ListenerAfterCapture = 0;
+    var test_MiddlerGotCapture = 0;
+    var test_MiddlerOver = 0;
+    var test_MiddlerLeave = 0;
+    var test_MiddlerUp = 0;
+    var test_MiddlerLostCapture = 0;
+    var test_TargetDown = 0;
+    var test_TargetUnwanted = 0;
+    var test_TargetUp = 0;
+
+    var captured_event = undefined;
+    var f_gotPointerCapture = false;
+    var f_lostPointerCapture = false;
+    var f_gotMiddlerPointerCapture = false;
+
+    function listenerEventHandler(event) {
+      logger("Listener: " + event.type + ". Captured_event: " + captured_event);
+      if(test_ListenerLostCapture)
+        test_ListenerAfterCapture++;
+      if (event.type == "gotpointercapture") {
+        f_gotPointerCapture = true;
+        test_ListenerGotCapture++;
+      }
+      else if (event.type == "lostpointercapture") {
+        f_lostPointerCapture = true;
+        f_gotPointerCapture = false;
+        test_ListenerLostCapture++;
+      }
+      else if (event.type == "pointermove") {
+        ok(captured_event && captured_event.pointerId == event.pointerId, "Listener: equals pointerId for lostpointercapture event");
+        if (f_gotPointerCapture) {
+          // on first event received for capture, release capture
+          logger("Listener call release");
+          ok(!!listener, "Listener should be live!");
+          ok(typeof(listener.releasePointerCapture) == "function", "Listener should have a function releasePointerCapture");
+          listener.releasePointerCapture(event.pointerId);
+        }
+        else {
+          logger("Listener.ASSERT: " + event.type);
+          test_ListenerUnwanted++;
+          // if any other events are received after releaseCapture, then the test fails
+          ok(false, event.target.id + "-" + event.type + " should be handled by target element handler");
+        }
+      }
+      else {
+        test_ListenerUnwanted++;
+        logger("Listener.ASSERT: " + event.type);
+        ok(false, event.type + "should be never handled by listener");
+      }
+    }
+
+    function middlerEventHandler(event) {
+      logger("Middler: " + event.type + ". Captured_event: " + captured_event);
+      if (event.type == "gotpointercapture") {
+        test_MiddlerGotCapture++;
+        f_gotMiddlerPointerCapture = true;
+        ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for gotpointercapture event");
+      }
+      else if (event.type == "pointerover") {
+        test_MiddlerOver++;
+        ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for pointerover event");
+      }
+      else if (event.type == "pointerleave") {
+        test_MiddlerLeave++;
+        ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for pointerleave event");
+        ok(!!listener, "Listener should be live!");
+        ok(typeof(listener.setPointerCapture) == "function", "Listener should have a function setPointerCapture");
+        listener.setPointerCapture(event.pointerId);
+      }
+      else if (event.type == "lostpointercapture") {
+        test_MiddlerLostCapture++;
+        f_gotMiddlerPointerCapture = false;
+        ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for lostpointercapture event");
+      }
+      else if (event.type == "pointerup" ) {
+        test_MiddlerUp++;
+      }
+    }
+  
+    function targetEventHandler(event) {
+      logger("Target: " + event.type + ". Captured_event: " + captured_event);
+      if (f_gotPointerCapture || f_gotMiddlerPointerCapture) {
+        if (event.type != "pointerout" && event.type != "pointerleave") {
+          logger("Target.ASSERT: " + event.type + " " + event.pointerId);
+          test_TargetUnwanted++;
+          ok(false, "The Target element should not have received any events while capture is active. Event recieved:" + event.type + ".  ");
+        }
+      }
+      if (event.type == "pointerdown") {
+        logger("Target.pointerdown 1: " + captured_event);
+        test_TargetDown++;
+        captured_event = event;
+        ok(!!middler, "Middler should be live!");
+        ok(typeof(middler.setPointerCapture) == "function", "Middler should have a function setPointerCapture");
+        middler.setPointerCapture(event.pointerId);
+        logger("Target.pointerdown 2: " + captured_event);
+      }
+      else if (event.type == "pointerup") {
+        ok(f_lostPointerCapture, "Target should have received pointerup");
+        ok(captured_event && captured_event.pointerId == event.pointerId, "Target: equals pointerId for lostpointercapture event");
+        test_TargetUp++; // complete test
+      }
+    }
+
+    function colorerHandler(event) {
+      if(event.type == "pointerover")
+        event.target.style.background = "red";
+      else if(event.type == "pointerout")
+        event.target.style.background = "yellow";
+    }
+    
+    function setEventHandlers() {
+      listener = document.getElementById("listener");
+      middler = document.getElementById("middler");
+      target = document.getElementById("target");
+      target.style["touchAction"] = "none";
+
+      // target and listener - handle all events
+      for (var i = 0; i < All_Pointer_Events.length; i++) {
+        on_event(target,    All_Pointer_Events[i], targetEventHandler);
+        on_event(listener,  All_Pointer_Events[i], listenerEventHandler);
+        on_event(middler,   All_Pointer_Events[i], middlerEventHandler);
+        on_event(target,    All_Pointer_Events[i], colorerHandler);
+        on_event(middler,   All_Pointer_Events[i], colorerHandler);
+      }
+    }
+
+    function prepareTest() {
+      SimpleTest.waitForExplicitFinish();
+      SpecialPowers.pushPrefEnv({
+        "set": [
+          ["dom.w3c_pointer_events.enabled", true]
+        ]
+      }, executeTest);
+    }    
+    
+    function executeTest()
+    {
+      logger("executeTest");
+      setEventHandlers();
+      document.body.offsetLeft;
+      var rect = target.getBoundingClientRect();
+      synthesizePointer(target,  rect.width/2, rect.height/2, {type: "pointermove"});
+      synthesizePointer(target,  rect.width/2, rect.height/2, {type: "pointerdown"});
+      synthesizePointer(target,  rect.width/3, rect.height/3, {type: "pointermove"});
+      synthesizePointer(middler, rect.width/2, rect.height/2, {type: "pointermove"});
+      synthesizePointer(target,  rect.width/2, rect.height/2, {type: "pointermove"});
+      synthesizePointer(middler, rect.width/2, rect.height/2, {type: "pointermove"});
+      synthesizePointer(target,  rect.width/2, rect.height/2, {type: "pointermove"});
+      synthesizePointer(target,  rect.width/2, rect.height/2, {type: "pointerup"});
+      finishTest();
+    }
+
+    function finishTest() {
+      setTimeout(function() {
+        is(test_ListenerGotCapture, 1, "Listener should receive gotpointercapture event");
+        is(test_ListenerUnwanted, 0, "Listener should not receive any unwanted events");
+        is(test_ListenerLostCapture, 1, "Listener should receive lostpointercapture event");
+        is(test_ListenerAfterCapture, 0, "Listener should not receive any events after release pointer capture");
+        is(test_MiddlerGotCapture, 1, "Middler should receive gotpointercapture event");
+        is(test_MiddlerOver, 1, "Middler should receive pointerover event");
+        is(test_MiddlerLeave, 1, "Middler should receive pointerleave event");
+        is(test_MiddlerUp, 0, "Middler should not receive pointerup event");
+        is(test_MiddlerLostCapture, 1, "Middler should receive lostpointercapture event");
+        is(test_TargetDown, 1, "Target should receive pointerdown event");
+        is(test_TargetUnwanted, 0, "Target should not receive any event while pointer capture is active");
+        is(test_TargetUp, 1, "Target should receive pointerup event");
+        logger("finishTest");
+        parent.finishTest();
+      }, 1000);
+    }
+
+    function logger(message) {
+      console.log(message);
+      var log = document.getElementById('log');
+      log.innerHTML = message + "<br>" + log.innerHTML;
+    }
+  </script>
+</head>
+<body onload="prepareTest()">
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=976963">Mozilla Bug 976963</a>
+  <p id="display"></p>
+  <div id="content" style="display: none">
+  </div>
+  <div id="listener">div id=listener</div>
+  <div id="middler">div id=middler</div>
+  <div id="target">div id=target</div>
+  <pre id="log">
+  </pre>
+</body>
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -204,16 +204,18 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug842853.html]
 [test_bug842853-2.html]
 [test_bug849219.html]
 [test_bug851485.html]
 [test_bug851445.html]
 support-files = bug851445_helper.html
 [test_bug970964.html]
 support-files = bug970964_inner.html
+[test_bug976963.html]
+support-files = bug976963_inner.html
 [test_emulateMedium.html]
 [test_getClientRects_emptytext.html]
 [test_bug858459.html]
 skip-if = toolkit == "gonk" || buildapp == 'b2g' #Bug 931116, b2g desktop specific, initial triage
 
 # Tests for bugs 441782, 467672 and 570378 do not pass reliably on Windows,
 # because of bug 469208.
 [test_bug332655-1.html]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug976963.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=976963
+-->
+  <head>
+    <meta charset="utf-8">
+    <meta name="author" content="Maksim Lebedev" />
+    <title>Test for Bug 976963</title>
+    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      function prepareTest() {
+        SimpleTest.waitForExplicitFinish();
+        SpecialPowers.pushPrefEnv({
+          "set": [
+            ["dom.w3c_pointer_events.enabled", true]
+          ]
+        }, startTest);
+      }
+      function startTest() {
+        var iframe = document.getElementById("testFrame");
+        iframe.src = "bug976963_inner.html";
+      }
+      function finishTest() {
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="prepareTest()">
+    <iframe id="testFrame" height="700" width="700"></iframe>
+  </body>
+</html>
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -3029,17 +3029,20 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
       // value. We'll use a reason of `resize' so that we don't fudge
       // any incremental reflow state.
 
       // The availSpace here is irrelevant to our needs - all we want
       // out if this setup is the margin-top value which doesn't depend
       // on the childs available space.
       // XXX building a complete nsHTMLReflowState just to get the margin-top
       // seems like a waste. And we do this for almost every block!
-      nsSize availSpace(aState.ContentISize(), NS_UNCONSTRAINEDSIZE);
+      nsSize availSpace =
+        LogicalSize(aState.mReflowState.GetWritingMode(),
+                    aState.ContentISize(), NS_UNCONSTRAINEDSIZE).
+          GetPhysicalSize(aState.mReflowState.GetWritingMode());
       nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState,
                                     frame, availSpace);
 
       if (treatWithClearance) {
         aState.mBCoord += aState.mPrevBEndMargin.get();
         aState.mPrevBEndMargin.Zero();
       }
 
@@ -5747,17 +5750,17 @@ nsBlockFrame::AdjustFloatAvailableSpace(
   }
 #endif
 
   WritingMode wm = aState.mReflowState.GetWritingMode();
   LogicalRect availSpace(wm, aState.ContentIStart(), aState.ContentBStart(),
                          availISize, availBSize);
 
   // for now return a physical rect
-  return availSpace.GetPhysicalRect(wm, aState.ContentISize());
+  return availSpace.GetPhysicalRect(wm, aState.mContainerWidth);
 }
 
 nscoord
 nsBlockFrame::ComputeFloatWidth(nsBlockReflowState& aState,
                                 const nsRect&       aFloatAvailableSpace,
                                 nsIFrame*           aFloat)
 {
   NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -324,19 +324,19 @@ nsHTMLReflowState::SetComputedHeight(nsc
 
 void
 nsHTMLReflowState::Init(nsPresContext* aPresContext,
                         nscoord         aContainingBlockWidth,
                         nscoord         aContainingBlockHeight,
                         const nsMargin* aBorder,
                         const nsMargin* aPadding)
 {
-  NS_WARN_IF_FALSE(AvailableWidth() != NS_UNCONSTRAINEDSIZE,
-                   "have unconstrained width; this should only result from "
-                   "very large sizes, not attempts at intrinsic width "
+  NS_WARN_IF_FALSE(AvailableISize() != NS_UNCONSTRAINEDSIZE,
+                   "have unconstrained inline-size; this should only result from "
+                   "very large sizes, not attempts at intrinsic inline-size "
                    "calculation");
 
   mStylePosition = frame->StylePosition();
   mStyleDisplay = frame->StyleDisplay();
   mStyleVisibility = frame->StyleVisibility();
   mStyleBorder = frame->StyleBorder();
   mStyleMargin = frame->StyleMargin();
   mStylePadding = frame->StylePadding();
@@ -400,19 +400,19 @@ nsHTMLReflowState::Init(nsPresContext* a
     }
   } else {
     frame->RemoveStateBits(NS_FRAME_IN_CONSTRAINED_HEIGHT);
   }
 
   NS_WARN_IF_FALSE((mFrameType == NS_CSS_FRAME_TYPE_INLINE &&
                     !frame->IsFrameOfType(nsIFrame::eReplaced)) ||
                    type == nsGkAtoms::textFrame ||
-                   ComputedWidth() != NS_UNCONSTRAINEDSIZE,
-                   "have unconstrained width; this should only result from "
-                   "very large sizes, not attempts at intrinsic width "
+                   ComputedISize() != NS_UNCONSTRAINEDSIZE,
+                   "have unconstrained inline-size; this should only result from "
+                   "very large sizes, not attempts at intrinsic inline-size "
                    "calculation");
 }
 
 void nsHTMLReflowState::InitCBReflowState()
 {
   if (!parentReflowState) {
     mCBReflowState = nullptr;
     return;
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -717,25 +717,25 @@ nsInlineFrame::ReflowFrames(nsPresContex
     // in the css2 spec! It's actually found in the css1 spec section
     // 4.4 (you will have to read between the lines to really see
     // it).
     //
     // The height of our box is the sum of our font size plus the top
     // and bottom border and padding. The height of children do not
     // affect our height.
     aMetrics.SetBlockStartAscent(fm->MaxAscent());
-    aMetrics.Height() = fm->MaxHeight();
+    aMetrics.BSize(lineWM) = fm->MaxHeight();
   } else {
     NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
     aMetrics.SetBlockStartAscent(aMetrics.Height() = 0);
   }
   aMetrics.SetBlockStartAscent(aMetrics.BlockStartAscent() +
                                framePadding.BStart(frameWM));
-  aMetrics.Height() += aReflowState.ComputedPhysicalBorderPadding().top +
-    aReflowState.ComputedPhysicalBorderPadding().bottom;
+  aMetrics.BSize(lineWM) +=
+    aReflowState.ComputedLogicalBorderPadding().BStartEnd(frameWM);
 
   // For now our overflow area is zero. The real value will be
   // computed in |nsLineLayout::RelativePositionFrames|.
   aMetrics.mOverflowAreas.Clear();
 
 #ifdef NOISY_FINAL_SIZE
   ListTag(stdout);
   printf(": metrics=%d,%d ascent=%d\n",
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -768,33 +768,35 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
   // the state out. We need to know how to treat the current frame
   // when breaking.
   bool notSafeToBreak = LineIsEmpty() && !mImpactedByFloats;
 
   // Figure out whether we're talking about a textframe here
   nsIAtom* frameType = aFrame->GetType();
   bool isText = frameType == nsGkAtoms::textFrame;
   
-  // Compute the available size for the frame. This available width
-  // includes room for the side margins.
-  // For now, set the available height to unconstrained always.
-  nsSize availSize(mBlockReflowState->ComputedWidth(), NS_UNCONSTRAINEDSIZE);
-
   // Inline-ish and text-ish things don't compute their width;
   // everything else does.  We need to give them an available width that
   // reflects the space left on the line.
   NS_WARN_IF_FALSE(psd->mIEnd != NS_UNCONSTRAINEDSIZE,
                    "have unconstrained width; this should only result from "
                    "very large sizes, not attempts at intrinsic width "
                    "calculation");
   nscoord availableSpaceOnLine = psd->mIEnd - psd->mICoord;
 
   // Setup reflow state for reflowing the frame
   Maybe<nsHTMLReflowState> reflowStateHolder;
   if (!isText) {
+    // Compute the available size for the frame. This available width
+    // includes room for the side margins.
+    // For now, set the available block-size to unconstrained always.
+    nsSize availSize =
+      LogicalSize(mBlockReflowState->GetWritingMode(),
+                  mBlockReflowState->ComputedISize(), NS_UNCONSTRAINEDSIZE).
+        GetPhysicalSize(mBlockReflowState->GetWritingMode());
     reflowStateHolder.construct(mPresContext, *psd->mReflowState,
                                 aFrame, availSize);
     nsHTMLReflowState& reflowState = reflowStateHolder.ref();
     reflowState.mLineLayout = this;
     reflowState.mFlags.mIsTopOfPage = mIsTopOfPage;
     if (reflowState.ComputedWidth() == NS_UNCONSTRAINEDSIZE)
       reflowState.AvailableWidth() = availableSpaceOnLine;
     WritingMode stateWM = reflowState.GetWritingMode();
--- a/layout/svg/nsSVGPaintServerFrame.cpp
+++ b/layout/svg/nsSVGPaintServerFrame.cpp
@@ -19,15 +19,13 @@ nsSVGPaintServerFrame::SetupPaintServer(
                                         float aOpacity)
 {
   nsRefPtr<gfxPattern> pattern =
     GetPaintServerPattern(aSource, aContext->CurrentMatrix(), aFillOrStroke,
                           aOpacity);
   if (!pattern)
     return false;
 
-  if (!aContext->IsCairo()) {
-    pattern->CacheColorStops(aContext->GetDrawTarget());
-  }
+  pattern->CacheColorStops(aContext->GetDrawTarget());
 
   aContext->SetPattern(pattern);
   return true;
 }
--- a/netwerk/base/public/security-prefs.js
+++ b/netwerk/base/public/security-prefs.js
@@ -18,30 +18,30 @@ pref("security.ssl.enable_npn", true);
 pref("security.ssl.enable_alpn", false);
 
 pref("security.ssl3.ecdhe_rsa_aes_128_gcm_sha256", true);
 pref("security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256", true);
 pref("security.ssl3.ecdhe_rsa_aes_128_sha", true);
 pref("security.ssl3.ecdhe_ecdsa_aes_128_sha", true);
 pref("security.ssl3.ecdhe_rsa_aes_256_sha", true);
 pref("security.ssl3.ecdhe_ecdsa_aes_256_sha", true);
-pref("security.ssl3.ecdhe_rsa_des_ede3_sha", true);
+pref("security.ssl3.ecdhe_rsa_des_ede3_sha", false);
 pref("security.ssl3.dhe_rsa_aes_128_sha", true);
-pref("security.ssl3.dhe_rsa_camellia_128_sha", true);
+pref("security.ssl3.dhe_rsa_camellia_128_sha", false);
 pref("security.ssl3.dhe_rsa_aes_256_sha", true);
-pref("security.ssl3.dhe_rsa_camellia_256_sha", true);
-pref("security.ssl3.dhe_rsa_des_ede3_sha", true);
+pref("security.ssl3.dhe_rsa_camellia_256_sha", false);
+pref("security.ssl3.dhe_rsa_des_ede3_sha", false);
 pref("security.ssl3.dhe_dss_aes_128_sha", true);
-pref("security.ssl3.dhe_dss_aes_256_sha", true);
+pref("security.ssl3.dhe_dss_aes_256_sha", false);
 pref("security.ssl3.ecdhe_rsa_rc4_128_sha", true);
 pref("security.ssl3.ecdhe_ecdsa_rc4_128_sha", true);
 pref("security.ssl3.rsa_aes_128_sha", true);
-pref("security.ssl3.rsa_camellia_128_sha", true);
+pref("security.ssl3.rsa_camellia_128_sha", false);
 pref("security.ssl3.rsa_aes_256_sha", true);
-pref("security.ssl3.rsa_camellia_256_sha", true);
+pref("security.ssl3.rsa_camellia_256_sha", false);
 pref("security.ssl3.rsa_des_ede3_sha", true);
 pref("security.ssl3.rsa_rc4_128_sha", true);
 pref("security.ssl3.rsa_rc4_128_md5", true);
 
 pref("security.default_personal_cert",   "Ask Every Time");
 pref("security.remember_cert_checkbox_default_setting", true);
 pref("security.ask_for_password",        0);
 pref("security.password_lifetime",       30);
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -814,49 +814,51 @@ static const CipherPref sCipherPrefs[] =
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, true },
 
  { "security.ssl3.ecdhe_rsa_aes_256_sha",
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, true },
  { "security.ssl3.ecdhe_ecdsa_aes_256_sha",
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, true },
 
  { "security.ssl3.ecdhe_rsa_des_ede3_sha",
-   TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, true }, // deprecated (3DES)
+   TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, false }, // deprecated (3DES)
 
  { "security.ssl3.dhe_rsa_aes_128_sha",
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA, true },
+
  { "security.ssl3.dhe_rsa_camellia_128_sha",
-   TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, true },
+   TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, false }, // deprecated (Camellia)
 
  { "security.ssl3.dhe_rsa_aes_256_sha",
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true },
+
  { "security.ssl3.dhe_rsa_camellia_256_sha",
-   TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, true },
+   TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, false }, // deprecated (Camellia)
 
  { "security.ssl3.dhe_rsa_des_ede3_sha",
-   TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, true }, // deprecated (3DES)
+   TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, false }, // deprecated (3DES)
 
  { "security.ssl3.dhe_dss_aes_128_sha",
    TLS_DHE_DSS_WITH_AES_128_CBC_SHA, true }, // deprecated (DSS)
  { "security.ssl3.dhe_dss_aes_256_sha",
-   TLS_DHE_DSS_WITH_AES_256_CBC_SHA, true }, // deprecated (DSS)
+   TLS_DHE_DSS_WITH_AES_256_CBC_SHA, false }, // deprecated (DSS)
 
  { "security.ssl3.ecdhe_rsa_rc4_128_sha",
    TLS_ECDHE_RSA_WITH_RC4_128_SHA, true }, // deprecated (RC4)
  { "security.ssl3.ecdhe_ecdsa_rc4_128_sha",
    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, true }, // deprecated (RC4)
 
  { "security.ssl3.rsa_aes_128_sha",
    TLS_RSA_WITH_AES_128_CBC_SHA, true }, // deprecated (RSA key exchange)
  { "security.ssl3.rsa_camellia_128_sha",
-   TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, true }, // deprecated (RSA key exchange)
+   TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, false }, // deprecated (RSA, Camellia)
  { "security.ssl3.rsa_aes_256_sha",
    TLS_RSA_WITH_AES_256_CBC_SHA, true }, // deprecated (RSA key exchange)
  { "security.ssl3.rsa_camellia_256_sha",
-   TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, true }, // deprecated (RSA key exchange)
+   TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, false }, // deprecated (RSA, Camellia)
  { "security.ssl3.rsa_des_ede3_sha",
    TLS_RSA_WITH_3DES_EDE_CBC_SHA, true }, // deprecated (RSA key exchange, 3DES)
 
  { "security.ssl3.rsa_rc4_128_sha",
    TLS_RSA_WITH_RC4_128_SHA, true }, // deprecated (RSA key exchange, RC4)
  { "security.ssl3.rsa_rc4_128_md5",
    TLS_RSA_WITH_RC4_128_MD5, true }, // deprecated (RSA key exchange, RC4, HMAC-MD5)
 
--- a/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js
+++ b/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js
@@ -535,17 +535,17 @@ MozMillElement.prototype.rightClick = fu
  *        the touch event was fired
  * @param {Touch[]} [aEvent.targetTouches]
  *        A TouchList of all the Touch objects that are both currently in
  *        contact with the touch surface and were also started on the same
  *        element that is the target of the event
  * @param {Touch[]} [aEvent.touches]
  *        A TouchList of all the Touch objects representing all current points
  *        of contact with the surface, regardless of target or changed status
- * @param {Number} [aEvent.type=*|touchstart|touchend|touchmove|touchenter|touchleave|touchcancel]
+ * @param {Number} [aEvent.type=*|touchstart|touchend|touchmove|touchcancel]
  *        The type of touch event that occurred
  * @param {Element} [aEvent.target]
  *        The target of the touches associated with this event. This target
  *        corresponds to the target of all the touches in the targetTouches
  *        attribute, but note that other touches in this event may have a
  *        different target. To be careful, you should use the target associated
  *        with individual touches
  */
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -302,24 +302,24 @@ function synthesizePointerAtPoint(left, 
     var button = aEvent.button || 0;
     var clickCount = aEvent.clickCount || 1;
     var modifiers = _parseModifiers(aEvent);
     var pressure = ("pressure" in aEvent) ? aEvent.pressure : 0;
     var inputSource = ("inputSource" in aEvent) ? aEvent.inputSource : 0;
     var synthesized = ("isSynthesized" in aEvent) ? aEvent.isSynthesized : true;
 
     if (("type" in aEvent) && aEvent.type) {
-      defaultPrevented = utils.sendPointerEvent(aEvent.type, left, top, button,
-                                                clickCount, modifiers, false,
-                                                pressure, inputSource,
-                                                synthesized);
+      defaultPrevented = utils.sendPointerEventToWindow(aEvent.type, left, top, button,
+                                                        clickCount, modifiers, false,
+                                                        pressure, inputSource,
+                                                        synthesized);
     }
     else {
-      utils.sendPointerEvent("pointerdown", left, top, button, clickCount, modifiers, false, pressure, inputSource);
-      utils.sendPointerEvent("pointerup", left, top, button, clickCount, modifiers, false, pressure, inputSource);
+      utils.sendPointerEventToWindow("pointerdown", left, top, button, clickCount, modifiers, false, pressure, inputSource);
+      utils.sendPointerEventToWindow("pointerup", left, top, button, clickCount, modifiers, false, pressure, inputSource);
     }
   }
 
   return defaultPrevented;
 }
 
 // Call synthesizeMouse with coordinates at the center of aTarget.
 function synthesizeMouseAtCenter(aTarget, aEvent, aWindow)
--- a/testing/mozbase/docs/mozdevice.rst
+++ b/testing/mozbase/docs/mozdevice.rst
@@ -195,16 +195,20 @@ Process management methods
 .. automethod:: ADBDevice.pkill(self, appname, sig=None,   attempts=3, wait=5, timeout=None, root=False)
 .. automethod:: ADBDevice.process_exist(self, process_name, timeout=None)
 
 
 ADBAndroid
 ``````````
 .. autoclass:: ADBAndroid
 
+Informational methods
++++++++++++++++++++++
+.. automethod:: ADBAndroid.get_battery_percentage(self, timeout=None)
+
 System control methods
 ++++++++++++++++++++++
 .. automethod:: ADBAndroid.is_device_ready(self, timeout=None)
 .. automethod:: ADBAndroid.power_on(self, timeout=None)
 .. automethod:: ADBAndroid.reboot(self, timeout=None)
 
 Application management methods
 ++++++++++++++++++++++++++++++
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -219,20 +219,18 @@ class ADBCommand(object):
         :param timeout: optional integer specifying the maximum time in seconds
             for any spawned adb process to complete before throwing
             an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBCommand constructor is used.
         :returns: string - content of stdout.
 
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         adb_process = None
         try:
             # Need to force the use of the ADBCommand class's command
             # since ADBDevice will redefine command and call its
             # own version otherwise.
             adb_process = ADBCommand.command(self, cmds,
@@ -330,69 +328,61 @@ class ADBHost(ADBCommand):
         :param timeout: optional integer specifying the maximum time in seconds
             for any spawned adb process to complete before throwing
             an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBHost constructor is used.
         :returns: string - content of stdout.
 
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         return ADBCommand.command_output(self, cmds, timeout=timeout)
 
     def start_server(self, timeout=None):
         """Starts the adb server.
 
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.  This timeout is per adb call. The
             total time spent may exceed this value. If it is not
             specified, the value set in the ADBHost constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         self.command_output(["start-server"], timeout=timeout)
 
     def kill_server(self, timeout=None):
         """Kills the adb server.
 
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.  This timeout is per adb call. The
             total time spent may exceed this value. If it is not
             specified, the value set in the ADBHost constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         self.command_output(["kill-server"], timeout=timeout)
 
     def devices(self, timeout=None):
         """Executes adb devices -l and returns a list of objects describing attached devices.
 
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.  This timeout is per adb call. The
             total time spent may exceed this value. If it is not
             specified, the value set in the ADBHost constructor is used.
         :returns: an object contain
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         The output of adb devices -l ::
 
             $ adb devices -l
             List of devices attached
             b313b945               device usb:1-7 product:d2vzw model:SCH_I535 device:d2vzw
 
         is parsed and placed into an object as in
@@ -587,18 +577,17 @@ class ADBDevice(ADBCommand):
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
         :raises: * ADBTimeoutError
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
+                 * ADBRootError
                  * ADBError
 
         """
         # In order to catch situations where the file
         # system is temporily read only, attempt to
         # remove the old test root if it exists, then
         # recreate it.
         if self.test_root:
@@ -685,20 +674,18 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time in seconds
             for any spawned adb process to complete before throwing
             an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :returns: string - content of stdout.
 
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         return ADBCommand.command_output(self, cmds,
                                          device_serial=self._device_serial,
                                          timeout=timeout)
 
     # Device Shell methods
 
@@ -713,18 +700,17 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.  This timeout is per adb call. The
             total time spent may exceed this value. If it is not
             specified, the value set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
         :returns: :class:`mozdevice.ADBProcess`
-        :raises: ADBRootError - raised if root is requested but the
-                 device is not rooted.
+        :raises: ADBRootError
 
         shell() provides a low level interface for executing commands
         on the device via adb shell.
 
         shell() executes on the host in such as fashion that stdout
         contains the stdout of the host abd process combined with the
         combined stdout/stderr of the shell command on the device
         while stderr is still the stderr of the adb process on the
@@ -821,20 +807,18 @@ class ADBDevice(ADBCommand):
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
         :returns: boolean
 
-        :raises: * ADBTimeoutError  - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
 
         """
         adb_process = None
         try:
             adb_process = self.shell(cmd, env=env, cwd=cwd,
                                      timeout=timeout, root=root)
             if adb_process.timedout:
                 raise ADBTimeoutError("%s" % adb_process)
@@ -856,22 +840,19 @@ class ADBDevice(ADBCommand):
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.  This timeout is per
             adb call. The total time spent may exceed this
             value. If it is not specified, the value set
             in the ADBDevice constructor is used.  :param root:
             optional boolean specifying if the command
             should be executed as root.
         :returns: string - content of stdout.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
+                 * ADBError
 
         """
         adb_process = None
         try:
             adb_process = self.shell(cmd, env=env, cwd=cwd,
                                      timeout=timeout, root=root)
             if adb_process.timedout:
                 raise ADBTimeoutError("%s" % adb_process)
@@ -902,20 +883,18 @@ class ADBDevice(ADBCommand):
         """Clears logcat via adb logcat -c.
 
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.  This timeout is per
             adb call. The total time spent may exceed this
             value. If it is not specified, the value set
             in the ADBDevice constructor is used.
-        :raises: * ADBTimeoutError - raised if adb logcat takes longer than
-                   timeout seconds.
-                 * ADBError - raised if adb logcat exits with a non-zero
-                   exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         self.command_output(["logcat", "-c"], timeout=timeout)
 
     def get_logcat(self,
                   filter_specs=[
                       "dalvikvm:I",
                       "ConnectivityService:S",
@@ -935,20 +914,18 @@ class ADBDevice(ADBCommand):
             excluded.
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :returns: list of lines logcat output.
-        :raises: * ADBTimeoutError - raised if adb logcat takes longer than
-                   timeout seconds.
-                 * ADBError - raised if adb logcat exits with a non-zero
-                   exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         cmds = ["logcat", "-v", format, "-d"] + filter_specs
         lines = self.command_output(cmds, timeout=timeout).split('\r')
 
         for regex in filter_out_regexps:
             lines = [line for line in lines if not re.search(regex, line)]
 
@@ -960,39 +937,35 @@ class ADBDevice(ADBCommand):
         :param prop: string containing the propery name.
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :returns: string value of property.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if adb shell getprop exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         output = self.shell_output('getprop %s' % prop, timeout=timeout)
         return output
 
     def get_state(self, timeout=None):
         """Returns the device's state via adb get-state.
 
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before throwing
             an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :returns: string value of adb get-state.
-        :raises: * ADBTimeoutError - raised if adb get-state takes longer
-                   than timeout seconds.
-                 * ADBError - raised if adb get-state exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         output = self.command_output(["get-state"], timeout=timeout).strip()
         return output
 
     # File management methods
 
     def chmod(self, path, recursive=False, mask="777", timeout=None, root=False):
@@ -1006,22 +979,19 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before throwing
             an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
-        :raises: * ADBTimeoutError - raised if any of the adb commands takes
-                   longer than timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
-                 * ADBError  - raised if any of the adb commands raises
-                   an uncaught ADBError.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
+                 * ADBError
 
         """
         path = posixpath.normpath(path.strip())
         self._logger.debug('chmod: path=%s, recursive=%s, mask=%s, root=%s' %
                            (path, recursive, mask, root))
         self.shell_output("chmod %s %s" % (mask, path),
                           timeout=timeout, root=root)
         if recursive and self.is_dir(path, timeout=timeout, root=root):
@@ -1056,20 +1026,18 @@ class ADBDevice(ADBCommand):
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should be
             executed as root.
         :returns: boolean - True if path exists.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
 
         """
         path = posixpath.normpath(path)
         return self.shell_bool('ls -a %s' % path, timeout=timeout, root=root)
 
     def is_dir(self, path, timeout=None, root=False):
         """Returns True if path is an existing directory on the device.
 
@@ -1079,20 +1047,18 @@ class ADBDevice(ADBCommand):
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
         :returns: boolean - True if path exists on the device and is a
             directory.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
 
         """
         path = posixpath.normpath(path)
         return self.shell_bool('ls -a %s/' % path, timeout=timeout, root=root)
 
     def is_file(self, path, timeout=None, root=False):
         """Returns True if path is an existing file on the device.
 
@@ -1102,20 +1068,18 @@ class ADBDevice(ADBCommand):
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
         :returns: boolean - True if path exists on the device and is a
             file.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
 
         """
         path = posixpath.normpath(path)
         return (
             self.exists(path, timeout=timeout, root=root) and
             not self.is_dir(path, timeout=timeout, root=root))
 
     def list_files(self, path, timeout=None, root=False):
@@ -1127,20 +1091,18 @@ class ADBDevice(ADBCommand):
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
         :returns: list of files/directories contained in the directory.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
 
         """
         path = posixpath.normpath(path.strip())
         data = []
         if self.is_dir(path, timeout=timeout, root=root):
             try:
                 data = self.shell_output("%s %s" % (self._ls, path),
                                          timeout=timeout,
@@ -1163,23 +1125,19 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
-        :raises: * ADBTimeoutError - raised if any adb command takes longer
-                   than timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
-                 * ADBError - raised if adb shell mkdir exits with a
-                   non-zero exit code or if the directory is not
-                   created.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
+                 * ADBError
 
         """
         path = posixpath.normpath(path)
         if parents:
             if self._mkdir_p is None or self._mkdir_p:
                 # Use shell_bool to catch the possible
                 # non-zero exitcode if -p is not supported.
                 if self.shell_bool('mkdir -p %s' % path, timeout=timeout):
@@ -1210,20 +1168,18 @@ class ADBDevice(ADBCommand):
         :param remote: string containing the name of the remote file or
             directory name.
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
-        :raises: * ADBTimeoutError - raised if the adb push takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the adb push exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         self.command_output(["push", os.path.realpath(local), remote],
                             timeout=timeout)
 
     def rm(self, path, recursive=False, force=False, timeout=None, root=False):
         """Delete files or directories on the device.
 
@@ -1236,24 +1192,19 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
-        :raises: * ADBTimeoutError - raised if any of the adb commands takes
-                   longer than timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
-                 * ADBError - raised if the adb shell rm command exits
-                   with a non-zero exit code or if the file is not
-                   removed, or if force was not specified and the
-                   file did not exist.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
+                 * ADBError
 
         """
         cmd = "rm"
         if recursive:
             cmd += " -r"
         try:
             self.shell_output("%s %s" % (cmd, path), timeout=timeout, root=root)
             if self.is_file(path, timeout=timeout, root=root):
@@ -1269,23 +1220,19 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
-                 * ADBError - raised if the adb shell rmdir command
-                   exits with a non-zero exit code or if the
-                   directory was not removed..
+        :raises: * ADBTimeoutError
+                 * ADBRootError
+                 * ADBError
 
         """
         self.shell_output("rmdir %s" % path, timeout=timeout, root=root)
         if self.is_dir(path, timeout=timeout, root=root):
             raise ADBError('rmdir("%s") failed to remove directory.' % path)
 
     # Process management methods
 
@@ -1296,21 +1243,18 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time
             in seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified,
             the value set in the ADBDevice constructor is used.
         :returns: list of (pid, name, user) tuples for running processes
             on the device.
-        :raises: * ADBTimeoutError - raised if the adb shell ps command
-                   takes longer than timeout seconds.
-                 * ADBError - raised if the adb shell ps command exits
-                   with a non-zero exit code or if the ps output
-                   is not in the expected format.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         adb_process = None
         try:
             adb_process = self.shell("ps", timeout=timeout)
             if adb_process.timedout:
                 raise ADBTimeoutError("%s" % adb_process)
             elif adb_process.exitcode:
@@ -1360,23 +1304,19 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
-        :raises: * ADBTimeoutError - raised if adb shell kill takes longer
-                   than timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
-                 * ADBError - raised if adb shell kill exits with a
-                   non-zero exit code or not all of the processes have
-                   been killed.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
+                 * ADBError
 
         """
         pid_list = [str(pid) for pid in pids]
         for attempt in range(attempts):
             args = ["kill"]
             if sig:
                 args.append("-%d" % sig)
             args.extend(pid_list)
@@ -1412,22 +1352,19 @@ class ADBDevice(ADBCommand):
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :param root: optional boolean specifying if the command should
             be executed as root.
 
-        :raises: * ADBTimeoutError - raised if any of the adb commands takes
-                   longer than timeout seconds.
-                 * ADBRootError - raised if root is requested but the
-                   device is not rooted.
-                 * ADBError - raised if any of the adb commands raises
-                   ADBError or if the process is not killed.
+        :raises: * ADBTimeoutError
+                 * ADBRootError
+                 * ADBError
 
         """
         procs = self.get_process_list(timeout=timeout)
         # limit the comparion to the first 75 characters due to a
         # limitation in processname length in android.
         pids = [proc[0] for proc in procs if proc[1] == appname[:75]]
         if not pids:
             return
@@ -1449,21 +1386,18 @@ class ADBDevice(ADBCommand):
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADBDevice constructor is used.
         :returns: boolean - True if process exists.
 
-        :raises: * ADBTimeoutError - raised if any of the adb commands takes
-                   longer than timeout seconds.
-                 * ADBError - raised if the adb shell ps command exits
-                   with a non-zero exit code or if the ps output is
-                   not in the expected format.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         if not isinstance(process_name, basestring):
             raise ADBError("Process name %s is not a string" % process_name)
 
         # Filter out extra spaces.
         parts = [x for x in process_name.split(' ') if x != '']
         process_name = ' '.join(parts)
--- a/testing/mozbase/mozdevice/mozdevice/adb_android.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb_android.py
@@ -1,39 +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/.
 
 import os
+import re
 import time
 
 from adb import ADBDevice, ADBError
 from distutils.version import StrictVersion
 
 
 class ADBAndroidMixin(object):
     """Mixin to extend ADB with Android-specific functionality"""
 
+    # Informational methods
+
+    def get_battery_percentage(self, timeout=None):
+        """Returns the battery charge as a percentage.
+
+        :param timeout: optional integer specifying the maximum time in
+            seconds for any spawned adb process to complete before
+            throwing an ADBTimeoutError.
+            This timeout is per adb call. The total time spent
+            may exceed this value. If it is not specified, the value
+            set in the ADBDevice constructor is used.
+        :returns: battery charge as a percentage.
+        :raises: * ADBTimeoutError
+                 * ADBError
+
+        """
+        level = None
+        scale = None
+        percentage = 0
+        cmd = "dumpsys battery"
+        re_parameter = re.compile(r'\s+(\w+):\s+(\d+)')
+        lines = self.shell_output(cmd, timeout=timeout).split('\r')
+        for line in lines:
+            match = re_parameter.match(line)
+            if match:
+                parameter = match.group(1)
+                value = match.group(2)
+                if parameter == 'level':
+                    level = float(value)
+                elif parameter == 'scale':
+                    scale = float(value)
+                if parameter is not None and scale is not None:
+                    percentage = 100.0*level/scale
+                    break
+        return percentage
+
     # System control methods
 
     def is_device_ready(self, timeout=None):
         """Checks if a device is ready for testing.
 
         This method uses the android only package manager to check for
         readiness.
 
         :param timeout: optional integer specifying the maximum time
             in seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the wait-for-device command fails.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         self.command_output(["wait-for-device"], timeout=timeout)
         pm_error_string = "Error: Could not access the Package Manager"
         pm_list_commands = ["packages", "permission-groups", "permissions",
                             "instrumentation", "features", "libraries"]
         ready_path = os.path.join(self.test_root, "ready")
         for attempt in range(self._device_ready_retry_attempts):
@@ -70,20 +106,18 @@ class ADBAndroidMixin(object):
         """Sets the device's power stayon value.
 
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         try:
             self.shell_output('svc power stayon true', timeout=timeout)
         except ADBError, e:
             # Executing this via adb shell errors, but not interactively.
             # Any other exitcode is a real error.
             if 'exitcode: 137' not in e.message:
@@ -97,20 +131,18 @@ class ADBAndroidMixin(object):
         if the device is ready after the reboot.
 
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         reboot() reboots the device, issues an adb wait-for-device in order to
         wait for the device to complete rebooting, then calls is_device_ready()
         to determine if the device has completed booting.
 
         """
         self.command_output(["reboot"], timeout=timeout)
         self.command_output(["wait-for-device"], timeout=timeout)
@@ -124,20 +156,18 @@ class ADBAndroidMixin(object):
         :param apk_path: string containing the apk file name to be
             installed.
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         data = self.command_output(["install", apk_path], timeout=timeout)
         if data.find('Success') == -1:
             raise ADBError("install failed for %s. Got: %s" %
                            (apk_path, data))
 
     def is_app_installed(self, app_name, timeout=None):
@@ -146,20 +176,18 @@ class ADBAndroidMixin(object):
         :param app_name: string containing the name of the app to be
             checked.
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         pm_error_string = 'Error: Could not access the Package Manager'
         data = self.shell_output("pm list package %s" % app_name, timeout=timeout)
         if pm_error_string in data:
             raise ADBError(pm_error_string)
         if app_name not in data:
             return False
@@ -180,20 +208,18 @@ class ADBAndroidMixin(object):
         :param fail_if_running: Raise an exception if instance of
             application is already running.
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         # If fail_if_running is True, we throw an exception here. Only one
         # instance of an application can be running at once on Android,
         # starting a new instance may not be what we want depending on what
         # we want to do
         if fail_if_running and self.process_exist(app_name, timeout=timeout):
             raise ADBError("Only one instance of an application may be running "
@@ -239,20 +265,18 @@ class ADBAndroidMixin(object):
         :param fail_if_running: Raise an exception if instance of
             application is already running
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         extras = {}
 
         if moz_env:
             # moz_env is expected to be a dictionary of environment variables:
             # Fennec itself will set them when launched
             for (env_count, (env_key, env_val)) in enumerate(moz_env.iteritems()):
@@ -278,20 +302,18 @@ class ADBAndroidMixin(object):
 
         :param app_name: Name of application (e.g. `com.android.chrome`)
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         version = self.shell_output("getprop ro.build.version.release",
                                     timeout=timeout, root=root)
         if StrictVersion(version) >= StrictVersion('3.0'):
             self.shell_output("am force-stop %s" % app_name,
                               timeout=timeout, root=root)
         else:
@@ -319,20 +341,18 @@ class ADBAndroidMixin(object):
             be rebooted after the app is uninstalled. No reboot occurs
             if the app is not installed.
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         if self.is_app_installed(app_name, timeout=timeout):
             data = self.command_output(["uninstall", app_name], timeout=timeout)
             if data.find('Success') == -1:
                 self._logger.debug('uninstall_app failed: %s' % data)
                 raise ADBError("uninstall failed for %s. Got: %s" % (app_name, data))
             if reboot:
@@ -344,20 +364,18 @@ class ADBAndroidMixin(object):
         :param apk_path: string containing the apk file name to be
             updated.
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.
             This timeout is per adb call. The total time spent
             may exceed this value. If it is not specified, the value
             set in the ADB constructor is used.
-        :raises: * ADBTimeoutError - raised if the command takes longer than
-                   timeout seconds.
-                 * ADBError - raised if the command exits with a
-                   non-zero exit code.
+        :raises: * ADBTimeoutError
+                 * ADBError
 
         """
         output = self.command_output(["install", "-r", apk_path],
                                      timeout=timeout)
         self.reboot(timeout=timeout)
         return output
 
 
--- a/testing/mozbase/mozlog/mozlog/structured/structuredlog.py
+++ b/testing/mozbase/mozlog/mozlog/structured/structuredlog.py
@@ -148,60 +148,71 @@ class StructuredLogger(object):
 
     def test_start(self, test):
         """Log a test_start message
 
         :param test: Identifier of the test that will run.
         """
         self._log_data("test_start", {"test": test})
 
-    def test_status(self, test, subtest, status, expected="PASS", message=None):
+    def test_status(self, test, subtest, status, expected="PASS", message=None,
+                    stack=None, extra=None):
         """
         Log a test_status message indicating a subtest result. Tests that
         do not have subtests are not expected to produce test_status messages.
 
         :param test: Identifier of the test that produced the result.
         :param subtest: Name of the subtest.
         :param status: Status string indicating the subtest result
         :param expected: Status string indicating the expected subtest result.
         :param message: String containing a message associated with the result.
+        :param stack: a stack trace encountered during test execution.
+        :param extra: suite-specific data associated with the test result.
         """
         if status.upper() not in ["PASS", "FAIL", "TIMEOUT", "NOTRUN", "ASSERT"]:
             raise ValueError("Unrecognised status %s" % status)
         data = {"test": test,
                 "subtest": subtest,
                 "status": status.upper()}
         if message is not None:
             data["message"] = message
         if expected != data["status"]:
             data["expected"] = expected
+        if stack is not None:
+            data["stack"] = stack
+        if extra is not None:
+            data["extra"] = extra
         self._log_data("test_status", data)
 
-    def test_end(self, test, status, expected="OK", message=None, extra=None):
+    def test_end(self, test, status, expected="OK", message=None, stack=None,
+                 extra=None):
         """
         Log a test_end message indicating that a test completed. For tests
         with subtests this indicates whether the overall test completed without
         errors. For tests without subtests this indicates the test result
         directly.
 
         :param test: Identifier of the test that produced the result.
         :param status: Status string indicating the test result
         :param expected: Status string indicating the expected test result.
         :param message: String containing a message associated with the result.
+        :param stack: a stack trace encountered during test execution.
         :param extra: suite-specific data associated with the test result.
         """
         if status.upper() not in ["PASS", "FAIL", "OK", "ERROR", "TIMEOUT",
                                   "CRASH", "ASSERT", "SKIP"]:
             raise ValueError("Unrecognised status %s" % status)
         data = {"test": test,
                 "status": status.upper()}
         if message is not None:
             data["message"] = message
         if expected != data["status"] and status != "SKIP":
             data["expected"] = expected
+        if stack is not None:
+            data["stack"] = stack
         if extra is not None:
             data["extra"] = extra
         self._log_data("test_end", data)
 
     def process_output(self, process, data, command=None):
         """Log output from a managed process.
 
         :param process: A unique identifier for the process producing the output
--- a/testing/mozbase/mozlog/tests/test_structured.py
+++ b/testing/mozbase/mozlog/tests/test_structured.py
@@ -81,16 +81,36 @@ class TestStructuredLog(BaseStructuredTe
                                 "subtest": "subtest name",
                                 "status": "FAIL",
                                 "expected": "PASS",
                                 "test":"test1"})
 
     def test_status_2(self):
         self.assertRaises(ValueError, self.logger.test_status, "test1", "subtest name", "XXXUNKNOWNXXX")
 
+    def test_status_extra(self):
+        self.logger.test_status("test1", "subtest name", "FAIL", expected="PASS", extra={"data": 42})
+        self.assert_log_equals({"action": "test_status",
+                                "subtest": "subtest name",
+                                "status": "FAIL",
+                                "expected": "PASS",
+                                "test": "test1",
+                                "extra": {"data":42}
+                            })
+
+    def test_status_stack(self):
+        self.logger.test_status("test1", "subtest name", "FAIL", expected="PASS", stack="many\nlines\nof\nstack")
+        self.assert_log_equals({"action": "test_status",
+                                "subtest": "subtest name",
+                                "status": "FAIL",
+                                "expected": "PASS",
+                                "test": "test1",
+                                "stack": "many\nlines\nof\nstack"
+                            })
+
     def test_end(self):
         self.logger.test_end("test1", "fail", message="Test message")
         self.assert_log_equals({"action": "test_end",
                                 "status": "FAIL",
                                 "expected": "OK",
                                 "message": "Test message",
                                 "test":"test1"})
 
@@ -99,16 +119,24 @@ class TestStructuredLog(BaseStructuredTe
         self.assert_log_equals({"action": "test_end",
                                 "status": "PASS",
                                 "extra": {"data": 123},
                                 "test":"test1"})
 
     def test_end_2(self):
         self.assertRaises(ValueError, self.logger.test_end, "test1", "XXXUNKNOWNXXX")
 
+    def test_end_stack(self):
+        self.logger.test_end("test1", "PASS", expected="PASS", stack="many\nlines\nof\nstack")
+        self.assert_log_equals({"action": "test_end",
+                                "status": "PASS",
+                                "test": "test1",
+                                "stack": "many\nlines\nof\nstack"
+                            })
+
     def test_process(self):
         self.logger.process_output(1234, "test output")
         self.assert_log_equals({"action": "process_output",
                                 "process": 1234,
                                 "data": "test output"})
 
     def test_log(self):
         for level in ["critical", "error", "warning", "info", "debug"]:
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -205,8 +205,11 @@ user_pref("identity.fxaccounts.remote.si
 user_pref("identity.fxaccounts.settings.uri", "https://%(server)s/fxa-settings");
 
 // Enable logging of APZ test data (see bug 961289).
 user_pref('apz.test.logging_enabled', true);
 
 // Make sure Translation won't hit the network.
 user_pref("browser.translation.bing.authURL", "http://%(server)s/browser/browser/components/translation/test/bing.sjs");
 user_pref("browser.translation.bing.translateArrayURL", "http://%(server)s/browser/browser/components/translation/test/bing.sjs");
+
+// Enable debug logging in the mozApps implementation.
+user_pref("dom.mozApps.debug", true);
--- a/testing/xpcshell/Makefile.in
+++ b/testing/xpcshell/Makefile.in
@@ -23,43 +23,31 @@ TEST_HARNESS_FILES := \
   $(NULL)
 
 # Extra files needed from $(topsrcdir)/build
 EXTRA_BUILD_FILES := \
   automationutils.py \
   manifestparser.py \
   $(NULL)
 
-MOZDEVICE_FILES := \
-  devicemanager.py \
-  devicemanagerADB.py \
-  devicemanagerSUT.py \
-  Zeroconf.py \
-  $(NULL)
-
 # Components / typelibs that don't get packaged with
 # the build, but that we need for the test harness.
 TEST_HARNESS_COMPONENTS := \
   httpd.js \
   httpd.manifest \
   $(NULL)
 
-MOZINFO_FILES := \
-  mozinfo.py
-
 # Rules for staging the necessary harness bits for a test package
 PKG_STAGE = $(DIST)/test-stage
 
 libs::
 	$(INSTALL) $(srcdir)/xpcshell_b2g.ini $(DEPTH)/_tests/xpcshell
 	$(INSTALL) $(srcdir)/xpcshell_android.ini $(DEPTH)/_tests/xpcshell
 	cp $(DEPTH)/_tests/xpcshell/xpcshell.ini $(DEPTH)/_tests/xpcshell/all-test-dirs.list
 
 stage-package:
 	$(NSINSTALL) -D $(PKG_STAGE)/xpcshell/tests
-	@(cd $(topsrcdir)/testing/mozbase/mozinfo/mozinfo && tar $(TAR_CREATE_FLAGS) - $(MOZINFO_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -)
 	@(cd $(srcdir) && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -)
 	@(cd $(topsrcdir)/build && tar $(TAR_CREATE_FLAGS) - $(EXTRA_BUILD_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -)
 	@cp $(DEPTH)/mozinfo.json $(PKG_STAGE)/xpcshell
 	@cp $(DEPTH)/build/automation.py $(PKG_STAGE)/xpcshell
-	@(cd $(topsrcdir)/testing/mozbase/mozdevice/mozdevice && tar $(TAR_CREATE_FLAGS) - $(MOZDEVICE_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -)
 	(cd $(DEPTH)/_tests/xpcshell/ && tar $(TAR_CREATE_FLAGS) - *) | (cd $(PKG_STAGE)/xpcshell/tests && tar -xf -)
 	@(cd $(DIST)/bin/components && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_COMPONENTS)) | (cd $(PKG_STAGE)/bin/components && tar -xf -)
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -718,16 +718,19 @@ function do_check_neq(left, right, stack
 function todo_check_neq(left, right, stack) {
   if (!stack)
       stack = Components.stack.caller;
 
   _do_check_neq(left, right, stack, true);
 }
 
 function do_report_result(passed, text, stack, todo) {
+  while (stack.filename.contains("head.js") && stack.caller) {
+    stack = stack.caller;
+  }
   if (passed) {
     if (todo) {
       do_throw_todo(text, stack);
     } else {
       ++_passedChecks;
       _log("test_pass",
            {source_file: stack.filename,
             test_name: stack.name,
--- a/testing/xpcshell/selftest.py
+++ b/testing/xpcshell/selftest.py
@@ -532,16 +532,29 @@ tail =
         self.writeFile("test_add_test_simple.js", ADD_TEST_SIMPLE)
         self.writeManifest(["test_add_test_simple.js"])
 
         self.assertTestResult(True)
         self.assertEquals(1, self.x.testCount)
         self.assertEquals(1, self.x.passCount)
         self.assertEquals(0, self.x.failCount)
 
+    def testLogCorrectFileName(self):
+        """
+        Make sure a meaningful filename and line number is logged
+        by a passing test.
+        """
+        self.writeFile("test_add_test_simple.js", ADD_TEST_SIMPLE)
+        self.writeManifest(["test_add_test_simple.js"])
+
+        self.assertTestResult(True, verbose=True)
+        self.assertInLog("true == true")
+        self.assertNotInLog("[do_check_true :")
+        self.assertInLog("[test_simple : 5]")
+
     def testAddTestFailing(self):
         """
         Ensure add_test() with a failing test is reported.
         """
         self.writeFile("test_add_test_failing.js", ADD_TEST_FAILING)
         self.writeManifest(["test_add_test_failing.js"])
 
         self.assertTestResult(False)
--- a/toolkit/modules/AsyncShutdown.jsm
+++ b/toolkit/modules/AsyncShutdown.jsm
@@ -96,18 +96,18 @@ function log(msg, prefix = "", error = n
     if (typeof error == "object" && "stack" in error) {
       dump(prefix + error.stack + "\n");
     }
   }
 }
 function warn(msg, error = null) {
   return log(msg, "WARNING: ", error);
 }
-function err(msg, error = null) {
-  return log(msg, "ERROR: ", error);
+function fatalerr(msg, error = null) {
+  return log(msg, "FATAL ERROR: ", error);
 }
 
 // Utility function designed to get the current state of execution
 // of a blocker.
 // We are a little paranoid here to ensure that in case of evaluation
 // error we do not block the AsyncShutdown.
 function safeGetState(fetchState) {
   if (!fetchState) {
@@ -716,17 +716,17 @@ Barrier.prototype = Object.freeze({
           // within the first 200 characters of the message. This
           // helps automatically sort oranges.
           let msg = "AsyncShutdown timeout in " + topic +
             " Conditions: " + JSON.stringify(state) +
             " At least one completion condition failed to complete" +
 	    " within a reasonable amount of time. Causing a crash to" +
 	    " ensure that we do not leave the user with an unresponsive" +
 	    " process draining resources.";
-	  err(msg);
+	  fatalerr(msg);
 	  if (gCrashReporter && gCrashReporter.enabled) {
             let data = {
               phase: topic,
               conditions: state
 	    };
             gCrashReporter.annotateCrashReport("AsyncShutdownTimeout",
               JSON.stringify(data));
 	  } else {
--- a/toolkit/mozapps/update/common/updatehelper.cpp
+++ b/toolkit/mozapps/update/common/updatehelper.cpp
@@ -5,16 +5,17 @@
 #ifdef MOZ_METRO
 // Needed for COM calls to launch Metro applications
 #undef WINVER
 #undef _WIN32_WINNT
 #define WINVER 0x602
 #define _WIN32_WINNT 0x602
 #include <objbase.h>
 #include <shobjidl.h>
+#pragma comment(lib, "ole32.lib")
 #endif
 
 #include <windows.h>
 
 // Needed for CreateToolhelp32Snapshot
 #include <tlhelp32.h>
 #ifndef ONLY_SERVICE_LAUNCHING
 
--- a/toolkit/webapps/WebappOSUtils.jsm
+++ b/toolkit/webapps/WebappOSUtils.jsm
@@ -337,17 +337,17 @@ this.WebappOSUtils = {
 
     let mwaUtils = Cc["@mozilla.org/widget/mac-web-app-utils;1"].
                    createInstance(Ci.nsIMacWebAppUtils);
 
     mwaUtils.trashApp(path, (aResult) => {
       if (aResult == Cr.NS_OK) {
         deferred.resolve(true);
       } else {
-        deferred.resolve("Error moving the app to the Trash: " + aResult);
+        deferred.reject("Error moving the app to the Trash: " + aResult);
       }
     });
 
     return deferred.promise;
 #elifdef XP_UNIX
     let exeFile = this.getLaunchTarget(aApp);
     if (!exeFile) {
       return Promise.reject("App executable file not found");
--- a/toolkit/webapps/tests/head.js
+++ b/toolkit/webapps/tests/head.js
@@ -262,17 +262,18 @@ function TestAppInfo(aApp, aIsPackaged) 
           yield OS.File.removeDir(this.installPath, { ignoreAbsent: true });
 
           yield OS.File.remove(desktopShortcut, { ignoreAbsent: true });
           yield OS.File.remove(startMenuShortcut, { ignoreAbsent: true });
 
           removed = true;
         } catch (ex if ex instanceof OS.File.Error &&
                  (ex.winLastError == OS.Constants.Win.ERROR_ACCESS_DENIED ||
-                  ex.winLastError == OS.Constants.Win.ERROR_SHARING_VIOLATION)) {
+                  ex.winLastError == OS.Constants.Win.ERROR_SHARING_VIOLATION ||
+                  ex.winLastError == OS.Constants.Win.ERROR_DIR_NOT_EMPTY)) {
           // Wait 100 ms before attempting to remove again.
           yield wait(100);
         }
       } while (!removed);
     });
   } else if (MAC) {
     this.installPath = OS.Path.join(OS.Constants.Path.homeDir,
                                     "Applications",
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -429,19 +429,17 @@ enum nsEventStructType
 #define NS_FULL_SCREEN_START         5100
 #define NS_FULLSCREENCHANGE          (NS_FULL_SCREEN_START)
 #define NS_FULLSCREENERROR           (NS_FULL_SCREEN_START + 1)
 
 #define NS_TOUCH_EVENT_START         5200
 #define NS_TOUCH_START               (NS_TOUCH_EVENT_START)
 #define NS_TOUCH_MOVE                (NS_TOUCH_EVENT_START+1)
 #define NS_TOUCH_END                 (NS_TOUCH_EVENT_START+2)
-#define NS_TOUCH_ENTER               (NS_TOUCH_EVENT_START+3)
-#define NS_TOUCH_LEAVE               (NS_TOUCH_EVENT_START+4)
-#define NS_TOUCH_CANCEL              (NS_TOUCH_EVENT_START+5)
+#define NS_TOUCH_CANCEL              (NS_TOUCH_EVENT_START+3)
 
 // Pointerlock DOM API
 #define NS_POINTERLOCK_START         5300
 #define NS_POINTERLOCKCHANGE         (NS_POINTERLOCK_START)
 #define NS_POINTERLOCKERROR          (NS_POINTERLOCK_START + 1)
 
 #define NS_WHEEL_EVENT_START         5400
 #define NS_WHEEL_WHEEL               (NS_WHEEL_EVENT_START)
--- a/widget/InputData.h
+++ b/widget/InputData.h
@@ -160,18 +160,16 @@ public:
 class MultiTouchInput : public InputData
 {
 public:
   enum MultiTouchType
   {
     MULTITOUCH_START,
     MULTITOUCH_MOVE,
     MULTITOUCH_END,
-    MULTITOUCH_ENTER,
-    MULTITOUCH_LEAVE,
     MULTITOUCH_CANCEL
   };
 
   MultiTouchInput(MultiTouchType aType, uint32_t aTime, TimeStamp aTimeStamp,
                   Modifiers aModifiers)
     : InputData(MULTITOUCH_INPUT, aTime, aTimeStamp, aModifiers),
       mType(aType)
   {
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -42,25 +42,28 @@ namespace dom {
 
 class WidgetPointerHelper
 {
 public:
   bool convertToPointer;
   uint32_t pointerId;
   uint32_t tiltX;
   uint32_t tiltY;
+  bool retargetedByPointerCapture;
 
-  WidgetPointerHelper() : convertToPointer(true), pointerId(0), tiltX(0), tiltY(0) {}
+  WidgetPointerHelper() : convertToPointer(true), pointerId(0), tiltX(0), tiltY(0),
+                          retargetedByPointerCapture(false) {}
 
   void AssignPointerHelperData(const WidgetPointerHelper& aEvent)
   {
     convertToPointer = aEvent.convertToPointer;
     pointe