Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 22 Dec 2014 17:55:32 -0500
changeset 220949 f6d10f05f6e9f0631267d5c426e523fb525dd451
parent 220926 d5167dc0ded36155527b67e4a92fb77a84c3691a (current diff)
parent 220948 961dff3f8c30cfea7b658cc8c81862866bde4028 (diff)
child 220951 8991815dd086e90539e00f53ceaebda31fcdfb0a
child 220953 998ef5e8fde42a66d5a21d6374e9388638053699
child 220972 b85f2f139c4d86f7b0f5eb366c646299246353cd
child 221005 c12fab47017b88bf16e4841da432cae8f06ee14d
push id28004
push userryanvm@gmail.com
push dateMon, 22 Dec 2014 22:55:36 +0000
treeherdermozilla-central@f6d10f05f6e9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
dom/xul/nsIXULContextMenuBuilder.idl
dom/xul/nsXULContextMenuBuilder.cpp
dom/xul/nsXULContextMenuBuilder.h
js/xpconnect/tests/idl/Makefile.in
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,14 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1105308 - Cleanup BluetoothUtils.{cpp,h}
-
-This patch set moves some files around and requires a rebuild
-of the build system's dependency information.
-
-Merge day clobber
+Bug 1066383 - Clobber needed due to build system not reliably picking up an IDL removal.
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -396,16 +396,18 @@
 @BINPATH@/components/nsDownloadManagerUI.manifest
 @BINPATH@/components/nsDownloadManagerUI.js
 @BINPATH@/components/Downloads.manifest
 @BINPATH@/components/DownloadLegacy.js
 @BINPATH@/components/nsSidebar.manifest
 @BINPATH@/components/nsSidebar.js
 @BINPATH@/components/nsAsyncShutdown.manifest
 @BINPATH@/components/nsAsyncShutdown.js
+@BINPATH@/components/htmlMenuBuilder.js
+@BINPATH@/components/htmlMenuBuilder.manifest
 
 ; WiFi, NetworkManager, NetworkStats
 #ifdef MOZ_WIDGET_GONK
 @BINPATH@/components/DOMWifiManager.js
 @BINPATH@/components/DOMWifiManager.manifest
 @BINPATH@/components/DOMWifiP2pManager.js
 @BINPATH@/components/DOMWifiP2pManager.manifest
 @BINPATH@/components/NetworkInterfaceListService.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -254,20 +254,20 @@ XPCOMUtils.defineLazyGetter(this, "Win7F
 });
 
 #ifdef MOZ_CRASHREPORTER
 XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter",
                                    "@mozilla.org/xre/app-info;1",
                                    "nsICrashReporter");
 #endif
 
-XPCOMUtils.defineLazyGetter(this, "PageMenu", function() {
+XPCOMUtils.defineLazyGetter(this, "PageMenuParent", function() {
   let tmp = {};
   Cu.import("resource://gre/modules/PageMenu.jsm", tmp);
-  return new tmp.PageMenu();
+  return new tmp.PageMenuParent();
 });
 
 /**
 * We can avoid adding multiple load event listeners and save some time by adding
 * one listener that calls all real handlers.
 */
 function pageShowEventHandlers(persisted) {
   XULBrowserWindow.asyncUpdateUI();
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -38,16 +38,21 @@ XPCOMUtils.defineLazyGetter(this, "Simpl
       return new RokuApp(aService);
     },
     mirror: true,
     types: ["video/mp4"],
     extensions: ["mp4"]
   });
   return ssdp;
 });
+XPCOMUtils.defineLazyGetter(this, "PageMenuChild", function() {
+  let tmp = {};
+  Cu.import("resource://gre/modules/PageMenu.jsm", tmp);
+  return new tmp.PageMenuChild();
+});
 
 // TabChildGlobal
 var global = this;
 
 // Load the form validation popup handler
 var formSubmitObserver = new FormSubmitObserver(content, this);
 
 addMessageListener("Browser:HideSessionRestoreButton", function (message) {
@@ -97,16 +102,20 @@ addMessageListener("SecondScreen:tab-mir
   if (app) {
     let width = content.innerWidth;
     let height = content.innerHeight;
     let viewport = {cssWidth: width, cssHeight: height, width: width, height: height};
     app.mirror(function() {}, content, viewport, function() {}, content);
   }
 });
 
+addMessageListener("ContextMenu:DoCustomCommand", function(message) {
+  PageMenuChild.executeMenu(message.data);
+});
+
 addEventListener("DOMFormHasPassword", function(event) {
   InsecurePasswordUtils.checkForInsecurePasswords(event.target);
   LoginManagerContent.onFormPassword(event);
 });
 addEventListener("DOMAutoComplete", function(event) {
   LoginManagerContent.onUsernameInput(event);
 });
 addEventListener("blur", function(event) {
@@ -143,17 +152,18 @@ let handleContentContextMenu = function 
     let editFlags = SpellCheckHelper.isEditable(event.target, content);
     let spellInfo;
     if (editFlags &
         (SpellCheckHelper.EDITABLE | SpellCheckHelper.CONTENTEDITABLE)) {
       spellInfo =
         InlineSpellCheckerContent.initContextMenu(event, editFlags, this);
     }
 
-    sendSyncMessage("contextmenu", { editFlags, spellInfo, addonInfo }, { event, popupNode: event.target });
+    let customMenuItems = PageMenuChild.build(event.target);
+    sendSyncMessage("contextmenu", { editFlags, spellInfo, customMenuItems, addonInfo }, { event, popupNode: event.target });
   }
   else {
     // Break out to the parent window and pass the add-on info along
     let browser = docShell.chromeEventHandler;
     let mainWin = browser.ownerDocument.defaultView;
     mainWin.gContextMenuContentData = {
       isRemote: false,
       event: event,
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -19,20 +19,25 @@ nsContextMenu.prototype = {
   initMenu: function CM_initMenu(aXulMenu, aIsShift) {
     // Get contextual info.
     this.setTarget(document.popupNode, document.popupRangeParent,
                    document.popupRangeOffset);
     if (!this.shouldDisplay)
       return;
 
     this.hasPageMenu = false;
-    // FIXME (bug 1047751) - The page menu is disabled in e10s.
-    if (!aIsShift && !this.isRemote) {
-      this.hasPageMenu = PageMenu.maybeBuildAndAttachMenu(this.target,
-                                                          aXulMenu);
+    if (!aIsShift) {
+      if (this.isRemote) {
+        this.hasPageMenu =
+          PageMenuParent.addToPopup(gContextMenuContentData.customMenuItems,
+                                    this.browser, aXulMenu);
+      }
+      else {
+        this.hasPageMenu = PageMenuParent.buildAndAddToPopup(this.target, aXulMenu);
+      }
     }
 
     this.isFrameImage = document.getElementById("isFrameImage");
     this.ellipsis = "\u2026";
     try {
       this.ellipsis = gPrefService.getComplexValue("intl.ellipsis",
                                                    Ci.nsIPrefLocalizedString).data;
     } catch (e) { }
@@ -1761,17 +1766,17 @@ nsContextMenu.prototype = {
       }
       // Target should be in the menu (this catches using shortcuts for items
       // not in the menu while the menu is up)
       if (!aXulMenu.contains(e.target)) {
         return;
       }
 
       // Check if this is a page menu item:
-      if (e.target.hasAttribute(PageMenu.GENERATEDITEMID_ATTR)) {
+      if (e.target.hasAttribute(PageMenuParent.GENERATEDITEMID_ATTR)) {
         this._telemetryClickID = "custom-page-item";
       } else {
         this._telemetryClickID = (e.target.id || "unknown").replace(/^context-/i, "");
       }
     };
     aXulMenu.ownerDocument.addEventListener("command", activationHandler, true);
     aXulMenu.addEventListener("popuphiding", this._onPopupHiding, true);
   },
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3170,16 +3170,17 @@
               if (spellInfo)
                 spellInfo.target = aMessage.target.messageManager;
               gContextMenuContentData = { isRemote: true,
                                           event: aMessage.objects.event,
                                           popupNode: aMessage.objects.popupNode,
                                           browser: browser,
                                           editFlags: aMessage.data.editFlags,
                                           spellInfo: spellInfo,
+                                          customMenuItems: aMessage.data.customMenuItems,
                                           addonInfo: aMessage.data.addonInfo };
               let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
               let event = gContextMenuContentData.event;
               let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY);
               popup.openPopupAtScreen(pos.x, pos.y, true);
               break;
             }
             case "DOMWebNotificationClicked": {
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -67,16 +67,17 @@ support-files =
   parsingTestHelpers.jsm
   pinning_headers.sjs
   pinning_reports.sjs
   popup_blocker.html
   print_postdata.sjs
   redirect_bug623155.sjs
   searchSuggestionEngine.sjs
   searchSuggestionEngine.xml
+  subtst_contextmenu.html
   test-mixedcontent-securityerrors.html
   test_bug435035.html
   test_bug462673.html
   test_bug628179.html
   test_bug839103.html
   test_bug959531.html
   test_wyciwyg_copying.html
   title_test.svg
@@ -481,9 +482,10 @@ skip-if = e10s
 skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_bug1045809.js]
 [browser_e10s_switchbrowser.js]
 [browser_blockHPKP.js]
 skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_mcb_redirect.js]
 skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account
 [browser_windowactivation.js]
+[browser_contextmenu_childprocess.js]
 [browser_bug963945.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_contextmenu_childprocess.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const gBaseURL = "https://example.com/browser/browser/base/content/test/general/";
+
+add_task(function *() {
+  let tab = gBrowser.addTab();
+  let browser = gBrowser.getBrowserForTab(tab);
+
+  gBrowser.selectedTab = tab;
+  yield promiseTabLoadEvent(tab, gBaseURL + "subtst_contextmenu.html");
+
+  let popupShownPromise = promiseWaitForEvent(window, "popupshown", true);
+
+  // Get the point of the element with the page menu (test-pagemenu) and
+  // synthesize a right mouse click there.
+  let eventDetails = { type : "contextmenu", button : 2 };
+  let rect = browser.contentWindow.document.getElementById("test-pagemenu").getBoundingClientRect();
+  EventUtils.synthesizeMouse(browser, rect.x + rect.width / 2, rect.y + rect.height / 2, eventDetails, window);
+
+  let event = yield popupShownPromise;
+
+  let contextMenu = document.getElementById("contentAreaContextMenu");
+  checkMenu(contextMenu);
+  contextMenu.hidePopup();
+  gBrowser.removeCurrentTab();
+});
+
+function checkItems(menuitem, arr)
+{
+  for (let i = 0; i < arr.length; i += 2) {
+    let str = arr[i];
+    let details = arr[i + 1];
+    if (str == "---") {
+      is(menuitem.localName, "menuseparator", "menuseparator");
+    }
+    else if ("children" in details) {
+      is(menuitem.localName, "menu", "submenu");
+      is(menuitem.getAttribute("label"), str, str + " label");
+      checkItems(menuitem.firstChild.firstChild, details.children);
+    }
+    else {
+      is(menuitem.localName, "menuitem", str + " menuitem");
+
+      is(menuitem.getAttribute("label"), str, str + " label");
+      is(menuitem.getAttribute("type"), details.type, str + " type");
+      is(menuitem.getAttribute("image"), details.icon ? gBaseURL + details.icon : "", str + " icon");
+
+      if (details.checked)
+        is(menuitem.getAttribute("checked"), "true", str + " checked");
+      else
+        ok(!menuitem.hasAttribute("checked"), str + " checked");
+
+      if (details.disabled)
+        is(menuitem.getAttribute("disabled"), "true", str + " disabled");
+      else
+        ok(!menuitem.hasAttribute("disabled"), str + " disabled");
+    }
+
+    menuitem = menuitem.nextSibling;
+  }
+}
+
+function checkMenu(contextMenu)
+{
+  let items = [ "Plain item",          {type: "", icon: "", checked: false, disabled: false},
+                "Disabled item",       {type: "", icon: "", checked: false, disabled: true},
+                "Item w/ textContent", {type: "", icon: "", checked: false, disabled: false},
+                "---",                  null,
+                "Checkbox",            {type: "checkbox", icon: "", checked: true, disabled: false},
+                "---",                  null,
+                "Radio1",              {type: "checkbox", icon: "", checked: true, disabled: false},
+                "Radio2",              {type: "checkbox", icon: "", checked: false, disabled: false},
+                "Radio3",              {type: "checkbox", icon: "", checked: false, disabled: false},
+                "---",                  null,
+                "Item w/ icon",        {type: "", icon: "favicon.ico", checked: false, disabled: false},
+                "Item w/ bad icon",    {type: "", icon: "", checked: false, disabled: false},
+                "---",                  null,
+                "Submenu",  { children:
+                  ["Radio1",             {type: "checkbox", icon: "", checked: false, disabled: false},
+                   "Radio2",             {type: "checkbox", icon: "", checked: true, disabled: false},
+                   "Radio3",             {type: "checkbox", icon: "", checked: false, disabled: false},
+                   "---",                 null,
+                   "Checkbox",           {type: "checkbox", icon: "", checked: false, disabled: false}] }
+               ];
+  checkItems(contextMenu.childNodes[2], items);
+}
--- a/browser/base/content/test/general/test_contextmenu.html
+++ b/browser/base/content/test/general/test_contextmenu.html
@@ -490,17 +490,17 @@ function runTest(testNum) {
                           "---",                  null,
                           "context-viewbgimage",  false,
                           "context-selectall",    true,
                           "---",                  null,
                           "context-viewsource",   true,
                           "context-viewinfo",     true
                          ].concat(inspectItems));
 
-        invokeItemAction("0");
+        invokeItemAction("1");
         closeContextMenu();
 
         // run mozRequestFullScreen on the element we're testing
         var full_screen_element = subwindow.document.getElementById("test-dom-full-screen");
         var openDomFullScreen = function() {
             subwindow.removeEventListener("mozfullscreenchange", openDomFullScreen, false);
             openContextMenuFor(dom_full_screen, true); // Invoke context menu for next test.
         }
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -537,16 +537,18 @@
 @RESPATH@/components/Webapps.manifest
 @RESPATH@/components/AppsService.js
 @RESPATH@/components/AppsService.manifest
 @RESPATH@/components/nsDOMIdentity.js
 @RESPATH@/components/nsIDService.js
 @RESPATH@/components/Identity.manifest
 @RESPATH@/components/recording-cmdline.js
 @RESPATH@/components/recording-cmdline.manifest
+@RESPATH@/components/htmlMenuBuilder.js
+@RESPATH@/components/htmlMenuBuilder.manifest
 
 @RESPATH@/components/PermissionSettings.js
 @RESPATH@/components/PermissionSettings.manifest
 @RESPATH@/components/ContactManager.js
 @RESPATH@/components/ContactManager.manifest
 @RESPATH@/components/PhoneNumberService.js
 @RESPATH@/components/PhoneNumberService.manifest
 @RESPATH@/components/NotificationStorage.js
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -72,17 +72,17 @@ ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDI
 SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/metrolist.txt))
 else
 SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/list.txt)) ddg
 endif
 SEARCHPLUGINS_PATH := $(FINAL_TARGET)/searchplugins
 # metro build call a searchplugins target for search engine plugins
 .PHONY: searchplugins
 SEARCHPLUGINS_TARGET := libs searchplugins
-SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_NAMES)),$(or $(wildcard $(call MERGE_FILE,searchplugins/$(plugin))),$(info Missing searchplugin: $(plugin))))
+SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_NAMES)),$(or $(wildcard $(call EN_US_OR_L10N_FILE,searchplugins/$(plugin))),$(info Missing searchplugin: $(plugin))))
 # Some locale-specific search plugins may have preprocessor directives, but the
 # default en-US ones do not.
 SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings
 PP_TARGETS += SEARCHPLUGINS
 
 # Required for l10n.mk - defines a list of app sub dirs that should
 # be included in langpack xpis.
 ifdef MOZ_METRO
--- a/config/config.mk
+++ b/config/config.mk
@@ -609,16 +609,23 @@ MERGE_FILE = $(firstword \
   $(wildcard $(LOCALE_MERGEDIR)/$(subst /locales,,$(relativesrcdir))/$(1)) \
   $(wildcard $(LOCALE_SRCDIR)/$(1)) \
   $(srcdir)/en-US/$(1) )
 else
 MERGE_FILE = $(LOCALE_SRCDIR)/$(1)
 endif
 MERGE_FILES = $(foreach f,$(1),$(call MERGE_FILE,$(f)))
 
+# These marcros are similar to MERGE_FILE, but no merging, and en-US first.
+# They're used for searchplugins, for example.
+EN_US_OR_L10N_FILE = $(firstword \
+  $(wildcard $(srcdir)/en-US/$(1)) \
+  $(LOCALE_SRCDIR)/$(1) )
+EN_US_OR_L10N_FILES = $(foreach f,$(1),$(call EN_US_OR_L10N_FILE,$(f)))
+
 ifneq (WINNT,$(OS_ARCH))
 RUN_TEST_PROGRAM = $(LIBXUL_DIST)/bin/run-mozilla.sh
 endif # ! WINNT
 
 #
 # Java macros
 #
 
--- a/config/makefiles/xpidl/Makefile.in
+++ b/config/makefiles/xpidl/Makefile.in
@@ -17,54 +17,45 @@ include $(topsrcdir)/config/rules.mk
 #
 # XPIDL files are logically grouped together by modules. The typelib
 # information for all XPIDLs in the same module is linked together into
 # an .xpt file having the name of the module.
 #
 # As an optimization to reduce overall CPU usage, we process all .idl
 # belonging to a module with a single command invocation. This prevents
 # redundant parsing of .idl files and significantly reduces CPU cycles.
-#
-# Future improvement: Headers are currently written to a local directory then
-# installed in the distribution directory. It is preferable to write headers
-# directly into the distribution directory. However, PGO builds remove the dist
-# directory via rm -rf (with no regards to manifests). Since the cost of
-# processing XPIDL files is not trivial, it is preferrable to cache the headers
-# and reinstall them rather than regenerate them. Ideally the dist pruning is
-# performed with manifests. At that time we can write headers directly to the
-# dist directory.
 
 # For dependency files.
 idl_deps_dir := .deps
 
-# Where we put our final, linked .xpt files.
-idl_xpt_dir := xpt
-
 dist_idl_dir := $(DIST)/idl
 dist_include_dir := $(DIST)/include
 process_py := $(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py
 
+ifdef LIBXUL_SDK
+libxul_sdk_includes := -I$(LIBXUL_SDK)/idl
+endif
+
 # TODO we should use py_action, but that would require extra directories to be
 # in the virtualenv.
-idlprocess := $(PYTHON_PATH) $(PLY_INCLUDE) -I$(IDL_PARSER_DIR) -I$(IDL_PARSER_CACHE_DIR) \
-    $(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) $(dist_idl_dir) \
-        $(dist_include_dir) $(idl_xpt_dir) $(idl_deps_dir)
-
-ifdef LIBXUL_SDK
-idlprocess += -I$(LIBXUL_SDK)/idl
-endif
+%.xpt:
+	@echo "$(@F)"
+	$(PYTHON_PATH) $(PLY_INCLUDE) -I$(IDL_PARSER_DIR) -I$(IDL_PARSER_CACHE_DIR) \
+		$(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) $(dist_idl_dir) \
+		$(dist_include_dir) $(@D) $(idl_deps_dir) $(libxul_sdk_includes) \
+		$(basename $(notdir $@ $(filter %.idl,$^)))
 
 xpidl_modules := @xpidl_modules@
+xpt_files := @xpt_files@
 
 @xpidl_rules@
 
-linked_xpt_files := $(addprefix $(idl_xpt_dir)/,$(addsuffix .xpt,$(xpidl_modules)))
 depends_files := $(foreach root,$(xpidl_modules),$(idl_deps_dir)/$(root).pp)
 
-GARBAGE += $(linked_xpt_files) $(depends_files)
+GARBAGE += $(xpt_files) $(depends_files)
 
-xpidl:: $(linked_xpt_files)
+xpidl:: $(xpt_files)
 
-$(linked_xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(dist_include_dir) $(idl_xpt_dir))
+$(xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(dist_include_dir))
 
 $(call include_deps,$(depends_files))
 
 .PHONY: xpidl
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1152,21 +1152,16 @@ endif
 endif
 
 ################################################################################
 # Install a linked .xpt into the appropriate place.
 # This should ideally be performed by the non-recursive idl make file. Some day.
 ifdef XPT_NAME #{
 
 ifndef NO_DIST_INSTALL
-_XPT_NAME_FILES := $(DEPTH)/config/makefiles/xpidl/xpt/$(XPT_NAME)
-_XPT_NAME_DEST := $(FINAL_TARGET)/components
-_XPT_NAME_TARGET := misc
-INSTALL_TARGETS += _XPT_NAME
-
 ifndef NO_INTERFACES_MANIFEST
 misc:: $(call mkdir_deps,$(FINAL_TARGET)/components)
 	$(call py_action,buildlist,$(FINAL_TARGET)/components/interfaces.manifest 'interfaces $(XPT_NAME)')
 	$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest 'manifest components/interfaces.manifest')
 endif
 endif
 
 endif #} XPT_NAME
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -814,17 +814,22 @@ nsScriptLoader::ProcessOffThreadRequest(
   return rv;
 }
 
 NS_IMETHODIMP
 NotifyOffThreadScriptLoadCompletedRunnable::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsresult rv = mLoader->ProcessOffThreadRequest(mRequest, &mToken);
