diff --git a/CLOBBER b/CLOBBER index 37b2285a1c32..d15932f19fab 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,9 +22,4 @@ # 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. diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 59ace3c21438..024bbc6d7b06 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -401,6 +401,8 @@ @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 diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index d6e4b1de03a3..c886033e57ed 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -259,10 +259,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter", "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(); }); /** diff --git a/browser/base/content/content.js b/browser/base/content/content.js index b2356a6fe4e7..9fc0fd64847e 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -43,6 +43,11 @@ XPCOMUtils.defineLazyGetter(this, "SimpleServiceDiscovery", function() { }); 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; @@ -102,6 +107,10 @@ addMessageListener("SecondScreen:tab-mirror", function(message) { } }); +addMessageListener("ContextMenu:DoCustomCommand", function(message) { + PageMenuChild.executeMenu(message.data); +}); + addEventListener("DOMFormHasPassword", function(event) { InsecurePasswordUtils.checkForInsecurePasswords(event.target); LoginManagerContent.onFormPassword(event); @@ -148,7 +157,8 @@ let handleContentContextMenu = function (event) { 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 diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 4dc54af0cdcc..196882fd942f 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -24,10 +24,15 @@ nsContextMenu.prototype = { 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"); @@ -1766,7 +1771,7 @@ nsContextMenu.prototype = { } // 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, ""); diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index b081551681c6..87d36f9722f0 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3175,6 +3175,7 @@ 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; diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 7322e5b95d66..a1232ad10570 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -72,6 +72,7 @@ support-files = redirect_bug623155.sjs searchSuggestionEngine.sjs searchSuggestionEngine.xml + subtst_contextmenu.html test-mixedcontent-securityerrors.html test_bug435035.html test_bug462673.html @@ -486,4 +487,5 @@ skip-if = e10s # bug 1100687 - test directly manipulates content (content.docume [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] diff --git a/browser/base/content/test/general/browser_contextmenu_childprocess.js b/browser/base/content/test/general/browser_contextmenu_childprocess.js new file mode 100644 index 000000000000..c967137919ff --- /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); +} diff --git a/browser/base/content/test/general/test_contextmenu.html b/browser/base/content/test/general/test_contextmenu.html index edb7c705d502..c87ae2b5c40e 100644 --- a/browser/base/content/test/general/test_contextmenu.html +++ b/browser/base/content/test/general/test_contextmenu.html @@ -495,7 +495,7 @@ function runTest(testNum) { "context-viewinfo", true ].concat(inspectItems)); - invokeItemAction("0"); + invokeItemAction("1"); closeContextMenu(); // run mozRequestFullScreen on the element we're testing diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 0feaf0fe704f..a2f944bb616d 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -542,6 +542,8 @@ @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 diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index 679c3ef0b67e..c7cb1a39413b 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -77,7 +77,7 @@ 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 diff --git a/config/config.mk b/config/config.mk index 948a71af2092..141dda16fa5f 100644 --- a/config/config.mk +++ b/config/config.mk @@ -614,6 +614,13 @@ 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 diff --git a/config/makefiles/xpidl/Makefile.in b/config/makefiles/xpidl/Makefile.in index 178b7f2168f9..2c2b1b76627b 100644 --- a/config/makefiles/xpidl/Makefile.in +++ b/config/makefiles/xpidl/Makefile.in @@ -22,48 +22,39 @@ include $(topsrcdir)/config/rules.mk # 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 -# 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 +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. +%.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)) diff --git a/config/rules.mk b/config/rules.mk index cec5deec5eeb..f5f21f5a13a4 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1157,11 +1157,6 @@ endif 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)') diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 5fe40e37cd7a..f1f66db2f044 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -819,7 +819,12 @@ 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 request = mRequest.forget(); + nsRefPtr loader = mLoader.forget(); + + nsresult rv = loader->ProcessOffThreadRequest(request, &mToken); if (mToken) { // The result of the off thread parse was not actually needed to process diff --git a/dom/html/HTMLMenuElement.cpp b/dom/html/HTMLMenuElement.cpp index 8553534119f5..a15e7d0ea79f 100644 --- a/dom/html/HTMLMenuElement.cpp +++ b/dom/html/HTMLMenuElement.cpp @@ -9,11 +9,13 @@ #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 { @@ -97,12 +99,8 @@ 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 builder = CreateBuilder(); + builder.swap(*_retval); return NS_OK; } @@ -113,8 +111,9 @@ HTMLMenuElement::CreateBuilder() return nullptr; } - nsCOMPtr ret = new nsXULContextMenuBuilder(); - return ret.forget(); + nsCOMPtr builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID); + NS_WARN_IF(!builder); + return builder.forget(); } NS_IMETHODIMP diff --git a/dom/html/htmlMenuBuilder.js b/dom/html/htmlMenuBuilder.js new file mode 100644 index 000000000000..863fc4d74b13 --- /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]); diff --git a/dom/html/htmlMenuBuilder.manifest b/dom/html/htmlMenuBuilder.manifest new file mode 100644 index 000000000000..b245f8fe2de5 --- /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} + diff --git a/dom/html/moz.build b/dom/html/moz.build index cd725e70d2a4..97f6d1799026 100644 --- a/dom/html/moz.build +++ b/dom/html/moz.build @@ -215,6 +215,11 @@ SOURCES += [ 'PluginDocument.cpp', ] +EXTRA_COMPONENTS += [ + 'htmlMenuBuilder.js', + 'htmlMenuBuilder.manifest' +] + FAIL_ON_WARNINGS = True MSVC_ENABLE_PGO = True diff --git a/dom/html/nsIMenuBuilder.idl b/dom/html/nsIMenuBuilder.idl index a925fbcb709e..02664480fa46 100644 --- a/dom/html/nsIMenuBuilder.idl +++ b/dom/html/nsIMenuBuilder.idl @@ -11,7 +11,7 @@ interface nsIDOMHTMLMenuItemElement; * An interface used to construct native toolbar or context menus from */ -[scriptable, uuid(12724737-f7db-43b4-94ab-708a7b86e115)] +[scriptable, uuid(93F4A48F-D043-4F45-97FD-9771EA1AF976)] interface nsIMenuBuilder : nsISupports { @@ -49,4 +49,28 @@ interface nsIMenuBuilder : nsISupports */ 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); }; diff --git a/dom/media/gstreamer/GStreamerReader.cpp b/dom/media/gstreamer/GStreamerReader.cpp index d80901ec3e08..4fdd44b4c4e3 100644 --- a/dom/media/gstreamer/GStreamerReader.cpp +++ b/dom/media/gstreamer/GStreamerReader.cpp @@ -70,6 +70,7 @@ GStreamerReader::GStreamerReader(AbstractMediaDecoder* aDecoder) mMP3FrameParser(aDecoder->GetResource()->GetLength()), mDataOffset(0), mUseParserDuration(false), + mLastParserDuration(-1), #if GST_VERSION_MAJOR >= 1 mAllocator(nullptr), mBufferPool(nullptr), diff --git a/dom/media/webaudio/AudioBufferSourceNode.cpp b/dom/media/webaudio/AudioBufferSourceNode.cpp index cd8df5566c47..ceed1a3988c7 100644 --- a/dom/media/webaudio/AudioBufferSourceNode.cpp +++ b/dom/media/webaudio/AudioBufferSourceNode.cpp @@ -7,6 +7,7 @@ #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" @@ -110,7 +111,7 @@ public: 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."); @@ -415,7 +416,7 @@ public: } else { playbackRate = mPlaybackRateTimeline.GetValueAtTime(mSource->GetCurrentPosition()); } - if (playbackRate <= 0 || playbackRate != playbackRate) { + if (playbackRate <= 0 || mozilla::IsNaN(playbackRate)) { playbackRate = 1.0f; } diff --git a/dom/media/webaudio/WebAudioUtils.h b/dom/media/webaudio/WebAudioUtils.h index ee22ea07e21d..baaa373535c8 100644 --- a/dom/media/webaudio/WebAudioUtils.h +++ b/dom/media/webaudio/WebAudioUtils.h @@ -181,7 +181,7 @@ namespace WebAudioUtils { static_assert(mozilla::IsFloatingPoint::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"); diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp index a885ceb96675..4dcc4a39ee5c 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp @@ -691,40 +691,72 @@ MediaEngineGonkVideoSource::RotateImage(layers::Image* aImage, uint32_t aWidth, gfx::BackendType::NONE, layers::TextureFlags::DEFAULT, layers::ALLOC_DISALLOW_BUFFERTEXTURECLIENT); - if (!textureClient) { - return; + if (textureClient) { + RefPtr grallocTextureClient = + static_cast(textureClient.get()); + + android::sp destBuffer = grallocTextureClient->GetGraphicBuffer(); + + void* destMem = nullptr; + destBuffer->lock(android::GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destMem); + uint8_t* dstPtr = static_cast(destMem); + + 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(mRotation), + libyuv::FOURCC_NV21); + destBuffer->unlock(); + + layers::GrallocImage::GrallocData data; + + 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(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(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); } - RefPtr grallocTextureClient = - static_cast(textureClient.get()); - - android::sp destBuffer = grallocTextureClient->GetGraphicBuffer(); - - void* destMem = nullptr; - destBuffer->lock(android::GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destMem); - uint8_t* dstPtr = static_cast(destMem); - - 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(mRotation), - libyuv::FOURCC_NV21); - destBuffer->unlock(); 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(); } @@ -767,9 +799,14 @@ MediaEngineGonkVideoSource::OnNewMediaBufferFrame(MediaBuffer* aBuffer) MonitorAutoLock enter(mMonitor); if (mImage) { - GonkCameraImage* cameraImage = static_cast(mImage.get()); - - cameraImage->SetBuffer(aBuffer); + if (mImage->AsGrallocImage()) { + // MediaEngineGonkVideoSource expects that GrallocImage is GonkCameraImage. + // See Bug 938034. + GonkCameraImage* cameraImage = static_cast(mImage.get()); + cameraImage->SetBuffer(aBuffer); + } else { + LOG(("mImage is non-GrallocImage")); + } uint32_t len = mSources.Length(); for (uint32_t i = 0; i < len; i++) { @@ -780,12 +817,15 @@ MediaEngineGonkVideoSource::OnNewMediaBufferFrame(MediaBuffer* aBuffer) // 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(mImage.get()); + // Clear MediaBuffer immediately, it prevents MediaBuffer is kept in + // MediaStreamGraph thread. + cameraImage->ClearBuffer(); + } } return NS_OK; diff --git a/dom/webidl/HTMLMenuElement.webidl b/dom/webidl/HTMLMenuElement.webidl index 5ee2e66e3790..ff81a7c80d23 100644 --- a/dom/webidl/HTMLMenuElement.webidl +++ b/dom/webidl/HTMLMenuElement.webidl @@ -40,11 +40,11 @@ partial interface HTMLMenuElement { /** * 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. diff --git a/dom/xul/moz.build b/dom/xul/moz.build index 62315cd7cfc5..a316ca9397ec 100644 --- a/dom/xul/moz.build +++ b/dom/xul/moz.build @@ -12,7 +12,6 @@ if CONFIG['MOZ_XUL']: DIRS += ['templates'] XPIDL_SOURCES += [ - 'nsIXULContextMenuBuilder.idl', 'nsIXULOverlayProvider.idl', ] @@ -23,7 +22,6 @@ if CONFIG['MOZ_XUL']: UNIFIED_SOURCES += [ 'nsXULCommandDispatcher.cpp', 'nsXULContentSink.cpp', - 'nsXULContextMenuBuilder.cpp', 'nsXULElement.cpp', 'nsXULPopupListener.cpp', 'nsXULPrototypeCache.cpp', diff --git a/dom/xul/nsIXULContextMenuBuilder.idl b/dom/xul/nsIXULContextMenuBuilder.idl deleted file mode 100644 index 1f5070393f6f..000000000000 --- 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); - -}; diff --git a/dom/xul/nsXULContextMenuBuilder.cpp b/dom/xul/nsXULContextMenuBuilder.cpp deleted file mode 100644 index e6d9d5602c9e..000000000000 --- 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 menu; - nsresult rv = CreateElement(nsGkAtoms::menu, nullptr, getter_AddRefs(menu)); - NS_ENSURE_SUCCESS(rv, rv); - - menu->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aLabel, false); - - nsCOMPtr 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 menuitem; - nsCOMPtr 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 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 element = mElements.SafeObjectAt(idx); - if (element) { - element->DOMClick(); - } - } - - return NS_OK; -} - -nsresult -nsXULContextMenuBuilder::CreateElement(nsIAtom* aTag, - nsIDOMHTMLElement* aHTMLElement, - Element** aResult) -{ - *aResult = nullptr; - - nsRefPtr 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; -} diff --git a/dom/xul/nsXULContextMenuBuilder.h b/dom/xul/nsXULContextMenuBuilder.h deleted file mode 100644 index 83e19cb99dab..000000000000 --- 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 mFragment; - nsCOMPtr mDocument; - nsCOMPtr mGeneratedItemIdAttr; - - nsCOMPtr mCurrentNode; - int32_t mCurrentGeneratedItemId; - - nsCOMArray mElements; -}; diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 2795f2d7a5d9..0b4cf6ed6042 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -216,7 +216,7 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics( 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; } diff --git a/gfx/layers/opengl/GrallocTextureHost.cpp b/gfx/layers/opengl/GrallocTextureHost.cpp index 3df82b18a710..ee1f60822f9c 100644 --- a/gfx/layers/opengl/GrallocTextureHost.cpp +++ b/gfx/layers/opengl/GrallocTextureHost.cpp @@ -96,150 +96,6 @@ TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat) } } -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(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) @@ -272,9 +128,6 @@ void GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor) { mCompositor = static_cast(aCompositor); - if (mTilingTextureSource) { - mTilingTextureSource->SetCompositor(mCompositor); - } if (mGLTextureSource) { mGLTextureSource->SetCompositor(mCompositor); } @@ -312,10 +165,6 @@ GrallocTextureHostOGL::GetFormat() const void GrallocTextureHostOGL::DeallocateSharedData() { - if (mTilingTextureSource) { - mTilingTextureSource->ForgetBuffer(); - mTilingTextureSource = nullptr; - } if (mGLTextureSource) { mGLTextureSource = nullptr; } @@ -339,10 +188,6 @@ GrallocTextureHostOGL::DeallocateSharedData() void GrallocTextureHostOGL::ForgetSharedData() { - if (mTilingTextureSource) { - mTilingTextureSource->ForgetBuffer(); - mTilingTextureSource = nullptr; - } if (mGLTextureSource) { mGLTextureSource = nullptr; } @@ -351,9 +196,6 @@ GrallocTextureHostOGL::ForgetSharedData() void GrallocTextureHostOGL::DeallocateDeviceData() { - if (mTilingTextureSource) { - mTilingTextureSource->DeallocateDeviceData(); - } if (mGLTextureSource) { mGLTextureSource = nullptr; } @@ -387,77 +229,24 @@ GrallocTextureHostOGL::GetRenderState() TemporaryRef 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(&grallocData)); - RefPtr grallocTempSurf = - gfx::Factory::CreateWrappingDataSourceSurface(grallocData, - graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()), - GetSize(), GetFormat()); - RefPtr surf = CreateDataSourceSurfaceByCloning(grallocTempSurf); - - graphicBuffer->unlock(); - - return surf.forget(); - } -} - -TemporaryRef -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(&grallocData)); - if (rv) { - return nullptr; - } - + int32_t rv = graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast(&grallocData)); RefPtr grallocTempSurf = gfx::Factory::CreateWrappingDataSourceSurface(grallocData, - mGraphicBuffer->getStride() * android::bytesPerPixel(mGraphicBuffer->getPixelFormat()), + graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()), GetSize(), GetFormat()); - RefPtr 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 @@ -529,8 +318,6 @@ GrallocTextureHostOGL::PrepareTextureSource(CompositableTextureSourceRef& aTextu // 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); diff --git a/gfx/layers/opengl/GrallocTextureHost.h b/gfx/layers/opengl/GrallocTextureHost.h index 56290658f8d3..24565ff7d816 100644 --- a/gfx/layers/opengl/GrallocTextureHost.h +++ b/gfx/layers/opengl/GrallocTextureHost.h @@ -15,74 +15,6 @@ 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 GetAsSurface(); - - GLuint GetGLTexture(); - - void BindEGLImage(); - - EGLImage GetEGLImage() - { - return mEGLImage; - } - - bool Lock(); - -protected: - RefPtr mCompositor; - GrallocTextureHostOGL* mTextureHost; - android::sp mGraphicBuffer; - EGLImage mEGLImage; - GLuint mTexture; - gfx::SurfaceFormat mFormat; - bool mNeedsReset; -}; - class GrallocTextureHostOGL : public TextureHost #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 , public TextureHostOGL @@ -144,8 +76,6 @@ private: NewSurfaceDescriptorGralloc mGrallocHandle; RefPtr mGLTextureSource; RefPtr mCompositor; - // only used for tiling, will be removed. - RefPtr mTilingTextureSource; // Size reported by the GraphicBuffer gfx::IntSize mSize; // Size reported by TextureClient, can be different in some cases (video?), diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index 69b40766f289..15a442da0847 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -27,11 +27,7 @@ #include #include #include -#if ANDROID_VERSION >= 21 -#include -#else -#include -#endif +#include #include "mozilla/DebugOnly.h" @@ -1321,6 +1317,8 @@ EnsureKernelLowMemKillerParamsSet() 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. @@ -1358,7 +1356,7 @@ EnsureKernelLowMemKillerParamsSet() 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; @@ -1381,7 +1379,7 @@ EnsureKernelLowMemKillerParamsSet() // 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 diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 1d724cf4fc9b..5ef521d52188 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2242,7 +2242,7 @@ LIRGenerator::visitLoadSlot(MLoadSlot *ins) 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; } } @@ -3088,13 +3088,16 @@ LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole *ins) void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot *ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); + MDefinition *obj = ins->object(); + MOZ_ASSERT(obj->type() == MIRType_Object); - if (ins->type() == MIRType_Value) { - LLoadFixedSlotV *lir = new(alloc()) LLoadFixedSlotV(useRegisterAtStart(ins->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); } } diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index 38aa8c398d8f..e2ba7f10cc1c 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -482,6 +482,23 @@ LIRGeneratorShared::fillBoxUses(LInstruction *lir, size_t n, MDefinition *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 diff --git a/js/src/jit/shared/Lowering-shared.h b/js/src/jit/shared/Lowering-shared.h index f22b81864f51..98e86fda0834 100644 --- a/js/src/jit/shared/Lowering-shared.h +++ b/js/src/jit/shared/Lowering-shared.h @@ -111,6 +111,8 @@ class LIRGeneratorShared : public MDefinitionVisitor 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); diff --git a/js/xpconnect/tests/idl/Makefile.in b/js/xpconnect/tests/idl/Makefile.in deleted file mode 100644 index 5603df2a1320..000000000000 --- 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 diff --git a/js/xpconnect/tests/idl/moz.build b/js/xpconnect/tests/idl/moz.build index 1b55e03ae1e3..71aee0d47b0e 100644 --- a/js/xpconnect/tests/idl/moz.build +++ b/js/xpconnect/tests/idl/moz.build @@ -14,3 +14,11 @@ XPIDL_SOURCES += [ 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', +] diff --git a/mfbt/MathAlgorithms.h b/mfbt/MathAlgorithms.h index abfc2184847e..41be25960fb3 100644 --- a/mfbt/MathAlgorithms.h +++ b/mfbt/MathAlgorithms.h @@ -146,7 +146,7 @@ Abs(const long double aLongDouble) } // namespace mozilla -#if defined(_WIN32) && \ +#if defined(_MSC_VER) && \ (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) # define MOZ_BITSCAN_WINDOWS diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index bccdc4c56b66..60f807f6f8da 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -408,6 +408,8 @@ @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 diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat index 857110554315..06944edb5841 100644 --- a/netwerk/dns/effective_tld_names.dat +++ b/netwerk/dns/effective_tld_names.dat @@ -9233,7 +9233,7 @@ githubusercontent.com ro.com // Google, Inc. -// Submitted by Eduardo Vela 2012-10-24 +// Submitted by Eduardo Vela 2014-12-19 appspot.com blogspot.ae blogspot.be @@ -9281,6 +9281,7 @@ blogspot.tw codespot.com googleapis.com googlecode.com +pagespeedmobilizer.com withgoogle.com // Heroku : https://www.heroku.com/ diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index 7a46a22448ef..750dfafea8ba 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -2377,13 +2377,15 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param) LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param)); nsresult closeCode = static_cast(reason); - nsHttpTransaction *trans = (nsHttpTransaction *) param; + nsRefPtr trans = + dont_AddRef(static_cast(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 conn(trans->Connection()); if (conn && !trans->IsDone()) { conn->CloseTransaction(trans, closeCode); } else { @@ -2394,7 +2396,7 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param) 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! @@ -2429,12 +2431,11 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param) 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 diff --git a/python/mozbuild/mozbuild/backend/common.py b/python/mozbuild/mozbuild/backend/common.py index e2be49b0b7ee..4f8d0ee50eb3 100644 --- a/python/mozbuild/mozbuild/backend/common.py +++ b/python/mozbuild/mozbuild/backend/common.py @@ -39,7 +39,7 @@ class XPIDLManager(object): 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. @@ -58,7 +58,8 @@ class XPIDLManager(object): 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): @@ -181,7 +182,8 @@ class CommonBackend(BuildBackend): 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 diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 809407badb59..39c2f7b985ad 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals +import errno import itertools import json import logging @@ -15,11 +16,11 @@ 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, @@ -751,7 +752,7 @@ class RecursiveMakeBackend(CommonBackend): # 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)) @@ -983,8 +984,7 @@ INSTALL_TARGETS += %(prefix)s 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(): @@ -994,34 +994,44 @@ INSTALL_TARGETS += %(prefix)s % 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, @@ -1037,8 +1047,9 @@ INSTALL_TARGETS += %(prefix)s 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): diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py index e0cd58fb3acf..9b99dbba20ed 100644 --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -1161,7 +1161,7 @@ VARIABLES = { 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. diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py index ddb17920e548..3c88785c1127 100644 --- a/python/mozbuild/mozbuild/frontend/data.py +++ b/python/mozbuild/mozbuild/frontend/data.py @@ -157,6 +157,7 @@ class XPIDLFile(ContextDerived): __slots__ = ( 'basename', + 'install_target', 'source_path', ) @@ -167,6 +168,8 @@ class XPIDLFile(ContextDerived): 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. """ diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index f3f087e31dcc..6a7604c10278 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -345,6 +345,14 @@ class TreeMetadataEmitter(LoggingMixin): 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 @@ -523,9 +531,9 @@ class TreeMetadataEmitter(LoggingMixin): 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: @@ -616,10 +624,6 @@ class TreeMetadataEmitter(LoggingMixin): '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']) diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py index 08dada9a8803..8d045c85bfdc 100644 --- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py +++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py @@ -443,7 +443,9 @@ class TestRecursiveMakeBackend(BackendTester): 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) diff --git a/toolkit/modules/PageMenu.jsm b/toolkit/modules/PageMenu.jsm index 7d5823f8557b..d36120b6b0fe 100644 --- a/toolkit/modules/PageMenu.jsm +++ b/toolkit/modules/PageMenu.jsm @@ -2,7 +2,7 @@ * 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() { } @@ -11,46 +11,71 @@ PageMenu.prototype = { PAGEMENU_ATTR: "pagemenu", GENERATEDITEMID_ATTR: "generateditemid", - popup: null, - builder: null, + _popup: null, - maybeBuildAndAttachMenu: function(aTarget, aPopup) { - var pageMenu = null; - var target = aTarget; + // Only one of builder or browser will end up getting set. + _builder: null, + _browser: null, + + // 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; + } - var builder = pageMenu.createBuilder(); - if (!builder) { + pageMenu.build(this._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); @@ -60,33 +85,101 @@ PageMenu.prototype = { 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; - this.popup.removeEventListener("popuphidden", this); - this.popup.removeEventListener("command", this); + let children = aNode.children; + for (let child of children) { + let menuitem; + switch (child.type) { + case "menuitem": + if (!child.id) { + continue; // Ignore children without ids + } - this.popup = null; - this.builder = null; + menuitem = document.createElement("menuitem"); + if (child.checkbox) { + menuitem.setAttribute("type", "checkbox"); + if (child.checked) { + menuitem.setAttribute("checked", "true"); + } + } + + 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; + + 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; @@ -96,16 +189,19 @@ PageMenu.prototype = { 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; } @@ -117,19 +213,20 @@ PageMenu.prototype = { 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; @@ -139,3 +236,78 @@ PageMenu.prototype = { } } } + +// 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; + } + } +}