+  // We want these to be dropped on the main thread, once we return from this
+  // function.
+  nsRefPtr<nsScriptLoadRequest> request = mRequest.forget();
+  nsRefPtr<nsScriptLoader> loader = mLoader.forget();
+
+  nsresult rv = loader->ProcessOffThreadRequest(request, &mToken);
 
   if (mToken) {
     // The result of the off thread parse was not actually needed to process
     // the request (disappearing window, some other error, ...). Finish the
     // request to avoid leaks in the JS engine.
     nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
     NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
     JSRuntime *rt;
--- a/dom/html/HTMLMenuElement.cpp
+++ b/dom/html/HTMLMenuElement.cpp
@@ -4,21 +4,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/HTMLMenuElement.h"
 
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/HTMLMenuElementBinding.h"
 #include "mozilla/dom/HTMLMenuItemElement.h"
+#include "nsIMenuBuilder.h"
 #include "nsAttrValueInlines.h"
 #include "nsContentUtils.h"
-#include "nsXULContextMenuBuilder.h"
 #include "nsIURI.h"
 
+#define HTMLMENUBUILDER_CONTRACTID "@mozilla.org/content/html-menu-builder;1"
+
 NS_IMPL_NS_NEW_HTML_ELEMENT(Menu)
 
 namespace mozilla {
 namespace dom {
 
 enum MenuType
 {
   MENU_TYPE_CONTEXT = 1,
@@ -92,34 +94,31 @@ HTMLMenuElement::SendShowEvent()
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLMenuElement::CreateBuilder(nsIMenuBuilder** _retval)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
 
-  *_retval = nullptr;
-
-  if (mType == MENU_TYPE_CONTEXT) {
-    NS_ADDREF(*_retval = new nsXULContextMenuBuilder());
-  }
-
+  nsCOMPtr<nsIMenuBuilder> builder = CreateBuilder();
+  builder.swap(*_retval);
   return NS_OK;
 }
 
 already_AddRefed<nsIMenuBuilder>
 HTMLMenuElement::CreateBuilder()
 {
   if (mType != MENU_TYPE_CONTEXT) {
     return nullptr;
   }
 
-  nsCOMPtr<nsIMenuBuilder> ret = new nsXULContextMenuBuilder();
-  return ret.forget();
+  nsCOMPtr<nsIMenuBuilder> builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID);
+  NS_WARN_IF(!builder);
+  return builder.forget();
 }
 
 NS_IMETHODIMP
 HTMLMenuElement::Build(nsIMenuBuilder* aBuilder)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
 
   if (!aBuilder) {
new file mode 100644
--- /dev/null
+++ b/dom/html/htmlMenuBuilder.js
@@ -0,0 +1,132 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This component is used to build the menus for the HTML contextmenu attribute.
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+// A global value that is used to identify each menu item. It is
+// incremented with each one that is found.
+var gGeneratedId = 1;
+
+function HTMLMenuBuilder() {
+  this.currentNode = null;
+  this.root = null;
+  this.items = {};
+  this.nestedStack = [];
+};
+
+// Building is done in two steps:
+// The first generates a hierarchical JS object that contains the menu structure.
+// This object is returned by toJSONString.
+//
+// The second step can take this structure and generate a XUL menu hierarchy or
+// other UI from this object. The default UI is done in PageMenu.jsm.
+//
+// When a multi-process browser is used, the first step is performed by the child
+// process and the second step is performed by the parent process.
+
+HTMLMenuBuilder.prototype =
+{
+  classID:        Components.ID("{51c65f5d-0de5-4edc-9058-60e50cef77f8}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIMenuBuilder]),
+
+  currentNode: null,
+  root: null,
+  items: {},
+  nestedStack: [],
+
+  toJSONString: function() {
+    return JSON.stringify(this.root);
+  },
+
+  openContainer: function(aLabel) {
+    if (!this.currentNode) {
+      this.root = {
+        type: "menu",
+        children: []
+      };
+      this.currentNode = this.root;
+    }
+    else {
+      let parent = this.currentNode;
+      this.currentNode = {
+        type: "menu",
+        label: aLabel,
+        children: []
+      };
+      parent.children.push(this.currentNode);
+      this.nestedStack.push(parent);
+    }
+  },
+
+  addItemFor: function(aElement, aCanLoadIcon) {
+    if (!("children" in this.currentNode)) {
+      return;
+    }
+
+    let item = {
+      type: "menuitem",
+      label: aElement.label
+    };
+
+    let elementType = aElement.type;
+    if (elementType == "checkbox" || elementType == "radio") {
+      item.checkbox = true;
+
+      if (aElement.checked) {
+        item.checked = true;
+      }
+    }
+
+    let icon = aElement.icon;
+    if (icon.length > 0 && aCanLoadIcon) {
+      item.icon = icon;
+    }
+
+    if (aElement.disabled) {
+      item.disabled = true;
+    }
+
+    item.id = gGeneratedId++;
+    this.currentNode.children.push(item);
+
+    this.items[item.id] = aElement;
+  },
+
+  addSeparator: function() {
+    if (!("children" in this.currentNode)) {
+      return;
+    }
+
+    this.currentNode.children.push({ type: "separator"});
+  },
+
+  undoAddSeparator: function() {
+    if (!("children" in this.currentNode)) {
+      return;
+    }
+
+    let children = this.currentNode.children;
+    if (children.length && children[children.length - 1].type == "separator") {
+      children.pop();
+    }
+  },
+
+  closeContainer: function() {
+    this.currentNode = this.nestedStack.length ? this.nestedStack.pop() : this.root;
+  },
+
+  click: function(id) {
+    let item = this.items[id];
+    if (item) {
+      item.click();
+    }
+  }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HTMLMenuBuilder]);
new file mode 100644
--- /dev/null
+++ b/dom/html/htmlMenuBuilder.manifest
@@ -0,0 +1,3 @@
+component {51c65f5d-0de5-4edc-9058-60e50cef77f8} htmlMenuBuilder.js
+contract @mozilla.org/content/html-menu-builder;1 {51c65f5d-0de5-4edc-9058-60e50cef77f8}
+
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -210,16 +210,21 @@ UNIFIED_SOURCES += [
     'VideoDocument.cpp',
 ]
 
 SOURCES += [
     # Includes npapi.h.
     'PluginDocument.cpp',
 ]
 
+EXTRA_COMPONENTS += [
+    'htmlMenuBuilder.js',
+    'htmlMenuBuilder.manifest'
+]
+
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/caps',
--- a/dom/html/nsIMenuBuilder.idl
+++ b/dom/html/nsIMenuBuilder.idl
@@ -6,17 +6,17 @@
 #include "nsISupports.idl"
 
 interface nsIDOMHTMLMenuItemElement;
 
 /**
  * An interface used to construct native toolbar or context menus from <menu>
  */
 
-[scriptable, uuid(12724737-f7db-43b4-94ab-708a7b86e115)]
+[scriptable, uuid(93F4A48F-D043-4F45-97FD-9771EA1AF976)]
 interface nsIMenuBuilder : nsISupports
 {
 
   /**
    * Create the top level menu or a submenu. The implementation should create
    * a new context for this menu, so all subsequent methods will add new items
    * to this newly created menu.
    */
@@ -44,9 +44,33 @@ interface nsIMenuBuilder : nsISupports
    */
   void undoAddSeparator();
 
   /**
    * Set the context to the parent menu.
    */
   void closeContainer();
 
+  /**
+   * Returns a JSON string representing the menu hierarchy. For a context menu,
+   * it will be of the form:
+   *  {
+   *    type: "menu",
+   *    children: [
+   *      {
+   *        type: "menuitem",
+   *        label: "label",
+   *        icon: "image.png"
+   *      },
+   *      {
+   *        type: "separator",
+   *      },
+   *    ];
+   */
+  AString toJSONString();
+
+  /**
+   * Invoke the action of the menuitem with assigned id aGeneratedItemId.
+   *
+   * @param aGeneratedItemId the menuitem id
+   */
+  void click(in DOMString aGeneratedItemId);
 };
--- a/dom/media/gstreamer/GStreamerReader.cpp
+++ b/dom/media/gstreamer/GStreamerReader.cpp
@@ -65,16 +65,17 @@ typedef enum {
   GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10)
 } PlayFlags;
 
 GStreamerReader::GStreamerReader(AbstractMediaDecoder* aDecoder)
   : MediaDecoderReader(aDecoder),
   mMP3FrameParser(aDecoder->GetResource()->GetLength()),
   mDataOffset(0),
   mUseParserDuration(false),
+  mLastParserDuration(-1),
 #if GST_VERSION_MAJOR >= 1
   mAllocator(nullptr),
   mBufferPool(nullptr),
 #endif
   mPlayBin(nullptr),
   mBus(nullptr),
   mSource(nullptr),
   mVideoSink(nullptr),
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AudioBufferSourceNode.h"
 #include "mozilla/dom/AudioBufferSourceNodeBinding.h"
 #include "mozilla/dom/AudioParam.h"
+#include "mozilla/FloatingPoint.h"
 #include "nsMathUtils.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioDestinationNode.h"
 #include "AudioParamTimeline.h"
 #include <limits>
 
 namespace mozilla {
@@ -105,17 +106,17 @@ public:
     case AudioBufferSourceNode::START:
       MOZ_ASSERT(!mStart, "Another START?");
       mStart =
         mSource->FractionalTicksFromDestinationTime(mDestination, aParam);
       // Round to nearest
       mBeginProcessing = mStart + 0.5;
       break;
     case AudioBufferSourceNode::DOPPLERSHIFT:
-      mDopplerShift = aParam > 0 && aParam == aParam ? aParam : 1.0;
+      mDopplerShift = (aParam <= 0 || mozilla::IsNaN(aParam)) ? 1.0 : aParam;
       break;
     default:
       NS_ERROR("Bad AudioBufferSourceNodeEngine double parameter.");
     };
   }
   virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam)
   {
     switch (aIndex) {
@@ -410,17 +411,17 @@ public:
   {
     float playbackRate;
 
     if (mPlaybackRateTimeline.HasSimpleValue()) {
       playbackRate = mPlaybackRateTimeline.GetValue();
     } else {
       playbackRate = mPlaybackRateTimeline.GetValueAtTime(mSource->GetCurrentPosition());
     }
-    if (playbackRate <= 0 || playbackRate != playbackRate) {
+    if (playbackRate <= 0 || mozilla::IsNaN(playbackRate)) {
       playbackRate = 1.0f;
     }
 
     int32_t outRate = ComputeFinalOutSampleRate(playbackRate);
     UpdateResampler(outRate, aChannels);
   }
 
   virtual void ProcessBlock(AudioNodeStream* aStream,
--- a/dom/media/webaudio/WebAudioUtils.h
+++ b/dom/media/webaudio/WebAudioUtils.h
@@ -176,17 +176,17 @@ namespace WebAudioUtils {
   {
     using namespace std;
 
     static_assert(mozilla::IsIntegral<IntType>::value == true,
                   "IntType must be an integral type");
     static_assert(mozilla::IsFloatingPoint<FloatType>::value == true,
                   "FloatType must be a floating point type");
 
-    if (f != f) {
+    if (mozilla::IsNaN(f)) {
       // It is the responsibility of the caller to deal with NaN values.
       // If we ever get to this point, we have a serious bug to fix.
       NS_RUNTIMEABORT("We should never see a NaN here");
     }
 
     if (f > FloatType(numeric_limits<IntType>::max())) {
       // If the floating point value is outside of the range of maximum
       // integral value for this type, just clamp to the maximum value.
--- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
@@ -686,50 +686,82 @@ MediaEngineGonkVideoSource::RotateImage(
   layers::GrallocImage* videoImage = static_cast<layers::GrallocImage*>(image.get());
   MOZ_ASSERT(mTextureClientAllocator);
   RefPtr<layers::TextureClient> textureClient
     = mTextureClientAllocator->CreateOrRecycleForDrawing(gfx::SurfaceFormat::YUV,
                                                          gfx::IntSize(dstWidth, dstHeight),
                                                          gfx::BackendType::NONE,
                                                          layers::TextureFlags::DEFAULT,
                                                          layers::ALLOC_DISALLOW_BUFFERTEXTURECLIENT);
-  if (!textureClient) {
-    return;
-  }
-  RefPtr<layers::GrallocTextureClientOGL> grallocTextureClient =
-    static_cast<layers::GrallocTextureClientOGL*>(textureClient.get());
+  if (textureClient) {
+    RefPtr<layers::GrallocTextureClientOGL> grallocTextureClient =
+      static_cast<layers::GrallocTextureClientOGL*>(textureClient.get());
 
-  android::sp<android::GraphicBuffer> destBuffer = grallocTextureClient->GetGraphicBuffer();
+    android::sp<android::GraphicBuffer> destBuffer = grallocTextureClient->GetGraphicBuffer();
+
+    void* destMem = nullptr;
+    destBuffer->lock(android::GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destMem);
+    uint8_t* dstPtr = static_cast<uint8_t*>(destMem);
 
-  void* destMem = nullptr;
-  destBuffer->lock(android::GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destMem);
-  uint8_t* dstPtr = static_cast<uint8_t*>(destMem);
+    int32_t yStride = destBuffer->getStride();
+    // Align to 16 bytes boundary
+    int32_t uvStride = ((yStride / 2) + 15) & ~0x0F;
 
-  int32_t yStride = destBuffer->getStride();
-  // Align to 16 bytes boundary
-  int32_t uvStride = ((yStride / 2) + 15) & ~0x0F;
+    libyuv::ConvertToI420(srcPtr, size,
+                          dstPtr, yStride,
+                          dstPtr + (yStride * dstHeight + (uvStride * dstHeight / 2)), uvStride,
+                          dstPtr + (yStride * dstHeight), uvStride,
+                          0, 0,
+                          aWidth, aHeight,
+                          aWidth, aHeight,
+                          static_cast<libyuv::RotationMode>(mRotation),
+                          libyuv::FOURCC_NV21);
+    destBuffer->unlock();
+
+    layers::GrallocImage::GrallocData data;
 
-  libyuv::ConvertToI420(srcPtr, size,
-                        dstPtr, yStride,
-                        dstPtr + (yStride * dstHeight + (uvStride * dstHeight / 2)), uvStride,
-                        dstPtr + (yStride * dstHeight), uvStride,
-                        0, 0,
-                        aWidth, aHeight,
-                        aWidth, aHeight,
-                        static_cast<libyuv::RotationMode>(mRotation),
-                        libyuv::FOURCC_NV21);
-  destBuffer->unlock();
+    data.mPicSize = gfx::IntSize(dstWidth, dstHeight);
+    data.mGraphicBuffer = textureClient;
+    videoImage->SetData(data);
+  } else {
+    // Handle out of gralloc case.
+    image = mImageContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
+    layers::PlanarYCbCrImage* videoImage = static_cast<layers::PlanarYCbCrImage*>(image.get());
+    uint8_t* dstPtr = videoImage->AllocateAndGetNewBuffer(size);
+
+    libyuv::ConvertToI420(srcPtr, size,
+                          dstPtr, dstWidth,
+                          dstPtr + (dstWidth * dstHeight), half_width,
+                          dstPtr + (dstWidth * dstHeight * 5 / 4), half_width,
+                          0, 0,
+                          aWidth, aHeight,
+                          aWidth, aHeight,
+                          static_cast<libyuv::RotationMode>(mRotation),
+                          ConvertPixelFormatToFOURCC(graphicBuffer->getPixelFormat()));
+
+    const uint8_t lumaBpp = 8;
+    const uint8_t chromaBpp = 4;
+
+    layers::PlanarYCbCrData data;
+    data.mYChannel = dstPtr;
+    data.mYSize = IntSize(dstWidth, dstHeight);
+    data.mYStride = dstWidth * lumaBpp / 8;
+    data.mCbCrStride = dstWidth * chromaBpp / 8;
+    data.mCbChannel = dstPtr + dstHeight * data.mYStride;
+    data.mCrChannel = data.mCbChannel + data.mCbCrStride * (dstHeight / 2);
+    data.mCbCrSize = IntSize(dstWidth / 2, dstHeight / 2);
+    data.mPicX = 0;
+    data.mPicY = 0;
+    data.mPicSize = IntSize(dstWidth, dstHeight);
+    data.mStereoMode = StereoMode::MONO;
+
+    videoImage->SetDataNoCopy(data);
+  }
   graphicBuffer->unlock();
 
-  layers::GrallocImage::GrallocData data;
-
-  data.mPicSize = gfx::IntSize(dstWidth, dstHeight);
-  data.mGraphicBuffer = textureClient;
-  videoImage->SetData(data);
-
   // Implicitly releases last preview image.
   mImage = image.forget();
 }
 
 bool
 MediaEngineGonkVideoSource::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) {
   {
     ReentrantMonitorAutoEnter sync(mCallbackMonitor);
@@ -762,33 +794,41 @@ MediaEngineGonkVideoSource::OnNewMediaBu
     ReentrantMonitorAutoEnter sync(mCallbackMonitor);
     if (mState == kStopped) {
       return NS_OK;
     }
   }
 
   MonitorAutoLock enter(mMonitor);
   if (mImage) {
-    GonkCameraImage* cameraImage = static_cast<GonkCameraImage*>(mImage.get());
-
-    cameraImage->SetBuffer(aBuffer);
+    if (mImage->AsGrallocImage()) {
+      // MediaEngineGonkVideoSource expects that GrallocImage is GonkCameraImage.
+      // See Bug 938034.
+      GonkCameraImage* cameraImage = static_cast<GonkCameraImage*>(mImage.get());
+      cameraImage->SetBuffer(aBuffer);
+    } else {
+      LOG(("mImage is non-GrallocImage"));
+    }
 
     uint32_t len = mSources.Length();
     for (uint32_t i = 0; i < len; i++) {
       if (mSources[i]) {
         // Duration is 1 here.
         // Ideally, it should be camera timestamp here and the MSG will have
         // enough sample duration without calling NotifyPull() anymore.
         // Unfortunately, clock in gonk camera looks like is a different one
         // comparing to MSG. As result, it causes time inaccurate. (frames be
         // queued in MSG longer and longer as time going by in device like Frame)
-        AppendToTrack(mSources[i], cameraImage, mTrackID, 1);
+        AppendToTrack(mSources[i], mImage, mTrackID, 1);
       }
     }
-    // Clear MediaBuffer immediately, it prevents MediaBuffer is kept in
-    // MediaStreamGraph thread.
-    cameraImage->ClearBuffer();
+    if (mImage->AsGrallocImage()) {
+      GonkCameraImage* cameraImage = static_cast<GonkCameraImage*>(mImage.get());
+      // Clear MediaBuffer immediately, it prevents MediaBuffer is kept in
+      // MediaStreamGraph thread.
+      cameraImage->ClearBuffer();
+    }
   }
 
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/webidl/HTMLMenuElement.webidl
+++ b/dom/webidl/HTMLMenuElement.webidl
@@ -35,21 +35,21 @@ partial interface HTMLMenuElement {
    * The event is not cancelable and does not bubble.
    * See http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus
    */
   [ChromeOnly]
   void sendShowEvent();
 
   /**
    * Creates a native menu builder. The builder type is dependent on menu type.
-   * Currently, it returns nsXULContextMenuBuilder for context menus.
-   * Toolbar menus are not yet supported (the method returns null).
+   * Currently, it returns the @mozilla.org/content/html-menu-builder;1
+   * component. Toolbar menus are not yet supported (the method returns null).
    */
   [ChromeOnly]
-  MenuBuilder createBuilder();
+  MenuBuilder? createBuilder();
 
   /*
    * Builds a menu by iterating over menu children.
    * See http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#building-menus-and-toolbars
    * The caller can use a native builder by calling createBuilder() or provide
    * a custom builder that implements the nsIMenuBuilder interface.
    * A custom builder can be used for example to build native context menus
    * that are not defined using <menupopup>.
--- a/dom/xul/moz.build
+++ b/dom/xul/moz.build
@@ -7,28 +7,26 @@
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 if CONFIG['MOZ_XUL']:
     DIRS += ['templates']
 
     XPIDL_SOURCES += [
-        'nsIXULContextMenuBuilder.idl',
         'nsIXULOverlayProvider.idl',
     ]
 
     EXPORTS += [
         'nsIXULDocument.h',
     ]
 
     UNIFIED_SOURCES += [
         'nsXULCommandDispatcher.cpp',
         'nsXULContentSink.cpp',
-        'nsXULContextMenuBuilder.cpp',
         'nsXULElement.cpp',
         'nsXULPopupListener.cpp',
         'nsXULPrototypeCache.cpp',
         'nsXULPrototypeDocument.cpp',
         'XULDocument.cpp',
     ]
 
 XPIDL_SOURCES += [
deleted file mode 100644
--- a/dom/xul/nsIXULContextMenuBuilder.idl
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-interface nsIDOMDocumentFragment;
-
-/**
- * An interface for initialization of XUL context menu builder
- * and for triggering of menuitem actions with assigned identifiers.
- */
-
-[scriptable, uuid(eb6b42c0-2f1c-4760-b5ca-bdc9b3ec77d4)]
-interface nsIXULContextMenuBuilder : nsISupports
-{
-
-  /**
-   * Initialize builder before building.
-   *
-   * @param aDocumentFragment the fragment that will be used to append top
-   *        level elements
-   *
-   * @param aGeneratedItemIdAttrName the name of the attribute that will be
-   *        used to mark elements as generated and for menuitem identification
-   */
-  void init(in nsIDOMDocumentFragment aDocumentFragment,
-            in AString aGeneratedItemIdAttrName);
-
-  /**
-   * Invoke the action of the menuitem with assigned id aGeneratedItemId.
-   *
-   * @param aGeneratedItemId the menuitem id
-   */
-  void click(in DOMString aGeneratedItemId);
-
-};
deleted file mode 100644
--- a/dom/xul/nsXULContextMenuBuilder.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsContentCreatorFunctions.h"
-#include "nsIContent.h"
-#include "nsIDOMDocumentFragment.h"
-#include "nsIDOMHTMLElement.h"
-#include "nsIDOMHTMLMenuItemElement.h"
-#include "nsXULContextMenuBuilder.h"
-#include "nsIDocument.h"
-#include "mozilla/dom/Element.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-
-nsXULContextMenuBuilder::nsXULContextMenuBuilder()
-  : mCurrentGeneratedItemId(0)
-{
-}
-
-nsXULContextMenuBuilder::~nsXULContextMenuBuilder()
-{
-}
-
-NS_IMPL_CYCLE_COLLECTION(nsXULContextMenuBuilder, mFragment, mDocument,
-                         mCurrentNode, mElements)
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULContextMenuBuilder)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULContextMenuBuilder)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULContextMenuBuilder)
-  NS_INTERFACE_MAP_ENTRY(nsIMenuBuilder)
-  NS_INTERFACE_MAP_ENTRY(nsIXULContextMenuBuilder)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMenuBuilder)
-NS_INTERFACE_MAP_END
-
-
-NS_IMETHODIMP
-nsXULContextMenuBuilder::OpenContainer(const nsAString& aLabel)
-{
-  if (!mFragment) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  if (!mCurrentNode) {
-    mCurrentNode = mFragment;
-  } else {
-    nsCOMPtr<Element> menu;
-    nsresult rv = CreateElement(nsGkAtoms::menu, nullptr, getter_AddRefs(menu));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    menu->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aLabel, false);
-
-    nsCOMPtr<Element> menuPopup;
-    rv = CreateElement(nsGkAtoms::menupopup, nullptr,
-                       getter_AddRefs(menuPopup));
-    NS_ENSURE_SUCCESS(rv, rv);
-        
-    rv = menu->AppendChildTo(menuPopup, false);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = mCurrentNode->AppendChildTo(menu, false);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mCurrentNode = menuPopup;
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsXULContextMenuBuilder::AddItemFor(nsIDOMHTMLMenuItemElement* aElement,
-                                    bool aCanLoadIcon)
-{
-  if (!mFragment) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  nsCOMPtr<Element> menuitem;
-  nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(aElement);
-  nsresult rv = CreateElement(nsGkAtoms::menuitem, element,
-                              getter_AddRefs(menuitem));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoString type;
-  aElement->GetType(type);
-  if (type.EqualsLiteral("checkbox") || type.EqualsLiteral("radio")) {
-    // The menu is only temporary, so we don't need to handle
-    // the radio type precisely.
-    menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
-                      NS_LITERAL_STRING("checkbox"), false);
-    bool checked;
-    aElement->GetChecked(&checked);
-    if (checked) {
-      menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::checked,
-                        NS_LITERAL_STRING("true"), false);
-    }
-  }
-
-  nsAutoString label;
-  aElement->GetLabel(label);
-  menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::label, label, false);
-
-  nsAutoString icon;
-  aElement->GetIcon(icon);
-  if (!icon.IsEmpty()) {
-    menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
-                      NS_LITERAL_STRING("menuitem-iconic"), false);
-    if (aCanLoadIcon) {
-      menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::image, icon, false);
-    }
-  }
-
-  bool disabled;
-  aElement->GetDisabled(&disabled);
-  if (disabled) {
-    menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
-                      NS_LITERAL_STRING("true"), false);
-  }
-
-  return mCurrentNode->AppendChildTo(menuitem, false);
-}
-
-NS_IMETHODIMP
-nsXULContextMenuBuilder::AddSeparator()
-{
-  if (!mFragment) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  nsCOMPtr<Element> menuseparator;
-  nsresult rv = CreateElement(nsGkAtoms::menuseparator, nullptr,
-                              getter_AddRefs(menuseparator));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return mCurrentNode->AppendChildTo(menuseparator, false);
-}
-
-NS_IMETHODIMP
-nsXULContextMenuBuilder::UndoAddSeparator()
-{
-  if (!mFragment) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  uint32_t count = mCurrentNode->GetChildCount();
-  if (!count ||
-      mCurrentNode->GetChildAt(count - 1)->Tag() != nsGkAtoms::menuseparator) {
-    return NS_OK;
-  }
-
-  mCurrentNode->RemoveChildAt(count - 1, false);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsXULContextMenuBuilder::CloseContainer()
-{
-  if (!mFragment) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  if (mCurrentNode == mFragment) {
-    mCurrentNode = nullptr;
-  } else {
-    nsIContent* parent = mCurrentNode->GetParent();
-    mCurrentNode = parent->GetParent();
-  }
-
-  return NS_OK;
-}
-
-
-NS_IMETHODIMP
-nsXULContextMenuBuilder::Init(nsIDOMDocumentFragment* aDocumentFragment,
-                              const nsAString& aGeneratedItemIdAttrName)
-{
-  NS_ENSURE_ARG_POINTER(aDocumentFragment);
-
-  mFragment = do_QueryInterface(aDocumentFragment);
-  mDocument = mFragment->GetOwnerDocument();
-  mGeneratedItemIdAttr = do_GetAtom(aGeneratedItemIdAttrName);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsXULContextMenuBuilder::Click(const nsAString& aGeneratedItemId)
-{
-  nsresult rv;
-  int32_t idx = nsString(aGeneratedItemId).ToInteger(&rv);
-  if (NS_SUCCEEDED(rv)) {
-    nsCOMPtr<nsIDOMHTMLElement> element = mElements.SafeObjectAt(idx);
-    if (element) {
-      element->DOMClick();
-    }
-  }
-
-  return NS_OK;
-}
-
-nsresult
-nsXULContextMenuBuilder::CreateElement(nsIAtom* aTag,
-                                       nsIDOMHTMLElement* aHTMLElement,
-                                       Element** aResult)
-{
-  *aResult = nullptr;
-
-  nsRefPtr<mozilla::dom::NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
-    aTag, nullptr, kNameSpaceID_XUL, nsIDOMNode::ELEMENT_NODE);
-
-  nsresult rv = NS_NewElement(aResult, nodeInfo.forget(), NOT_FROM_PARSER);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsAutoString generateditemid;
-
-  if (aHTMLElement) {
-    mElements.AppendObject(aHTMLElement);
-    generateditemid.AppendInt(mCurrentGeneratedItemId++);
-  }
-
-  (*aResult)->SetAttr(kNameSpaceID_None, mGeneratedItemIdAttr, generateditemid,
-                      false);
-
-  return NS_OK;
-}
deleted file mode 100644
--- a/dom/xul/nsXULContextMenuBuilder.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsCOMPtr.h"
-#include "nsCOMArray.h"
-#include "nsIMenuBuilder.h"
-#include "nsIXULContextMenuBuilder.h"
-#include "nsCycleCollectionParticipant.h"
-
-class nsIAtom;
-class nsIContent;
-class nsIDocument;
-class nsIDOMHTMLElement;
-
-namespace mozilla {
-namespace dom {
-class Element;
-} // namespace dom
-} // namespace mozilla
-
-class nsXULContextMenuBuilder : public nsIMenuBuilder,
-                                public nsIXULContextMenuBuilder
-{
-public:
-  nsXULContextMenuBuilder();
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULContextMenuBuilder,
-                                           nsIMenuBuilder)
-  NS_DECL_NSIMENUBUILDER
-
-  NS_DECL_NSIXULCONTEXTMENUBUILDER
-
-protected:
-  virtual ~nsXULContextMenuBuilder();
-
-  nsresult CreateElement(nsIAtom* aTag,
-                         nsIDOMHTMLElement* aHTMLElement,
-                         mozilla::dom::Element** aResult);
-
-  nsCOMPtr<nsIContent>          mFragment;
-  nsCOMPtr<nsIDocument>         mDocument;
-  nsCOMPtr<nsIAtom>             mGeneratedItemIdAttr;
-
-  nsCOMPtr<nsIContent>          mCurrentNode;
-  int32_t                       mCurrentGeneratedItemId;
-
-  nsCOMArray<nsIDOMHTMLElement> mElements;
-};
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -211,17 +211,17 @@ SharedFrameMetricsHelper::UpdateFromComp
   // display-port. If we abort updating when we shouldn't, we can end up
   // with blank regions on the screen and we open up the risk of entering
   // an endless updating cycle.
   if (fabsf(contentMetrics.GetScrollOffset().x - compositorMetrics.GetScrollOffset().x) <= 2 &&
       fabsf(contentMetrics.GetScrollOffset().y - compositorMetrics.GetScrollOffset().y) <= 2 &&
       fabsf(contentMetrics.mDisplayPort.x - compositorMetrics.mDisplayPort.x) <= 2 &&
       fabsf(contentMetrics.mDisplayPort.y - compositorMetrics.mDisplayPort.y) <= 2 &&
       fabsf(contentMetrics.mDisplayPort.width - compositorMetrics.mDisplayPort.width) <= 2 &&
-      fabsf(contentMetrics.mDisplayPort.height - compositorMetrics.mDisplayPort.height)) {
+      fabsf(contentMetrics.mDisplayPort.height - compositorMetrics.mDisplayPort.height) <= 2) {
     return false;
   }
 
   // When not a low precision pass and the page is in danger of checker boarding
   // abort update.
   if (!aLowPrecision && !mProgressiveUpdateWasInDanger) {
     bool scrollUpdatePending = contentMetrics.GetScrollOffsetUpdated() &&
         contentMetrics.GetScrollGeneration() != compositorMetrics.GetScrollGeneration();
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -91,160 +91,16 @@ TextureTargetForAndroidPixelFormat(andro
       // we'll take down the compositor process and thus the phone. This seems
       // like undesirable behaviour. We'd rather have a subtle artifact.
       MOZ_ASSERT(false, "Unknown Android pixel format.");
       return LOCAL_GL_TEXTURE_EXTERNAL;
     }
   }
 }
 
-GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor,
-                                                 GrallocTextureHostOGL* aTextureHost,
-                                                 android::GraphicBuffer* aGraphicBuffer,
-                                                 gfx::SurfaceFormat aFormat)
-  : mCompositor(aCompositor)
-  , mTextureHost(aTextureHost)
-  , mGraphicBuffer(aGraphicBuffer)
-  , mEGLImage(0)
-  , mFormat(aFormat)
-  , mNeedsReset(true)
-{
-  MOZ_ASSERT(mGraphicBuffer.get());
-}
-
-GrallocTextureSourceOGL::~GrallocTextureSourceOGL()
-{
-  DeallocateDeviceData();
-  mCompositor = nullptr;
-}
-
-void
-GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
-{
-  /*
-   * The job of this function is to ensure that the texture is tied to the
-   * android::GraphicBuffer, so that texturing will source the GraphicBuffer.
-   *
-   * To this effect we create an EGLImage wrapping this GraphicBuffer,
-   * using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our
-   * texture using fEGLImageTargetTexture2D.
-   */
-  MOZ_ASSERT(gl());
-  if (!IsValid() || !gl()->MakeCurrent()) {
-    return;
-  }
-
-  GLuint tex = GetGLTexture();
-  GLuint textureTarget = GetTextureTarget();
-
-  gl()->fActiveTexture(aTextureUnit);
-  gl()->fBindTexture(textureTarget, tex);
-
-  ApplyFilterToBoundTexture(gl(), aFilter, textureTarget);
-
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
-  if (mTextureHost) {
-    // Wait until it's ready.
-    mTextureHost->WaitAcquireFenceSyncComplete();
-  }
-#endif
-}
-
-bool GrallocTextureSourceOGL::Lock()
-{
-  MOZ_ASSERT(IsValid());
-  if (!IsValid()) {
-    return false;
-  }
-  if (!gl()->MakeCurrent()) {
-    NS_WARNING("Failed to make the gl context current");
-    return false;
-  }
-
-  mTexture = mCompositor->GetTemporaryTexture(GetTextureTarget(), LOCAL_GL_TEXTURE0);
-
-  GLuint textureTarget = GetTextureTarget();
-
-  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-  gl()->fBindTexture(textureTarget, mTexture);
-  if (!mEGLImage) {
-    mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
-  }
-  gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
-  return true;
-}
-
-bool
-GrallocTextureSourceOGL::IsValid() const
-{
-  return !!gl() && !!mGraphicBuffer.get() && !!mCompositor;
-}
-
-gl::GLContext*
-GrallocTextureSourceOGL::gl() const
-{
-  return mCompositor ? mCompositor->gl() : nullptr;
-}
-
-void
-GrallocTextureSourceOGL::SetCompositor(Compositor* aCompositor)
-{
-  if (mCompositor && !aCompositor) {
-    DeallocateDeviceData();
-  }
-  mCompositor = static_cast<CompositorOGL*>(aCompositor);
-}
-
-
-GLenum
-GrallocTextureSourceOGL::GetTextureTarget() const
-{
-  MOZ_ASSERT(gl());
-  MOZ_ASSERT(mGraphicBuffer.get());
-
-  if (!gl() || !mGraphicBuffer.get()) {
-    return LOCAL_GL_TEXTURE_EXTERNAL;
-  }
-
-  // SGX has a quirk that only TEXTURE_EXTERNAL works and any other value will
-  // result in black pixels when trying to draw from bound textures.
-  // Unfortunately, using TEXTURE_EXTERNAL on Adreno has a terrible effect on
-  // performance.
-  // See Bug 950050.
-  if (gl()->Renderer() == gl::GLRenderer::SGX530 ||
-      gl()->Renderer() == gl::GLRenderer::SGX540) {
-    return LOCAL_GL_TEXTURE_EXTERNAL;
-  }
-
-  return TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat());
-}
-
-gfx::IntSize
-GrallocTextureSourceOGL::GetSize() const
-{
-  if (!IsValid()) {
-    NS_WARNING("Trying to access the size of an invalid GrallocTextureSourceOGL");
-    return gfx::IntSize(0, 0);
-  }
-  return gfx::IntSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight());
-}
-
-void
-GrallocTextureSourceOGL::DeallocateDeviceData()
-{
-  if (mEGLImage) {
-    MOZ_ASSERT(mCompositor);
-    if (!gl() || !gl()->MakeCurrent()) {
-      return;
-    }
-    EGLImageDestroy(gl(), mEGLImage);
-    mEGLImage = EGL_NO_IMAGE;
-  }
-}
-
 GrallocTextureHostOGL::GrallocTextureHostOGL(TextureFlags aFlags,
                                              const NewSurfaceDescriptorGralloc& aDescriptor)
   : TextureHost(aFlags)
   , mGrallocHandle(aDescriptor)
   , mSize(0, 0)
   , mDescriptorSize(aDescriptor.size())
   , mFormat(gfx::SurfaceFormat::UNKNOWN)
   , mEGLImage(EGL_NO_IMAGE)
@@ -267,19 +123,16 @@ GrallocTextureHostOGL::~GrallocTextureHo
 {
   DestroyEGLImage();
 }
 
 void
 GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
 {
   mCompositor = static_cast<CompositorOGL*>(aCompositor);
-  if (mTilingTextureSource) {
-    mTilingTextureSource->SetCompositor(mCompositor);
-  }
   if (mGLTextureSource) {
     mGLTextureSource->SetCompositor(mCompositor);
   }
 
   if (mCompositor && aCompositor != mCompositor) {
     DestroyEGLImage();
   }
 }
@@ -307,20 +160,16 @@ gfx::SurfaceFormat
 GrallocTextureHostOGL::GetFormat() const
 {
   return mFormat;
 }
 
 void
 GrallocTextureHostOGL::DeallocateSharedData()
 {
-  if (mTilingTextureSource) {
-    mTilingTextureSource->ForgetBuffer();
-    mTilingTextureSource = nullptr;
-  }
   if (mGLTextureSource) {
     mGLTextureSource = nullptr;
   }
 
   DestroyEGLImage();
 
   if (mGrallocHandle.buffer().type() != MaybeMagicGrallocBufferHandle::Tnull_t) {
     MaybeMagicGrallocBufferHandle handle = mGrallocHandle.buffer();
@@ -334,31 +183,24 @@ GrallocTextureHostOGL::DeallocateSharedD
 
     SharedBufferManagerParent::DropGrallocBuffer(owner, mGrallocHandle);
   }
 }
 
 void
 GrallocTextureHostOGL::ForgetSharedData()
 {
-  if (mTilingTextureSource) {
-    mTilingTextureSource->ForgetBuffer();
-    mTilingTextureSource = nullptr;
-  }
   if (mGLTextureSource) {
     mGLTextureSource = nullptr;
   }
 }
 
 void
 GrallocTextureHostOGL::DeallocateDeviceData()
 {
-  if (mTilingTextureSource) {
-    mTilingTextureSource->DeallocateDeviceData();
-  }
   if (mGLTextureSource) {
     mGLTextureSource = nullptr;
   }
   DestroyEGLImage();
 }
 
 LayerRenderState
 GrallocTextureHostOGL::GetRenderState()
@@ -382,87 +224,34 @@ GrallocTextureHostOGL::GetRenderState()
                             this);
   }
 
   return LayerRenderState();
 }
 
 TemporaryRef<gfx::DataSourceSurface>
 GrallocTextureHostOGL::GetAsSurface() {
-  if (mTilingTextureSource) {
-    return mTilingTextureSource->GetAsSurface();
-  } else {
-    android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
-    uint8_t* grallocData;
-    int32_t rv = graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
-    RefPtr<gfx::DataSourceSurface> grallocTempSurf =
-      gfx::Factory::CreateWrappingDataSourceSurface(grallocData,
-                                                    graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()),
-                                                    GetSize(), GetFormat());
-    RefPtr<gfx::DataSourceSurface> surf = CreateDataSourceSurfaceByCloning(grallocTempSurf);
-
-    graphicBuffer->unlock();
-
-    return surf.forget();
-  }
-}
-
-TemporaryRef<gfx::DataSourceSurface>
-GrallocTextureSourceOGL::GetAsSurface() {
-  if (!IsValid()) {
-    return nullptr;
-  }
-
+  android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
   uint8_t* grallocData;
-  int32_t rv = mGraphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
-  if (rv) {
-    return nullptr;
-  }
-
+  int32_t rv = graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
   RefPtr<gfx::DataSourceSurface> grallocTempSurf =
     gfx::Factory::CreateWrappingDataSourceSurface(grallocData,
-                                                  mGraphicBuffer->getStride() * android::bytesPerPixel(mGraphicBuffer->getPixelFormat()),
+                                                  graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()),
                                                   GetSize(), GetFormat());
-
   RefPtr<gfx::DataSourceSurface> surf = CreateDataSourceSurfaceByCloning(grallocTempSurf);
 
-  mGraphicBuffer->unlock();
+  graphicBuffer->unlock();
 
   return surf.forget();
 }
 
-GLuint
-GrallocTextureSourceOGL::GetGLTexture()
-{
-  return mTexture;
-}
-
-void
-GrallocTextureSourceOGL::BindEGLImage()
-{
-  gl()->fEGLImageTargetTexture2D(GetTextureTarget(), mEGLImage);
-}
-
 TextureSource*
 GrallocTextureHostOGL::GetTextureSources()
 {
-  // This is now only used with tiled layers, and will eventually be removed.
-  // Other layer types use BindTextureSource instead.
-  MOZ_ASSERT(!mGLTextureSource);
-  if (!mTilingTextureSource) {
-    android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
-    MOZ_ASSERT(graphicBuffer);
-    if (!graphicBuffer) {
-      return nullptr;
-    }
-    mTilingTextureSource = new GrallocTextureSourceOGL(mCompositor, this,
-                                                 graphicBuffer, mFormat);
-  }
-  mTilingTextureSource->Lock();
-  return mTilingTextureSource;
+  return nullptr;
 }
 
 void
 GrallocTextureHostOGL::UnbindTextureSource()
 {
   // Clear the reference to the TextureSource (if any), because we know that
   // another TextureHost is being bound to the TextureSource. This means that
   // we will have to re-do gl->fEGLImageTargetTexture2D next time we go through
@@ -524,18 +313,16 @@ GrallocTextureHostOGL::PrepareTextureSou
   // attach to it. This has the effect of unlocking the previous TextureHost that
   // we attached to the TextureSource (the previous frame)
 
   // If the TextureSource used by the compositable is also used by other
   // compositables (see NumCompositableRefs), we have to create a new TextureSource,
   // because otherwise we would be modifying the content of every layer that uses
   // the TextureSource in question, even thoug they don't use this TextureHost.
 
-  MOZ_ASSERT(!mTilingTextureSource);
-
   android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
 
   MOZ_ASSERT(graphicBuffer);
   if (!graphicBuffer) {
     mGLTextureSource = nullptr;
     return;
   }
 
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -10,84 +10,16 @@
 #include "mozilla/layers/CompositorOGL.h"
 #include "mozilla/layers/TextureHostOGL.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include <ui/GraphicBuffer.h>
 
 namespace mozilla {
 namespace layers {
 
-class GrallocTextureHostOGL;
-
-// Progressively getting replaced by GLTextureSource
-class GrallocTextureSourceOGL : public TextureSource
-                              , public TextureSourceOGL
-{
-public:
-  friend class GrallocTextureHostOGL;
-
-  GrallocTextureSourceOGL(CompositorOGL* aCompositor,
-                          GrallocTextureHostOGL* aTextureHost,
-                          android::GraphicBuffer* aGraphicBuffer,
-                          gfx::SurfaceFormat aFormat);
-
-  virtual ~GrallocTextureSourceOGL();
-
-  virtual bool IsValid() const MOZ_OVERRIDE;
-
-  virtual void BindTexture(GLenum aTextureUnit, gfx::Filter aFilter) MOZ_OVERRIDE;
-
-  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
-
-  virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; }
-
-  virtual GLenum GetTextureTarget() const MOZ_OVERRIDE;
-
-  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mFormat; }
-
-  virtual GLenum GetWrapMode() const MOZ_OVERRIDE
-  {
-    return LOCAL_GL_CLAMP_TO_EDGE;
-  }
-
-  void DeallocateDeviceData();
-
-  gl::GLContext* gl() const;
-
-  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
-
-  void ForgetBuffer()
-  {
-    mGraphicBuffer = nullptr;
-    mTextureHost = nullptr;
-  }
-
-  TemporaryRef<gfx::DataSourceSurface> GetAsSurface();
-
-  GLuint GetGLTexture();
-
-  void BindEGLImage();
-
-  EGLImage GetEGLImage()
-  {
-    return mEGLImage;
-  }
-
-  bool Lock();
-
-protected:
-  RefPtr<CompositorOGL> mCompositor;
-  GrallocTextureHostOGL* mTextureHost;
-  android::sp<android::GraphicBuffer> mGraphicBuffer;
-  EGLImage mEGLImage;
-  GLuint mTexture;
-  gfx::SurfaceFormat mFormat;
-  bool mNeedsReset;
-};
-
 class GrallocTextureHostOGL : public TextureHost
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
                             , public TextureHostOGL
 #endif
 {
   friend class GrallocBufferActor;
 public:
   GrallocTextureHostOGL(TextureFlags aFlags,
@@ -139,18 +71,16 @@ public:
   gl::GLContext* GetGLContext() const { return mCompositor ? mCompositor->gl() : nullptr; }
 
 private:
   void DestroyEGLImage();
 
   NewSurfaceDescriptorGralloc mGrallocHandle;
   RefPtr<GLTextureSource> mGLTextureSource;
   RefPtr<CompositorOGL> mCompositor;
-  // only used for tiling, will be removed.
-  RefPtr<GrallocTextureSourceOGL> mTilingTextureSource;
   // Size reported by the GraphicBuffer
   gfx::IntSize mSize;
   // Size reported by TextureClient, can be different in some cases (video?),
   // used by LayerRenderState.
   gfx::IntSize mDescriptorSize;
   gfx::SurfaceFormat mFormat;
   EGLImage mEGLImage;
   bool mIsOpaque;
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -22,21 +22,17 @@
 #include <math.h>
 #include <regex.h>
 #include <sched.h>
 #include <stdio.h>
 #include <sys/klog.h>
 #include <sys/syscall.h>
 #include <sys/resource.h>
 #include <time.h>
-#if ANDROID_VERSION >= 21
-#include <limits.h>
-#else
-#include <asm/page.h>
-#endif
+#include <unistd.h>
 
 #include "mozilla/DebugOnly.h"
 
 #include "android/log.h"
 #include "cutils/properties.h"
 #include "hardware/hardware.h"
 #include "hardware/lights.h"
 #include "hardware_legacy/uevent.h"
@@ -1316,16 +1312,18 @@ EnsureKernelLowMemKillerParamsSet()
   // Build the adj and minfree strings.
   nsAutoCString adjParams;
   nsAutoCString minfreeParams;
 
   int32_t lowerBoundOfNextOomScoreAdj = OOM_SCORE_ADJ_MIN - 1;
   int32_t lowerBoundOfNextKillUnderKB = 0;
   int32_t countOfLowmemorykillerParametersSets = 0;
 
+  long page_size = sysconf(_SC_PAGESIZE);
+
   for (int i = NUM_PROCESS_PRIORITY - 1; i >= 0; i--) {
     // The system doesn't function correctly if we're missing these prefs, so
     // crash loudly.
 
     ProcessPriority priority = static_cast<ProcessPriority>(i);
 
     int32_t oomScoreAdj;
     if (!NS_SUCCEEDED(Preferences::GetInt(
@@ -1353,17 +1351,17 @@ EnsureKernelLowMemKillerParamsSet()
 
     // The LMK in kernel only accept 6 sets of LMK parameters. See bug 914728.
     MOZ_ASSERT(countOfLowmemorykillerParametersSets < 6);
 
     // adj is in oom_adj units.
     adjParams.AppendPrintf("%d,", OomAdjOfOomScoreAdj(oomScoreAdj));
 
     // minfree is in pages.
-    minfreeParams.AppendPrintf("%d,", killUnderKB * 1024 / PAGE_SIZE);
+    minfreeParams.AppendPrintf("%ld,", killUnderKB * 1024 / page_size);
 
     lowerBoundOfNextOomScoreAdj = oomScoreAdj;
     lowerBoundOfNextKillUnderKB = killUnderKB;
     countOfLowmemorykillerParametersSets++;
   }
 
   // Strip off trailing commas.
   adjParams.Cut(adjParams.Length() - 1, 1);
@@ -1376,17 +1374,17 @@ EnsureKernelLowMemKillerParamsSet()
   // Set the low-memory-notification threshold.
   int32_t lowMemNotifyThresholdKB;
   if (NS_SUCCEEDED(Preferences::GetInt(
         "hal.processPriorityManager.gonk.notifyLowMemUnderKB",
         &lowMemNotifyThresholdKB))) {
 
     // notify_trigger is in pages.
     WriteToFile("/sys/module/lowmemorykiller/parameters/notify_trigger",
-      nsPrintfCString("%d", lowMemNotifyThresholdKB * 1024 / PAGE_SIZE).get());
+      nsPrintfCString("%ld", lowMemNotifyThresholdKB * 1024 / page_size).get());
   }
 
   // Ensure OOM events appear in logcat
   nsRefPtr<OomVictimLogger> oomLogger = new OomVictimLogger();
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     os->AddObserver(oomLogger, "ipc:content-shutdown", false);
   }
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2237,17 +2237,17 @@ LIRGenerator::visitLoadSlot(MLoadSlot *i
         defineBox(new(alloc()) LLoadSlotV(useRegisterAtStart(ins->slots())), ins);
         break;
 
       case MIRType_Undefined:
       case MIRType_Null:
         MOZ_CRASH("typed load must have a payload");
 
       default:
-        define(new(alloc()) LLoadSlotT(useRegisterAtStart(ins->slots())), ins);
+        define(new(alloc()) LLoadSlotT(useRegisterForTypedLoad(ins->slots(), ins->type())), ins);
         break;
     }
 }
 
 void
 LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment *ins)
 {
     define(new(alloc()) LFunctionEnvironment(useRegisterAtStart(ins->function())), ins);
@@ -3083,23 +3083,26 @@ LIRGenerator::visitStoreTypedArrayElemen
     else
         value = useRegisterOrNonDoubleConstant(ins->value());
     add(new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value), ins);
 }
 
 void
 LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot *ins)
 {
-    MOZ_ASSERT(ins->object()->type() == MIRType_Object);
-
-    if (ins->type() == MIRType_Value) {
-        LLoadFixedSlotV *lir = new(alloc()) LLoadFixedSlotV(useRegisterAtStart(ins->object()));
+    MDefinition *obj = ins->object();
+    MOZ_ASSERT(obj->type() == MIRType_Object);
+
+    MIRType type = ins->type();
+
+    if (type == MIRType_Value) {
+        LLoadFixedSlotV *lir = new(alloc()) LLoadFixedSlotV(useRegisterAtStart(obj));
         defineBox(lir, ins);
     } else {
-        LLoadFixedSlotT *lir = new(alloc()) LLoadFixedSlotT(useRegisterAtStart(ins->object()));
+        LLoadFixedSlotT *lir = new(alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type));
         define(lir, ins);
     }
 }
 
 void
 LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot *ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType_Object);
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -477,12 +477,29 @@ void
 LIRGeneratorShared::fillBoxUses(LInstruction *lir, size_t n, MDefinition *mir)
 {
     ensureDefined(mir);
     lir->getOperand(n)->toUse()->setVirtualRegister(mir->virtualRegister() + VREG_TYPE_OFFSET);
     lir->getOperand(n + 1)->toUse()->setVirtualRegister(VirtualRegisterOfPayload(mir));
 }
 #endif
 
+LUse
+LIRGeneratorShared::useRegisterForTypedLoad(MDefinition *mir, MIRType type)
+{
+    MOZ_ASSERT(type != MIRType_Value && type != MIRType_None);
+    MOZ_ASSERT(mir->type() == MIRType_Object || mir->type() == MIRType_Slots);
+
+#ifdef JS_PUNBOX64
+    // On x64, masm.loadUnboxedValue emits slightly less efficient code when
+    // the input and output use the same register and we're not loading an
+    // int32/bool/double, so we just call useRegister in this case.
+    if (type != MIRType_Int32 && type != MIRType_Boolean && type != MIRType_Double)
+        return useRegister(mir);
+#endif
+
+    return useRegisterAtStart(mir);
+}
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_shared_Lowering_shared_inl_h */
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -106,16 +106,18 @@ class LIRGeneratorShared : public MDefin
     inline LAllocation useStorable(MDefinition *mir);
     inline LAllocation useStorableAtStart(MDefinition *mir);
     inline LAllocation useKeepaliveOrConstant(MDefinition *mir);
     inline LAllocation useRegisterOrConstant(MDefinition *mir);
     inline LAllocation useRegisterOrConstantAtStart(MDefinition *mir);
     inline LAllocation useRegisterOrNonNegativeConstantAtStart(MDefinition *mir);
     inline LAllocation useRegisterOrNonDoubleConstant(MDefinition *mir);
 
+    inline LUse useRegisterForTypedLoad(MDefinition *mir, MIRType type);
+
 #ifdef JS_NUNBOX32
     inline LUse useType(MDefinition *mir, LUse::Policy policy);
     inline LUse usePayload(MDefinition *mir, LUse::Policy policy);
     inline LUse usePayloadAtStart(MDefinition *mir, LUse::Policy policy);
     inline LUse usePayloadInRegisterAtStart(MDefinition *mir);
 
     // Adds a box input to an instruction, setting operand |n| to the type and
     // |n+1| to the payload. Does not modify the operands, instead expecting a
deleted file mode 100644
--- a/js/xpconnect/tests/idl/Makefile.in
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include $(topsrcdir)/config/rules.mk
-
-componentdir = js/xpconnect/tests/components
-libs:: $(DEPTH)/config/makefiles/xpidl/xpt/$(XPT_NAME)
-	$(INSTALL) $^ $(testxpcobjdir)/$(componentdir)/native
-	$(INSTALL) $^ $(testxpcobjdir)/$(componentdir)/js
--- a/js/xpconnect/tests/idl/moz.build
+++ b/js/xpconnect/tests/idl/moz.build
@@ -9,8 +9,16 @@ XPIDL_SOURCES += [
     'xpctest_bug809674.idl',
     'xpctest_interfaces.idl',
     'xpctest_params.idl',
     'xpctest_returncode.idl',
 ]
 
 XPIDL_MODULE = 'xpctest'
 
+# XXX: This relies on xpctest.xpt being created in dist/bin/components/ during
+# the export tier AND TEST_HARNESS_FILES being processed after that.
+TEST_HARNESS_FILES.xpcshell.js.xpconnect.tests.components.native += [
+    '!/dist/bin/components/xpctest.xpt',
+]
+TEST_HARNESS_FILES.xpcshell.js.xpconnect.tests.components.js += [
+    '!/dist/bin/components/xpctest.xpt',
+]
--- a/mfbt/MathAlgorithms.h
+++ b/mfbt/MathAlgorithms.h
@@ -141,17 +141,17 @@ template<>
 inline long double
 Abs<long double>(const long double aLongDouble)
 {
   return std::fabs(aLongDouble);
 }
 
 } // namespace mozilla
 
-#if defined(_WIN32) && \
+#if defined(_MSC_VER) && \
     (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
 #  define MOZ_BITSCAN_WINDOWS
 
 #  include <intrin.h>
 #  pragma intrinsic(_BitScanForward, _BitScanReverse)
 
 #  if defined(_M_AMD64) || defined(_M_X64)
 #    define MOZ_BITSCAN_WINDOWS64
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -403,16 +403,18 @@
 @BINPATH@/components/TelemetryStartup.js
 @BINPATH@/components/TelemetryStartup.manifest
 @BINPATH@/components/XULStore.js
 @BINPATH@/components/XULStore.manifest
 @BINPATH@/components/Webapps.js
 @BINPATH@/components/Webapps.manifest
 @BINPATH@/components/AppsService.js
 @BINPATH@/components/AppsService.manifest
+@BINPATH@/components/htmlMenuBuilder.js
+@BINPATH@/components/htmlMenuBuilder.manifest
 
 @BINPATH@/components/Activities.manifest
 @BINPATH@/components/ActivitiesGlue.js
 @BINPATH@/components/ActivityProxy.js
 @BINPATH@/components/ActivityRequestHandler.js
 @BINPATH@/components/ActivityWrapper.js
 @BINPATH@/components/ActivityMessageConfigurator.js
 
--- a/netwerk/dns/effective_tld_names.dat
+++ b/netwerk/dns/effective_tld_names.dat
@@ -9228,17 +9228,17 @@ flynnhub.com
 github.io
 githubusercontent.com
 
 // GlobeHosting, Inc.
 // Submitted by Zoltan Egresi <egresi@globehosting.com> 2013-07-12
 ro.com
 
 // Google, Inc.
-// Submitted by Eduardo Vela <evn@google.com> 2012-10-24
+// Submitted by Eduardo Vela <evn@google.com> 2014-12-19
 appspot.com
 blogspot.ae
 blogspot.be
 blogspot.bj
 blogspot.ca
 blogspot.cf
 blogspot.ch
 blogspot.co.at
@@ -9276,16 +9276,17 @@ blogspot.ru
 blogspot.se
 blogspot.sg
 blogspot.sk
 blogspot.td
 blogspot.tw
 codespot.com
 googleapis.com
 googlecode.com
+pagespeedmobilizer.com
 withgoogle.com
 
 // Heroku : https://www.heroku.com/
 // Submitted by Tom Maher <tmaher@heroku.com> 2013-05-02
 herokuapp.com
 herokussl.com
 
 // iki.fi
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -2372,34 +2372,36 @@ nsHttpConnectionMgr::OnMsgReschedTransac
 
 void
 nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param));
 
     nsresult closeCode = static_cast<nsresult>(reason);
-    nsHttpTransaction *trans = (nsHttpTransaction *) param;
+    nsRefPtr<nsHttpTransaction> trans =
+        dont_AddRef(static_cast<nsHttpTransaction *>(param));
+
     //
     // if the transaction owns a connection and the transaction is not done,
     // then ask the connection to close the transaction.  otherwise, close the
     // transaction directly (removing it from the pending queue first).
     //
-    nsAHttpConnection *conn = trans->Connection();
+    nsRefPtr<nsAHttpConnection> conn(trans->Connection());
     if (conn && !trans->IsDone()) {
         conn->CloseTransaction(trans, closeCode);
     } else {
         nsConnectionEntry *ent =
             LookupConnectionEntry(trans->ConnectionInfo(), nullptr, trans);
 
         if (ent) {
             int32_t index = ent->mPendingQ.IndexOf(trans);
             if (index >= 0) {
                 LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
-                     " found in pending queue\n", trans));
+                     " found in pending queue\n", trans.get()));
                 ent->mPendingQ.RemoveElementAt(index);
                 nsHttpTransaction *temp = trans;
                 NS_RELEASE(temp); // b/c NS_RELEASE nulls its argument!
             }
 
             // Abandon all half-open sockets belonging to the given transaction.
             for (uint32_t index = 0;
                  index < ent->mHalfOpens.Length();
@@ -2424,22 +2426,21 @@ nsHttpConnectionMgr::OnMsgCancelTransact
         for (uint32_t index = 0;
              ent && (index < ent->mActiveConns.Length());
              ++index) {
             nsHttpConnection *activeConn = ent->mActiveConns[index];
             nsAHttpTransaction *liveTransaction = activeConn->Transaction();
             if (liveTransaction && liveTransaction->IsNullTransaction()) {
                 LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p] "
                      "also canceling Null Transaction %p on conn %p\n",
-                     trans, liveTransaction, activeConn));
+                     trans.get(), liveTransaction, activeConn));
                 activeConn->CloseTransaction(liveTransaction, closeCode);
             }
         }
     }
-    NS_RELEASE(trans);
 }
 
 void
 nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, void *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     nsHttpConnectionInfo *ci = (nsHttpConnectionInfo *) param;
 
--- a/python/mozbuild/mozbuild/backend/common.py
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -34,17 +34,17 @@ class XPIDLManager(object):
     def __init__(self, config):
         self.config = config
         self.topsrcdir = config.topsrcdir
         self.topobjdir = config.topobjdir
 
         self.idls = {}
         self.modules = {}
 
-    def register_idl(self, source, module, allow_existing=False):
+    def register_idl(self, source, module, install_target, allow_existing=False):
         """Registers an IDL file with this instance.
 
         The IDL file will be built, installed, etc.
         """
         basename = mozpath.basename(source)
         root = mozpath.splitext(basename)[0]
 
         entry = {
@@ -53,17 +53,18 @@ class XPIDLManager(object):
             'basename': basename,
             'root': root,
         }
 
         if not allow_existing and entry['basename'] in self.idls:
             raise Exception('IDL already registered: %' % entry['basename'])
 
         self.idls[entry['basename']] = entry
-        self.modules.setdefault(entry['module'], set()).add(entry['root'])
+        t = self.modules.setdefault(entry['module'], (install_target, set()))
+        t[1].add(entry['root'])
 
 
 class WebIDLCollection(object):
     """Collects WebIDL info referenced during the build."""
 
     def __init__(self):
         self.sources = set()
         self.generated_sources = set()
@@ -176,17 +177,18 @@ class CommonBackend(BuildBackend):
         self._configs.add(obj.config)
 
         if isinstance(obj, TestManifest):
             for test in obj.tests:
                 self._test_manager.add(test, flavor=obj.flavor,
                     topsrcdir=obj.topsrcdir)
 
         elif isinstance(obj, XPIDLFile):
-            self._idl_manager.register_idl(obj.source_path, obj.module)
+            self._idl_manager.register_idl(obj.source_path, obj.module,
+                obj.install_target)
 
         elif isinstance(obj, ConfigFileSubstitution):
             # Do not handle ConfigFileSubstitution for Makefiles. Leave that
             # to other
             if mozpath.basename(obj.output_path) == 'Makefile':
                 return
             with self._get_preprocessor(obj) as pp:
                 pp.do_include(obj.input_path)
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -1,30 +1,31 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import unicode_literals
 
+import errno
 import itertools
 import json
 import logging
 import os
 import re
 import types
 
 from collections import (
     defaultdict,
     namedtuple,
 )
+from StringIO import StringIO
 
 import mozwebidlcodegen
 from reftest import ReftestManifest
 
-import mozbuild.makeutil as mozmakeutil
 from mozpack.copier import FilePurger
 from mozpack.manifests import (
     InstallManifest,
 )
 import mozpack.path as mozpath
 
 from .common import CommonBackend
 from ..frontend.data import (
@@ -746,17 +747,17 @@ class RecursiveMakeBackend(CommonBackend
                             continue
                         if objdir == self.environment.topobjdir:
                             continue
                         self._no_skip['tools'].add(mozpath.relpath(objdir,
                             self.environment.topobjdir))
 
         # Write out a master list of all IPDL source files.
         ipdl_dir = mozpath.join(self.environment.topobjdir, 'ipc', 'ipdl')
-        mk = mozmakeutil.Makefile()
+        mk = Makefile()
 
         sorted_ipdl_sources = list(sorted(self._ipdl_sources))
         mk.add_statement('ALL_IPDLSRCS := %s' % ' '.join(sorted_ipdl_sources))
 
         def files_from(ipdl):
             base = mozpath.basename(ipdl)
             root, ext = mozpath.splitext(base)
 
@@ -978,72 +979,82 @@ INSTALL_TARGETS += %(prefix)s
         manifest = self._install_manifests['tests']
 
         for source, dest, _ in self._walk_hierarchy(obj, obj.modules):
             manifest.add_symlink(source, mozpath.join('modules', dest))
 
     def _handle_idl_manager(self, manager):
         build_files = self._install_manifests['xpidl']
 
-        for p in ('Makefile', 'backend.mk', '.deps/.mkdir.done',
-            'xpt/.mkdir.done'):
+        for p in ('Makefile', 'backend.mk', '.deps/.mkdir.done'):
             build_files.add_optional_exists(p)
 
         for idl in manager.idls.values():
             self._install_manifests['dist_idl'].add_symlink(idl['source'],
                 idl['basename'])
             self._install_manifests['dist_include'].add_optional_exists('%s.h'
                 % idl['root'])
 
         for module in manager.modules:
-            build_files.add_optional_exists(mozpath.join('xpt',
-                '%s.xpt' % module))
             build_files.add_optional_exists(mozpath.join('.deps',
                 '%s.pp' % module))
 
         modules = manager.modules
         xpt_modules = sorted(modules.keys())
-        rules = []
+        xpt_files = set()
+
+        mk = Makefile()
 
         for module in xpt_modules:
-            deps = sorted(modules[module])
-            idl_deps = ['$(dist_idl_dir)/%s.idl' % dep for dep in deps]
-            rules.extend([
-                # It may seem strange to have the .idl files listed as
-                # prerequisites both here and in the auto-generated .pp files.
-                # It is necessary to list them here to handle the case where a
-                # new .idl is added to an xpt. If we add a new .idl and nothing
-                # else has changed, the new .idl won't be referenced anywhere
-                # except in the command invocation. Therefore, the .xpt won't
-                # be rebuilt because the dependencies say it is up to date. By
-                # listing the .idls here, we ensure the make file has a
-                # reference to the new .idl. Since the new .idl presumably has
-                # an mtime newer than the .xpt, it will trigger xpt generation.
-                '$(idl_xpt_dir)/%s.xpt: %s' % (module, ' '.join(idl_deps)),
-                '\t@echo "$(notdir $@)"',
-                '\t$(idlprocess) $(basename $(notdir $@)) %s' % ' '.join(deps),
-                '',
-            ])
+            install_target, sources = modules[module]
+            deps = sorted(sources)
+
+            # It may seem strange to have the .idl files listed as
+            # prerequisites both here and in the auto-generated .pp files.
+            # It is necessary to list them here to handle the case where a
+            # new .idl is added to an xpt. If we add a new .idl and nothing
+            # else has changed, the new .idl won't be referenced anywhere
+            # except in the command invocation. Therefore, the .xpt won't
+            # be rebuilt because the dependencies say it is up to date. By
+            # listing the .idls here, we ensure the make file has a
+            # reference to the new .idl. Since the new .idl presumably has
+            # an mtime newer than the .xpt, it will trigger xpt generation.
+            xpt_path = '$(DEPTH)/%s/components/%s.xpt' % (install_target, module)
+            xpt_files.add(xpt_path)
+            rule = mk.create_rule([xpt_path])
+            rule.add_dependencies(['$(call mkdir_deps,%s)' % mozpath.dirname(xpt_path)])
+            rule.add_dependencies(manager.idls['%s.idl' % dep]['source'] for dep in deps)
+
+            if install_target.startswith('dist/'):
+                path = mozpath.relpath(xpt_path, '$(DEPTH)/dist')
+                prefix, subpath = path.split('/', 1)
+                key = 'dist_%s' % prefix
+
+                self._install_manifests[key].add_optional_exists(subpath)
+
+        rules = StringIO()
+        mk.dump(rules, removal_guard=False)
 
         # Create dependency for output header so we force regeneration if the
         # header was deleted. This ideally should not be necessary. However,
         # some processes (such as PGO at the time this was implemented) wipe
         # out dist/include without regard to our install manifests.
 
         obj = self.Substitution()
         obj.output_path = mozpath.join(self.environment.topobjdir, 'config',
             'makefiles', 'xpidl', 'Makefile')
         obj.input_path = mozpath.join(self.environment.topsrcdir, 'config',
             'makefiles', 'xpidl', 'Makefile.in')
         obj.topsrcdir = self.environment.topsrcdir
         obj.topobjdir = self.environment.topobjdir
         obj.config = self.environment
         self._create_makefile(obj, extra=dict(
-            xpidl_rules='\n'.join(rules),
+            xpidl_rules=rules.getvalue(),
             xpidl_modules=' '.join(xpt_modules),
+            xpt_files=' '.join(sorted(xpt_files)),
         ))
 
     def _process_program(self, program, backend_file):
         backend_file.write('PROGRAM = %s\n' % program)
 
     def _process_host_program(self, program, backend_file):
         backend_file.write('HOST_PROGRAM = %s\n' % program)
 
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -1156,17 +1156,17 @@ VARIABLES = {
         which subdirectory they should be exported to. For example,
         to export ``foo.py`` to ``_tests/foo``, append to
         ``TEST_HARNESS_FILES`` like so::
            TEST_HARNESS_FILES.foo += ['foo.py']
 
         Files from topsrcdir and the objdir can also be installed by prefixing
         the path(s) with a '/' character and a '!' character, respectively::
            TEST_HARNESS_FILES.path += ['/build/bar.py', '!quux.py']
-        """, None),
+        """, 'libs'),
 }
 
 # Sanity check: we don't want any variable above to have a list as storage type.
 for name, (storage_type, input_types, docs, tier) in VARIABLES.items():
     if storage_type == list:
         raise RuntimeError('%s has a "list" storage type. Use "List" instead.'
             % name)
 
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -152,26 +152,29 @@ class VariablePassthru(ContextDerived):
         ContextDerived.__init__(self, context)
         self.variables = {}
 
 class XPIDLFile(ContextDerived):
     """Describes an XPIDL file to be compiled."""
 
     __slots__ = (
         'basename',
+        'install_target',
         'source_path',
     )
 
     def __init__(self, context, source, module):
         ContextDerived.__init__(self, context)
 
         self.source_path = source
         self.basename = mozpath.basename(source)
         self.module = module
 
+        self.install_target = context['FINAL_TARGET']
+
 class Defines(ContextDerived):
     """Context derived container object for DEFINES, which is an OrderedDict.
     """
     __slots__ = ('defines')
 
     def __init__(self, context, defines):
         ContextDerived.__init__(self, context)
         self.defines = defines
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -340,16 +340,24 @@ class TreeMetadataEmitter(LoggingMixin):
         else:
             return ExternalSharedLibrary(context, name)
 
     def emit_from_context(self, context):
         """Convert a Context to tree metadata objects.
 
         This is a generator of mozbuild.frontend.data.ContextDerived instances.
         """
+
+        # We only want to emit an InstallationTarget if one of the consulted
+        # variables is defined. Later on, we look up FINAL_TARGET, which has
+        # the side-effect of populating it. So, we need to do this lookup
+        # early.
+        if any(k in context for k in ('FINAL_TARGET', 'XPI_NAME', 'DIST_SUBDIR')):
+            yield InstallationTarget(context)
+
         # We always emit a directory traversal descriptor. This is needed by
         # the recursive make backend.
         for o in self._emit_directory_traversal_from_context(context): yield o
 
         for path in context['CONFIGURE_SUBST_FILES']:
             yield self._create_substitution(ConfigFileSubstitution, context,
                 path)
 
@@ -518,19 +526,19 @@ class TreeMetadataEmitter(LoggingMixin):
             for path, strings in test_harness_files.walk():
                 if not path and strings:
                     raise SandboxValidationError(
                         'Cannot install files to the root of TEST_HARNESS_FILES', context)
 
                 for s in strings:
                     if context.is_objdir_path(s):
                         if s.startswith('!/'):
-                            raise SandboxValidationError(
-                                'Topobjdir-relative file not allowed in TEST_HARNESS_FILES: %s' % s, context)
-                        objdir_files[path].append(s[1:])
+                            objdir_files[path].append('$(DEPTH)/%s' % s[2:])
+                        else:
+                            objdir_files[path].append(s[1:])
                     else:
                         resolved = context.resolve_path(s)
                         if '*' in s:
                             srcdir_pattern_files[path].append(s);
                         elif not os.path.exists(resolved):
                             raise SandboxValidationError(
                                 'File listed in TEST_HARNESS_FILES does not exist: %s' % s, context)
                         else:
@@ -611,20 +619,16 @@ class TreeMetadataEmitter(LoggingMixin):
                 relative_include = local_include
 
             actual_include = os.path.join(path, relative_include)
             if not os.path.exists(actual_include):
                 raise SandboxValidationError('Path specified in LOCAL_INCLUDES '
                     'does not exist: %s (resolved to %s)' % (local_include, actual_include), context)
             yield LocalInclude(context, local_include)
 
-        if context.get('FINAL_TARGET') or context.get('XPI_NAME') or \
-                context.get('DIST_SUBDIR'):
-            yield InstallationTarget(context)
-
         final_target_files = context.get('FINAL_TARGET_FILES')
         if final_target_files:
             yield FinalTargetFiles(context, final_target_files, context['FINAL_TARGET'])
 
         host_libname = context.get('HOST_LIBRARY_NAME')
         libname = context.get('LIBRARY_NAME')
 
         if host_libname:
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -438,17 +438,19 @@ class TestRecursiveMakeBackend(BackendTe
 
         m = InstallManifest(path=mozpath.join(install_dir, 'dist_idl'))
         self.assertEqual(len(m), 2)
         self.assertIn('bar.idl', m)
         self.assertIn('foo.idl', m)
 
         m = InstallManifest(path=mozpath.join(install_dir, 'xpidl'))
         self.assertIn('.deps/my_module.pp', m)
-        self.assertIn('xpt/my_module.xpt', m)
+
+        m = InstallManifest(path=os.path.join(install_dir, 'dist_bin'))
+        self.assertIn('components/my_module.xpt', m)
 
         m = InstallManifest(path=mozpath.join(install_dir, 'dist_include'))
         self.assertIn('foo.h', m)
 
         p = mozpath.join(env.topobjdir, 'config/makefiles/xpidl')
         self.assertTrue(os.path.isdir(p))
 
         self.assertTrue(os.path.isfile(mozpath.join(p, 'Makefile')))
--- a/toolkit/modules/PageMenu.jsm
+++ b/toolkit/modules/PageMenu.jsm
@@ -1,141 +1,313 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-this.EXPORTED_SYMBOLS = ["PageMenu"];
+this.EXPORTED_SYMBOLS = ["PageMenuParent", "PageMenuChild"];
 
 this.PageMenu = function PageMenu() {
 }
 
 PageMenu.prototype = {
   PAGEMENU_ATTR: "pagemenu",
   GENERATEDITEMID_ATTR: "generateditemid",
 
-  popup: null,
-  builder: null,
+  _popup: null,
+
+  // Only one of builder or browser will end up getting set.
+  _builder: null,
+  _browser: null,
 
-  maybeBuildAndAttachMenu: function(aTarget, aPopup) {
-    var pageMenu = null;
-    var target = aTarget;
+  // Given a target node, get the context menu for it or its ancestor.
+  getContextMenu: function(aTarget) {
+    let pageMenu = null;
+    let target = aTarget;
     while (target) {
-      var contextMenu = target.contextMenu;
+      let contextMenu = target.contextMenu;
       if (contextMenu) {
-        pageMenu = contextMenu;
-        break;
+        return contextMenu;
       }
       target = target.parentNode;
     }
 
-    if (!pageMenu) {
-      return false;
-    }
+    return null;
+  },
 
-    var insertionPoint = this.getInsertionPoint(aPopup);
-    if (!insertionPoint) {
-      return false;
+  // Given a target node, generate a JSON object for any context menu
+  // associated with it, or null if there is no context menu.
+  maybeBuild: function(aTarget) {
+    let pageMenu = this.getContextMenu(aTarget);
+    if (!pageMenu) {
+      return null;
     }
 
     pageMenu.QueryInterface(Components.interfaces.nsIHTMLMenu);
     pageMenu.sendShowEvent();
     // the show event is not cancelable, so no need to check a result here
 
-    var fragment = aPopup.ownerDocument.createDocumentFragment();
+    this._builder = pageMenu.createBuilder();
+    if (!this._builder) {
+      return null;
+    }
+
+    pageMenu.build(this._builder);
 
-    var builder = pageMenu.createBuilder();
-    if (!builder) {
+    // This serializes then parses again, however this could be avoided in
+    // the single-process case with further improvement.
+    let menuString = this._builder.toJSONString();
+    if (!menuString) {
+      return null;
+    }
+
+    return JSON.parse(menuString);
+  },
+
+  // Given a JSON menu object and popup, add the context menu to the popup.
+  buildAndAttachMenuWithObject: function(aMenu, aBrowser, aPopup) {
+    if (!aMenu) {
       return false;
     }
-    builder.QueryInterface(Components.interfaces.nsIXULContextMenuBuilder);
-    builder.init(fragment, this.GENERATEDITEMID_ATTR);
 
-    pageMenu.build(builder);
+    let insertionPoint = this.getInsertionPoint(aPopup);
+    if (!insertionPoint) {
+      return false;
+    }
 
-    var pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR);
+    let fragment = aPopup.ownerDocument.createDocumentFragment();
+    this.buildXULMenu(aMenu, fragment);
+
+    let pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR);
     if (pos == "start") {
       insertionPoint.insertBefore(fragment,
                                   insertionPoint.firstChild);
     } else if (pos.startsWith("#")) {
       insertionPoint.insertBefore(fragment, insertionPoint.querySelector(pos));
     } else {
       insertionPoint.appendChild(fragment);
     }
 
-    this.builder = builder;
-    this.popup = aPopup;
+    this._browser = aBrowser;
+    this._popup = aPopup;
 
-    this.popup.addEventListener("command", this);
-    this.popup.addEventListener("popuphidden", this);
+    this._popup.addEventListener("command", this);
+    this._popup.addEventListener("popuphidden", this);
 
     return true;
   },
 
-  handleEvent: function(event) {
-    var type = event.type;
-    var target = event.target;
-    if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) {
-      this.builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR));
-    } else if (type == "popuphidden" && this.popup == target) {
-      this.removeGeneratedContent(this.popup);
+  // Construct the XUL menu structure for a given JSON object.
+  buildXULMenu: function(aNode, aElementForAppending) {
+    let document = aElementForAppending.ownerDocument;
+
+    let children = aNode.children;
+    for (let child of children) {
+      let menuitem;
+      switch (child.type) {
+        case "menuitem":
+          if (!child.id) {
+            continue; // Ignore children without ids
+          }
+
+          menuitem = document.createElement("menuitem");
+          if (child.checkbox) {
+            menuitem.setAttribute("type", "checkbox");
+            if (child.checked) {
+              menuitem.setAttribute("checked", "true");
+            }
+          }
 
-      this.popup.removeEventListener("popuphidden", this);
-      this.popup.removeEventListener("command", this);
+          if (child.label) {
+            menuitem.setAttribute("label", child.label);
+          }
+          if (child.icon) {
+            menuitem.setAttribute("image", child.icon);
+            menuitem.className = "menuitem-iconic";
+          }
+          if (child.disabled) {
+            menuitem.setAttribute("disabled", true);
+          }
+
+          break;
 
-      this.popup = null;
-      this.builder = null;
+        case "separator":
+          menuitem = document.createElement("menuseparator");
+          break;
+
+        case "menu":
+          menuitem = document.createElement("menu");
+          if (child.label) {
+            menuitem.setAttribute("label", child.label);
+          }
+
+          let menupopup = document.createElement("menupopup");
+          menuitem.appendChild(menupopup);
+
+          this.buildXULMenu(child, menupopup);
+          break;
+      }
+
+      menuitem.setAttribute(this.GENERATEDITEMID_ATTR, child.id ? child.id : 0);
+      aElementForAppending.appendChild(menuitem);
     }
   },
 
+  // Called when the generated menuitem is executed.
+  handleEvent: function(event) {
+    let type = event.type;
+    let target = event.target;
+    if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) {
+      // If a builder is assigned, call click on it directly. Otherwise, this is
+      // likely a menu with data from another process, so send a message to the
+      // browser to execute the menuitem.
+      if (this._builder) {
+        this._builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR));
+      }
+      else if (this._browser) {
+        this._browser.messageManager.sendAsyncMessage("ContextMenu:DoCustomCommand",
+          target.getAttribute(this.GENERATEDITEMID_ATTR));
+      }
+    } else if (type == "popuphidden" && this._popup == target) {
+      this.removeGeneratedContent(this._popup);
+
+      this._popup.removeEventListener("popuphidden", this);
+      this._popup.removeEventListener("command", this);
+
+      this._popup = null;
+      this._builder = null;
+      this._browser = null;
+    }
+  },
+
+  // Get the first child of the given element with the given tag name.
   getImmediateChild: function(element, tag) {
-    var child = element.firstChild;
+    let child = element.firstChild;
     while (child) {
       if (child.localName == tag) {
         return child;
       }
       child = child.nextSibling;
     }
     return null;
   },
 
+  // Return the location where the generated items should be inserted into the
+  // given popup. They should be inserted as the next sibling of the returned
+  // element.
   getInsertionPoint: function(aPopup) {
     if (aPopup.hasAttribute(this.PAGEMENU_ATTR))
       return aPopup;
 
-    var element = aPopup.firstChild;
+    let element = aPopup.firstChild;
     while (element) {
       if (element.localName == "menu") {
-        var popup = this.getImmediateChild(element, "menupopup");
+        let popup = this.getImmediateChild(element, "menupopup");
         if (popup) {
-          var result = this.getInsertionPoint(popup);
+          let result = this.getInsertionPoint(popup);
           if (result) {
             return result;
           }
         }
       }
       element = element.nextSibling;
     }
 
     return null;
   },
 
+  // Remove the generated content from the given popup.
   removeGeneratedContent: function(aPopup) {
-    var ungenerated = [];
+    let ungenerated = [];
     ungenerated.push(aPopup);
 
-    var count;
+    let count;
     while (0 != (count = ungenerated.length)) {
-      var last = count - 1;
-      var element = ungenerated[last];
+      let last = count - 1;
+      let element = ungenerated[last];
       ungenerated.splice(last, 1);
 
-      var i = element.childNodes.length;
+      let i = element.childNodes.length;
       while (i-- > 0) {
-        var child = element.childNodes[i];
+        let child = element.childNodes[i];
         if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) {
           ungenerated.push(child);
           continue;
         }
         element.removeChild(child);
       }
     }
   }
 }
+
+// This object is expected to be used from a parent process.
+this.PageMenuParent = function PageMenuParent() {
+}
+
+PageMenuParent.prototype = {
+  __proto__ : PageMenu.prototype,
+
+  /*
+   * Given a target node and popup, add the context menu to the popup. This is
+   * intended to be called when a single process is used. This is equivalent to
+   * calling PageMenuChild.build and PageMenuParent.addToPopup in sequence.
+   *
+   * Returns true if custom menu items were present.
+   */
+  buildAndAddToPopup: function(aTarget, aPopup) {
+    let menuObject = this.maybeBuild(aTarget);
+    if (!menuObject) {
+      return false;
+    }
+
+    return this.buildAndAttachMenuWithObject(menuObject, null, aPopup);
+  },
+
+  /*
+   * Given a JSON menu object and popup, add the context menu to the popup. This
+   * is intended to be called when the child page is in a different process.
+   * aBrowser should be the browser containing the page the context menu is
+   * displayed for, which may be null.
+   *
+   * Returns true if custom menu items were present.
+   */
+  addToPopup: function(aMenu, aBrowser, aPopup) {
+    return this.buildAndAttachMenuWithObject(aMenu, aBrowser, aPopup);
+  }
+}
+
+// This object is expected to be used from a child process.
+this.PageMenuChild = function PageMenuChild() {
+}
+
+PageMenuChild.prototype = {
+  __proto__ : PageMenu.prototype,
+
+  /*
+   * Given a target node, return a JSON object for the custom menu commands. The
+   * object will consist of a hierarchical structure of menus, menuitems or
+   * separators. Supported properties of each are:
+   *   Menu: children, label, type="menu"
+   *   Menuitems: checkbox, checked, disabled, icon, label, type="menuitem"
+   *   Separators: type="separator"
+   *
+   * In addition, the id of each item will be used to identify the item
+   * when it is executed. The type will either be 'menu', 'menuitem' or
+   * 'separator'. The toplevel node will be a menu with a children property. The
+   * children property of a menu is an array of zero or more other items.
+   *
+   * If there is no menu associated with aTarget, null will be returned.
+   */
+  build: function(aTarget) {
+    return this.maybeBuild(aTarget);
+  },
+
+  /*
+   * Given the id of a menu, execute the command associated with that menu. It
+   * is assumed that only one command will be executed so the builder is
+   * cleared afterwards.
+   */
+  executeMenu: function(aId) {
+    if (this._builder) {
+      this._builder.click(aId);
+      this._builder = null;
+    }
+  }
+}