author | Brindusan Cristian <cbrindusan@mozilla.com> |
Tue, 17 Apr 2018 13:10:25 +0300 | |
changeset 414088 | e2b49506d98cfc7dba7a15ce28e9c4b35a8328ed |
parent 414087 | 617ce8cb79fbf444b207e840a89cd1b67f5baab1 (current diff) |
parent 413999 | f94b64e0020225c71701930f193bd96c3ad1d150 (diff) |
child 414089 | 71b23fab4c0b8a450cf906a725f55171c0e81638 |
push id | 33858 |
push user | ncsoregi@mozilla.com |
push date | Tue, 17 Apr 2018 21:55:44 +0000 |
treeherder | mozilla-central@d6eb5597d744 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 61.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
|
--- a/accessible/ipc/DocAccessibleChildBase.cpp +++ b/accessible/ipc/DocAccessibleChildBase.cpp @@ -52,17 +52,17 @@ DocAccessibleChildBase::InterfacesFor(Ac /* static */ void DocAccessibleChildBase::SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree) { uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID()); #if defined(XP_WIN) int32_t msaaId = AccessibleWrap::GetChildIDFor(aRoot); #endif - uint32_t role = aRoot->Role(); + a11y::role role = aRoot->Role(); uint32_t childCount = aRoot->ChildCount(); uint32_t interfaces = InterfacesFor(aRoot); // OuterDocAccessibles are special because we don't want to serialize the // child doc here, we'll call PDocAccessibleConstructor in // NotificationController. MOZ_ASSERT(!aRoot->IsDoc(), "documents shouldn't be serialized"); if (aRoot->IsOuterDoc()) {
--- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -108,31 +108,24 @@ DocAccessibleParent::AddSubtree(ProxyAcc uint32_t aIdx, uint32_t aIdxInParent) { if (aNewTree.Length() <= aIdx) { NS_ERROR("bad index in serialized tree!"); return 0; } const AccessibleData& newChild = aNewTree[aIdx]; - if (newChild.Role() > roles::LAST_ROLE) { - NS_ERROR("invalid role"); - return 0; - } if (mAccessibles.Contains(newChild.ID())) { NS_ERROR("ID already in use"); return 0; } - auto role = static_cast<a11y::role>(newChild.Role()); - - ProxyAccessible* newProxy = - new ProxyAccessible(newChild.ID(), aParent, this, role, - newChild.Interfaces()); + ProxyAccessible* newProxy = new ProxyAccessible( + newChild.ID(), aParent, this, newChild.Role(), newChild.Interfaces()); aParent->AddChildAt(aIdxInParent, newProxy); mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy; ProxyCreated(newProxy, newChild.Interfaces()); #if defined(XP_WIN) WrapperFor(newProxy)->SetID(newChild.MsaaID()); #endif @@ -391,28 +384,24 @@ DocAccessibleParent::RecvSelectionEvent( RefPtr<xpcAccEvent> event = new xpcAccEvent(aType, xpcTarget, xpcDoc, nullptr, false); nsCoreUtils::DispatchAccEvent(Move(event)); return IPC_OK(); } mozilla::ipc::IPCResult -DocAccessibleParent::RecvRoleChangedEvent(const uint32_t& aRole) +DocAccessibleParent::RecvRoleChangedEvent(const a11y::role& aRole) { if (mShutdown) { return IPC_OK(); } - if (aRole > roles::LAST_ROLE) { - return IPC_FAIL(this, "Child sent bad role in RoleChangedEvent"); - } - - mRole = static_cast<a11y::role>(aRole); - return IPC_OK(); + mRole = aRole; + return IPC_OK(); } mozilla::ipc::IPCResult DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) { // One document should never directly be the child of another. // We should always have at least an outer doc accessible in between. MOZ_ASSERT(aID);
--- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -101,17 +101,17 @@ public: virtual mozilla::ipc::IPCResult RecvFocusEvent(const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect) override; #endif // defined(XP_WIN) virtual mozilla::ipc::IPCResult RecvSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, const uint32_t& aType) override; - mozilla::ipc::IPCResult RecvRoleChangedEvent(const uint32_t& aRole) final; + mozilla::ipc::IPCResult RecvRoleChangedEvent(const a11y::role& aRole) final; virtual mozilla::ipc::IPCResult RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override; void Unbind() { if (DocAccessibleParent* parent = ParentDoc()) { parent->RemoveChildDoc(this); }
--- a/accessible/ipc/IPCTypes.h +++ b/accessible/ipc/IPCTypes.h @@ -2,16 +2,29 @@ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_a11y_IPCTypes_h #define mozilla_a11y_IPCTypes_h +#include "mozilla/a11y/Role.h" + +namespace IPC { + +template<> +struct ParamTraits<mozilla::a11y::role> + : public ContiguousEnumSerializerInclusive<mozilla::a11y::role, + mozilla::a11y::role::NOTHING, + mozilla::a11y::role::LAST_ROLE> +{ +}; +}; + /** * Since IPDL does not support preprocessing, this header file allows us to * define types used by PDocAccessible differently depending on platform. */ #if defined(XP_WIN) && defined(ACCESSIBILITY) // So that we don't include a bunch of other Windows junk.
--- a/accessible/ipc/other/PDocAccessible.ipdl +++ b/accessible/ipc/other/PDocAccessible.ipdl @@ -5,26 +5,27 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ include protocol PFileDescriptorSet; include protocol PBrowser; include "mozilla/GfxMessageUtils.h"; using nsIntRect from "nsRect.h"; +using mozilla::a11y::role from "mozilla/a11y/Role.h"; using mozilla::gfx::IntSize from "mozilla/gfx/Point.h"; using mozilla::gfx::IntPoint from "mozilla/gfx/Point.h"; namespace mozilla { namespace a11y { struct AccessibleData { uint64_t ID; - uint32_t Role; + role Role; uint32_t ChildrenCount; uint32_t Interfaces; }; struct ShowEventData { uint64_t ID; uint32_t Idx; @@ -58,17 +59,17 @@ parent: async Event(uint64_t aID, uint32_t type); async ShowEvent(ShowEventData data, bool aFromuser); async HideEvent(uint64_t aRootID, bool aFromUser); async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled); async CaretMoveEvent(uint64_t aID, int32_t aOffset); async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen, bool aIsInsert, bool aFromUser); async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType); - async RoleChangedEvent(uint32_t aRole); + async RoleChangedEvent(role aRole); /* * Tell the parent document to bind the existing document as a new child * document. */ async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID); child: @@ -88,17 +89,17 @@ child: nested(inside_sync) sync Help(uint64_t aID) returns(nsString help); nested(inside_sync) sync Description(uint64_t aID) returns(nsString desc); nested(inside_sync) sync Attributes(uint64_t aID) returns(Attribute[] attributes); nested(inside_sync) sync RelationByType(uint64_t aID, uint32_t aRelationType) returns(uint64_t[] targets); nested(inside_sync) sync Relations(uint64_t aID) returns(RelationTargets[] relations); nested(inside_sync) sync IsSearchbox(uint64_t aID) returns(bool retval); nested(inside_sync) sync LandmarkRole(uint64_t aID) returns(nsString landmark); - nested(inside_sync) sync ARIARoleAtom(uint64_t aID) returns(nsString role); + nested(inside_sync) sync ARIARoleAtom(uint64_t aID) returns(nsString ariaRole); nested(inside_sync) sync GetLevelInternal(uint64_t aID) returns(int32_t aLevel); async ScrollTo(uint64_t aID, uint32_t aScrollType); async ScrollToPoint(uint64_t aID, uint32_t aScrollType, int32_t aX, int32_t aY); // AccessibleText // TextSubstring is getText in IDL.
--- a/accessible/ipc/win/DocAccessibleChild.cpp +++ b/accessible/ipc/win/DocAccessibleChild.cpp @@ -258,17 +258,17 @@ DocAccessibleChild::SendSelectionEvent(c PushDeferredEvent(MakeUnique<SerializedSelection>(this, aID, aWidgetID, aType)); return true; } bool -DocAccessibleChild::SendRoleChangedEvent(const uint32_t& aRole) +DocAccessibleChild::SendRoleChangedEvent(const a11y::role& aRole) { if (IsConstructedInParentProcess()) { return PDocAccessibleChild::SendRoleChangedEvent(aRole); } PushDeferredEvent(MakeUnique<SerializedRoleChanged>(this, aRole)); return true; }
--- a/accessible/ipc/win/DocAccessibleChild.h +++ b/accessible/ipc/win/DocAccessibleChild.h @@ -52,17 +52,17 @@ public: bool SendFocusEvent(const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect); bool SendTextChangeEvent(const uint64_t& aID, const nsString& aStr, const int32_t& aStart, const uint32_t& aLen, const bool& aIsInsert, const bool& aFromUser, const bool aDoSyncCheck = true); bool SendSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, const uint32_t& aType); - bool SendRoleChangedEvent(const uint32_t& aRole); + bool SendRoleChangedEvent(const a11y::role& aRole); bool ConstructChildDocInParentProcess(DocAccessibleChild* aNewChildDoc, uint64_t aUniqueID, uint32_t aMsaaID); bool SendBindChildDoc(DocAccessibleChild* aChildDoc, const uint64_t& aNewParentID); protected: @@ -251,27 +251,27 @@ private: uint64_t mID; uint64_t mWidgetID; uint32_t mType; }; struct SerializedRoleChanged final : public DeferredEvent { - explicit SerializedRoleChanged(DocAccessibleChild* aTarget, uint32_t aRole) + explicit SerializedRoleChanged(DocAccessibleChild* aTarget, a11y::role aRole) : DeferredEvent(aTarget) , mRole(aRole) {} void Dispatch(DocAccessibleChild* aIPCDoc) override { Unused << aIPCDoc->SendRoleChangedEvent(mRole); } - uint32_t mRole; + a11y::role mRole; }; struct SerializedEvent final : public DeferredEvent { SerializedEvent(DocAccessibleChild* aTarget, uint64_t aID, uint32_t aType) : DeferredEvent(aTarget) , mID(aID) , mType(aType)
--- a/accessible/ipc/win/PDocAccessible.ipdl +++ b/accessible/ipc/win/PDocAccessible.ipdl @@ -2,29 +2,30 @@ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ include protocol PFileDescriptorSet; include protocol PBrowser; +using mozilla::a11y::role from "mozilla/a11y/Role.h"; using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h"; using mozilla::a11y::IDispatchHolder from "mozilla/a11y/IPCTypes.h"; using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h"; using mozilla::LayoutDeviceIntRect from "Units.h"; namespace mozilla { namespace a11y { struct AccessibleData { uint64_t ID; int32_t MsaaID; - uint32_t Role; + role Role; uint32_t ChildrenCount; uint32_t Interfaces; }; struct ShowEventData { uint64_t ID; uint32_t Idx; @@ -55,17 +56,17 @@ parent: async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled); async CaretMoveEvent(uint64_t aID, LayoutDeviceIntRect aCaretRect, int32_t aOffset); async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen, bool aIsInsert, bool aFromUser); sync SyncTextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen, bool aIsInsert, bool aFromUser); async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType); - async RoleChangedEvent(uint32_t aRole); + async RoleChangedEvent(role aRole); async FocusEvent(uint64_t aID, LayoutDeviceIntRect aCaretRect); /* * Tell the parent document to bind the existing document as a new child * document. */ async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
--- a/browser/base/content/browser-pageActions.js +++ b/browser/base/content/browser-pageActions.js @@ -1253,8 +1253,65 @@ BrowserPageActions.addSearchEngine = { let prompt = Services.prompt.getPrompt(gBrowser.contentWindow, Ci.nsIPrompt); prompt.QueryInterface(Ci.nsIWritablePropertyBag2); prompt.setPropertyAsBool("allowTabModal", true); prompt.alert(title, text); }, }); }, }; + +// share URL +BrowserPageActions.shareURL = { + onShowingInPanel(buttonNode) { + this._cached = false; + }, + + onPlacedInPanel(buttonNode) { + let action = PageActions.actionForID("shareURL"); + BrowserPageActions.takeActionTitleFromPanel(action); + }, + + onShowingSubview(panelViewNode) { + // We cache the providers + the UI if the user selects the share + // panel multiple times while the panel is open. + if (this._cached) { + return; + } + + let sharingService = this._sharingService; + let url = gBrowser.selectedBrowser.currentURI; + let currentURI = gURLBar.makeURIReadable(url).displaySpec; + let shareProviders = sharingService.getSharingProviders(currentURI); + let fragment = document.createDocumentFragment(); + + shareProviders.forEach(function(share) { + let item = document.createElement("toolbarbutton"); + item.setAttribute("label", share.menuItemTitle); + item.setAttribute("share-title", share.title); + item.setAttribute("image", share.image); + item.classList.add("subviewbutton", "subviewbutton-iconic"); + + item.addEventListener("command", event => { + let shareTitle = event.target.getAttribute("share-title"); + if (shareTitle) { + sharingService.shareUrl(shareTitle, currentURI); + } + PanelMultiView.hidePopup(BrowserPageActions.panelNode); + }); + + fragment.appendChild(item); + }); + + let bodyNode = panelViewNode.querySelector(".panel-subview-body"); + while (bodyNode.firstChild) { + bodyNode.firstChild.remove(); + } + bodyNode.appendChild(fragment); + this._cached = true; + } +}; + +// Attach sharingService here so tests can override the implementation +XPCOMUtils.defineLazyServiceGetter(BrowserPageActions.shareURL, + "_sharingService", + "@mozilla.org/widget/macsharingservice;1", + "nsIMacSharingService");
--- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -50,17 +50,17 @@ var gIdentityHandler = { * to be able to focus it on the popupshown event. */ _popupTriggeredByKeyboard: false, /** * RegExp used to decide if an about url should be shown as being part of * the browser UI. */ - _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|newaddon|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i, + _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i, get _isBroken() { return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN; }, get _isSecure() { // If a <browser> is included within a chrome document, then this._state // will refer to the security state for the <browser> and not the top level
--- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -163,41 +163,34 @@ panelview[mainview] > .panel-header { } .tabbrowser-tab:not([pinned]):not([fadein]) { max-width: 0.1px; min-width: 0.1px; visibility: hidden; } -.tab-close-button, -.tabbrowser-tab::after, -.tab-background { - /* Explicitly set the visibility to override the value (collapsed) - * we inherit from #TabsToolbar[collapsed] upon opening a browser window. */ - visibility: visible; -} - +.tab-icon-image[fadein], .tab-close-button[fadein], .tabbrowser-tab[fadein]::after, .tab-background[fadein] { /* This transition is only wanted for opening tabs. */ transition: visibility 0ms 25ms; } +.tab-icon-image:not([fadein]), .tab-close-button:not([fadein]), .tabbrowser-tab:not([fadein])::after, .tab-background:not([fadein]) { visibility: hidden; } .tab-label:not([fadein]), .tab-throbber:not([fadein]), -.tab-throbber-fallback:not([fadein]), -.tab-icon-image:not([fadein]) { +.tab-throbber-fallback:not([fadein]) { display: none; } %ifdef NIGHTLY_BUILD @supports -moz-bool-pref("browser.tabs.hideThrobber") { .tab-throbber, .tab-throbber-fallback { display: none; @@ -1215,17 +1208,17 @@ toolbarpaletteitem[place="palette"] > #d overflow-x: hidden; } #customization-panelWrapper, #customization-panelWrapper > .panel-arrowcontent, #customization-panelHolder { flex-direction: column; display: flex; - min-height: calc(174px + 8em); + min-height: calc(174px + 9em); } #customization-panelWrapper { flex: 1 1 auto; height: 0; /* Don't let my contents affect ancestors' content-based sizing */ align-items: end; /* align to the end on the cross-axis (affects arrow) */ }
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -7349,17 +7349,17 @@ var gIdentityHandler = { * to be able to focus it on the popupshown event. */ _popupTriggeredByKeyboard: false, /** * RegExp used to decide if an about url should be shown as being part of * the browser UI. */ - _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|newaddon|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i, + _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i, get _isBroken() { return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN; }, get _isSecure() { // If a <browser> is included within a chrome document, then this._state // will refer to the security state for the <browser> and not the top level
--- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -435,17 +435,18 @@ flip="slide" photon="true" position="bottomcenter topright" tabspecific="true" noautofocus="true" copyURL-title="&pageAction.copyLink.label;" emailLink-title="&emailPageCmd.label;" sendToDevice-title="&pageAction.sendTabToDevice.label;" - sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;"> + sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;" + shareURL-title="&pageAction.shareUrl.label;"> <panelmultiview id="pageActionPanelMultiView" mainViewId="pageActionPanelMainView" viewCacheId="appMenu-viewCache"> <panelview id="pageActionPanelMainView" context="pageActionContextMenu" class="PanelUI-subView"> <vbox class="panel-subview-body"/> </panelview> @@ -634,18 +635,17 @@ </toolbar> <toolbar id="TabsToolbar" class="titlebar-color" fullscreentoolbar="true" customizable="true" mode="icons" aria-label="&tabsToolbar.label;" - context="toolbar-context-menu" - collapsed="true"> + context="toolbar-context-menu"> <hbox class="titlebar-placeholder" type="pre-tabs" skipintoolbarset="true"/> <tabs id="tabbrowser-tabs" flex="1" setfocus="false" tooltip="tabbrowser-tab-tooltip" stopwatchid="FX_TAB_CLICK_MS">
--- a/browser/base/content/test/static/browser_parsable_script.js +++ b/browser/base/content/test/static/browser_parsable_script.js @@ -4,16 +4,21 @@ /* This list allows pre-existing or 'unfixable' JS issues to remain, while we * detect newly occurring issues in shipping JS. It is a list of regexes * matching files which have errors: */ const kWhitelist = new Set([ /browser\/content\/browser\/places\/controller.js$/, ]); +const kESModuleList = new Set([ + /toolkit\/res\/payments\/(components|containers|mixins)\/.*.js$/, + /toolkit\/res\/payments\/PaymentsStore.js$/, +]); + // Normally we would use reflect.jsm to get Reflect.parse. However, if // we do that, then all the AST data is allocated in reflect.jsm's // zone. That exposes a bug in our GC. The GC collects reflect.jsm's // zone but not the zone in which our test code lives (since no new // data is being allocated in it). The cross-compartment wrappers in // our zone that point to the AST data never get collected, and so the // AST data itself is never collected. We need to GC both zones at // once to fix the problem. @@ -31,26 +36,45 @@ function uriIsWhiteListed(uri) { for (let whitelistItem of kWhitelist) { if (whitelistItem.test(uri.spec)) { return true; } } return false; } -function parsePromise(uri) { +/** + * Check if a URI should be parsed as an ES module. + * + * @param uri the uri to check against the ES module list + * @return true if the uri should be parsed as a module, otherwise parse it as a script. + */ +function uriIsESModule(uri) { + for (let whitelistItem of kESModuleList) { + if (whitelistItem.test(uri.spec)) { + return true; + } + } + return false; +} + +function parsePromise(uri, parseTarget) { let promise = new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.open("GET", uri, true); xhr.onreadystatechange = function() { if (this.readyState == this.DONE) { let scriptText = this.responseText; try { - info("Checking " + uri); - Reflect.parse(scriptText, {source: uri}); + info(`Checking ${parseTarget} ${uri}`); + let parseOpts = { + source: uri, + target: parseTarget, + }; + Reflect.parse(scriptText, parseOpts); resolve(true); } catch (ex) { let errorMsg = "Script error reading " + uri + ": " + ex; ok(false, errorMsg); resolve(false); } } }; @@ -113,12 +137,16 @@ add_task(async function checkAllTheJS() // We create an array of promises so we can parallelize all our parsing // and file loading activity: await throttledMapPromises(uris, uri => { if (uriIsWhiteListed(uri)) { info("Not checking whitelisted " + uri.spec); return undefined; } - return parsePromise(uri.spec); + let target = "script"; + if (uriIsESModule(uri)) { + target = "module"; + } + return parsePromise(uri.spec, target); }); ok(true, "All files parsed"); });
--- a/browser/base/content/test/statuspanel/browser.ini +++ b/browser/base/content/test/statuspanel/browser.ini @@ -1,5 +1,7 @@ [DEFAULT] support-files = head.js [browser_show_statuspanel_twice.js] +[browser_show_statuspanel_idn.js] +skip-if = webrender && verify
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/statuspanel/browser_show_statuspanel_idn.js @@ -0,0 +1,23 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_PAGE_URL = encodeURI(`data:text/html;charset=utf-8,<a id="foo" href="http://nic.xn--rhqv96g/">abc</a><span id="bar">def</span>`); +const TEST_STATUS_TEXT = "nic.\u4E16\u754C"; + +/** + * Test that if the StatusPanel displays an IDN + * (Bug 1450538). + */ +add_task(async function test_show_statuspanel_twice() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URL); + + let promise = promiseStatusPanelShown(window, TEST_STATUS_TEXT); + ContentTask.spawn(tab.linkedBrowser, null, async () => { + content.document.links[0].focus(); + }); + await promise; + + await BrowserTestUtils.removeTab(tab); +});
--- a/browser/base/content/test/urlbar/browser.ini +++ b/browser/base/content/test/urlbar/browser.ini @@ -47,16 +47,18 @@ support-files = page_action_menu_add_search_engine_one.html page_action_menu_add_search_engine_many.html page_action_menu_add_search_engine_same_names.html page_action_menu_add_search_engine_0.xml page_action_menu_add_search_engine_1.xml page_action_menu_add_search_engine_2.xml [browser_page_action_menu_clipboard.js] subsuite = clipboard +[browser_page_action_menu_share_mac.js] +skip-if = os != "mac" # Mac only feature [browser_pasteAndGo.js] subsuite = clipboard [browser_removeUnsafeProtocolsFromURLBarPaste.js] subsuite = clipboard [browser_search_favicon.js] [browser_tabMatchesInAwesomebar.js] support-files = moz.png
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/urlbar/browser_page_action_menu_share_mac.js @@ -0,0 +1,72 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/* global sinon */ +Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js"); + +// Keep track of title of service we chose to share with +let sharedTitle; +let sharedUrl; + +let mockShareData = [{ + title: "NSA", + menuItemTitle: "National Security Agency", + image: "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEA" + + "LAAAAAABAAEAAAICTAEAOw==" +}]; + +let stub = sinon.stub(BrowserPageActions.shareURL, "_sharingService").get(() => { + return { + getSharingProviders(url) { + return mockShareData; + }, + shareUrl(title, url) { + sharedUrl = url; + sharedTitle = title; + } + }; +}); + +registerCleanupFunction(async function() { + stub.restore(); + delete window.sinon; + await EventUtils.synthesizeNativeMouseMove(document.documentElement, 0, 0); + await PlacesUtils.history.clear(); +}); + +add_task(async function shareURL() { + // Open an actionable page so that the main page action button appears. (It + // does not appear on about:blank for example.) + let url = "http://example.org/"; + + await BrowserTestUtils.withNewTab(url, async () => { + // Open the panel. + await promisePageActionPanelOpen(); + + // Click Share URL. + let shareURLButton = document.getElementById("pageAction-panel-shareURL"); + let viewPromise = promisePageActionViewShown(); + EventUtils.synthesizeMouseAtCenter(shareURLButton, {}); + + let view = await viewPromise; + let body = document.getElementById(view.id + "-body"); + + Assert.equal(body.childNodes.length, 1, "Has correct share receivers"); + let shareButton = body.childNodes[0]; + Assert.equal(shareButton.label, mockShareData[0].menuItemTitle); + let hiddenPromise = promisePageActionPanelHidden(); + // Click on share, panel should hide and sharingService should be + // given the title of service to share with + EventUtils.synthesizeMouseAtCenter(shareButton, {}); + await hiddenPromise; + + Assert.equal(sharedTitle, mockShareData[0].title, + "Shared with the correct title"); + Assert.equal(sharedUrl, "http://example.org/", + "Shared correct URL"); + + }); +});
--- a/browser/base/content/test/urlbar/browser_search_favicon.js +++ b/browser/base/content/test/urlbar/browser_search_favicon.js @@ -6,16 +6,20 @@ registerCleanupFunction(() => { Services.prefs.clearUserPref(gRestyleSearchesPref); Services.search.currentEngine = gOriginalEngine; Services.search.removeEngine(gEngine); return PlacesUtils.history.clear(); }); add_task(async function() { Services.prefs.setBoolPref(gRestyleSearchesPref, true); + + // This test is sensitive to the mouse position hovering awesome + // bar elements, so make sure it doesnt + await EventUtils.synthesizeNativeMouseMove(document.documentElement, 0, 0); }); add_task(async function() { Services.search.addEngineWithDetails("SearchEngine", "", "", "", "GET", "http://s.example.com/search"); gEngine = Services.search.getEngineByName("SearchEngine"); gEngine.addParam("q", "{searchTerms}", null);
--- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -2452,23 +2452,27 @@ file, You can obtain one at http://mozil <handler event="mousedown"><![CDATA[ // Required to make the xul:label.text-link elements in the search // suggestions notification work correctly when clicked on Linux. // This is copied from the mousedown handler in // browser-search-autocomplete-result-popup, which apparently had a // similar problem. event.preventDefault(); + if (event.button == 2) { + // Right mouse button currently allows to select. + this.input.userSelectionBehavior = "rightClick"; + // Ignore right-clicks. + return; + } + if (!this.input.speculativeConnectEnabled) { return; } - if (event.button == 2) { - // Ignore right-clicks. - return; - } + // Ensure the user is clicking on an url instead of other buttons // on the popup. let elt = event.originalTarget; while (elt && elt.localName != "richlistitem" && elt != this) { elt = elt.parentNode; } if (!elt || elt.localName != "richlistitem") { return;
--- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -711,17 +711,17 @@ BrowserGlue.prototype = { LightweightThemeManager.addBuiltInTheme({ id: "firefox-compact-dark@mozilla.org", name: gBrowserBundle.GetStringFromName("darkTheme.name"), description: gBrowserBundle.GetStringFromName("darkTheme.description"), iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg", textcolor: "white", accentcolor: "black", popup: "#4a4a4f", - popup_text: "rgba(249, 249, 250, 0.8)", + popup_text: "rgb(249, 249, 250)", popup_border: "#27272b", author: vendorShortName, }); Normandy.init(); // Initialize the default l10n resource sources for L10nRegistry. let locales = Services.locale.getPackagedLocales();
--- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -989,16 +989,18 @@ you can use these alternative items. Oth <!ENTITY pageAction.removeFromUrlbar.label "Remove from Address Bar"> <!ENTITY pageAction.allowInUrlbar.label "Show in Address Bar"> <!ENTITY pageAction.disallowInUrlbar.label "Don’t Show in Address Bar"> <!ENTITY pageAction.manageExtension.label "Manage Extension…"> <!ENTITY pageAction.sendTabToDevice.label "Send Tab to Device"> <!ENTITY sendToDevice.syncNotReady.label "Syncing Devices…"> +<!ENTITY pageAction.shareUrl.label "Share"> + <!ENTITY libraryButton.tooltip "View history, saved bookmarks, and more"> <!-- LOCALIZATION NOTE: (accessibilityIndicator.tooltip): This is used to display a tooltip for accessibility indicator in toolbar/tabbar. It is also used as a textual label for the indicator used by assistive technology users. --> <!ENTITY accessibilityIndicator.tooltip "Accessibility Features Enabled">
--- a/browser/modules/BrowserUsageTelemetry.jsm +++ b/browser/modules/BrowserUsageTelemetry.jsm @@ -78,16 +78,17 @@ const URLBAR_SELECTED_RESULT_TYPES = { * these category names directly when they add to a histogram. */ const URLBAR_SELECTED_RESULT_METHODS = { enter: 0, enterSelection: 1, click: 2, arrowEnterSelection: 3, tabEnterSelection: 4, + rightClickEnter: 5, }; const MINIMUM_TAB_COUNT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes, in ms function getOpenTabsAndWinsCounts() { let tabCount = 0; @@ -560,16 +561,20 @@ let BrowserUsageTelemetry = { } else if (highlightedIndex >= 0) { switch (userSelectionBehavior) { case "tab": category = "tabEnterSelection"; break; case "arrow": category = "arrowEnterSelection"; break; + case "rightClick": + // Selected by right mouse button. + category = "rightClickEnter"; + break; default: category = "enterSelection"; } } else { category = "enter"; } histogram.add(category); },
--- a/browser/modules/ExtensionsUI.jsm +++ b/browser/modules/ExtensionsUI.jsm @@ -92,23 +92,16 @@ var ExtensionsUI = { }; AddonManager.addAddonListener(this.sideloadListener); } for (let addon of sideloaded) { this.sideloaded.add(addon); } this._updateNotifications(); - } else { - // This and all the accompanying about:newaddon code can eventually - // be removed. See bug 1331521. - let win = RecentWindow.getMostRecentBrowserWindow(); - for (let addon of sideloaded) { - win.openTrustedLinkIn(`about:newaddon?id=${addon.id}`, "tab"); - } } }, async _checkNewDistroAddons() { let newDistroAddons = AddonManagerPrivate.getNewDistroAddons(); if (!newDistroAddons) { return; }
--- a/browser/modules/PageActions.jsm +++ b/browser/modules/PageActions.jsm @@ -1162,16 +1162,35 @@ if (Services.prefs.getBoolPref("identity }, onSubviewShowing(panelViewNode) { browserPageActions(panelViewNode).sendToDevice .onShowingSubview(panelViewNode); }, }); } +if (AppConstants.platform == "macosx") { + gBuiltInActions.push( + // Share URL + { + id: "shareURL", + title: "shareURL-title", + onShowingInPanel(buttonNode) { + browserPageActions(buttonNode).shareURL.onShowingInPanel(buttonNode); + }, + onPlacedInPanel(buttonNode) { + browserPageActions(buttonNode).shareURL.onPlacedInPanel(buttonNode); + }, + wantsSubview: true, + onSubviewShowing(panelViewNode) { + browserPageActions(panelViewNode).shareURL + .onShowingSubview(panelViewNode); + }, + }); +} /** * Gets a BrowserPageActions object in a browser window. * * @param obj * Either a DOM node or a browser window. * @return The BrowserPageActions object in the browser window related to the * given object.
--- a/browser/modules/test/browser/browser_UsageTelemetry_urlbar.js +++ b/browser/modules/test/browser/browser_UsageTelemetry_urlbar.js @@ -47,33 +47,63 @@ let searchInAwesomebar = async function( Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH); }; /** * Click one of the entries in the urlbar suggestion popup. * * @param {String} entryName * The name of the elemet to click on. + * @param {Number} button [optional] + * which button to click. */ -function clickURLBarSuggestion(entryName) { +function clickURLBarSuggestion(entryName, button = 1) { // The entry in the suggestion list should follow the format: // "<search term> <engine name> Search" const expectedSuggestionName = entryName + " " + SUGGESTION_ENGINE_NAME + " Search"; return BrowserTestUtils.waitForCondition(() => { for (let child of gURLBar.popup.richlistbox.children) { if (child.label === expectedSuggestionName) { // This entry is the search suggestion we're looking for. - child.click(); + if (button == 1) + child.click(); + else if (button == 2) { + EventUtils.synthesizeMouseAtCenter(child, {type: "mousedown", button: 2}); + } return true; } } return false; }, "Waiting for the expected suggestion to appear"); } +/** + * Create an engine to generate search suggestions and add it as default + * for this test. + */ +async function withNewSearchEngine(taskFn) { + const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml"; + let suggestionEngine = await new Promise((resolve, reject) => { + Services.search.addEngine(url, null, "", false, { + onSuccess(engine) { resolve(engine); }, + onError() { reject(); } + }); + }); + + let previousEngine = Services.search.currentEngine; + Services.search.currentEngine = suggestionEngine; + + try { + await taskFn(suggestionEngine); + } finally { + Services.search.currentEngine = previousEngine; + Services.search.removeEngine(suggestionEngine); + } +} + add_task(async function setup() { // Create a new search engine. Services.search.addEngineWithDetails("MozSearch", "", "mozalias", "", "GET", "http://example.com/?q={searchTerms}"); // Make it the default search engine. let engine = Services.search.getEngineByName("MozSearch"); let originalEngine = Services.search.currentEngine; @@ -115,17 +145,16 @@ add_task(async function setup() { Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled); Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF); await PlacesUtils.history.clear(); Services.telemetry.setEventRecordingEnabled("navigation", false); }); }); add_task(async function test_simpleQuery() { - // Let's reset the counts. Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); let resultIndexHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_INDEX"); let resultTypeHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_TYPE"); let resultIndexByTypeHist = getAndClearKeyedHistogram("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE"); let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS"); @@ -170,17 +199,16 @@ add_task(async function test_simpleQuery checkHistogramResults(resultMethods, URLBAR_SELECTED_RESULT_METHODS.enter, "FX_URLBAR_SELECTED_RESULT_METHOD"); BrowserTestUtils.removeTab(tab); }); add_task(async function test_searchAlias() { - // Let's reset the counts. Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); let resultIndexHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_INDEX"); let resultTypeHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_TYPE"); let resultIndexByTypeHist = getAndClearKeyedHistogram("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE"); let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS"); @@ -227,17 +255,16 @@ add_task(async function test_searchAlias "FX_URLBAR_SELECTED_RESULT_METHOD"); BrowserTestUtils.removeTab(tab); }); // Performs a search using the first result, a one-off button, and the Return // (Enter) key. add_task(async function test_oneOff_enter() { - // Let's reset the counts. Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); let resultIndexHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_INDEX"); let resultTypeHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_TYPE"); let resultIndexByTypeHist = getAndClearKeyedHistogram("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE"); let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS"); @@ -288,61 +315,45 @@ add_task(async function test_oneOff_ente BrowserTestUtils.removeTab(tab); }); // Performs a search using the second result, a one-off button, and the Return // (Enter) key. This only tests the FX_URLBAR_SELECTED_RESULT_METHOD histogram // since test_oneOff_enter covers everything else. add_task(async function test_oneOff_enterSelection() { - // Let's reset the counts. Services.telemetry.clearScalars(); - let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); - // Create an engine to generate search suggestions and add it as default - // for this test. - const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml"; - let suggestionEngine = await new Promise((resolve, reject) => { - Services.search.addEngine(url, null, "", false, { - onSuccess(engine) { resolve(engine); }, - onError() { reject(); } - }); - }); + await withNewSearchEngine(async function() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); - let previousEngine = Services.search.currentEngine; - Services.search.currentEngine = suggestionEngine; - - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); + info("Type a query. Suggestions should be generated by the test engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInAwesomebar("query"); - info("Type a query. Suggestions should be generated by the test engine."); - let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await searchInAwesomebar("query"); + info("Select the second result, press Alt+Down to take us to the first one-off engine."); + EventUtils.synthesizeKey("KEY_ArrowDown"); + EventUtils.synthesizeKey("KEY_ArrowDown", {altKey: true}); + EventUtils.synthesizeKey("KEY_Enter"); + await p; - info("Select the second result, press Alt+Down to take us to the first one-off engine."); - EventUtils.synthesizeKey("KEY_ArrowDown"); - EventUtils.synthesizeKey("KEY_ArrowDown", {altKey: true}); - EventUtils.synthesizeKey("KEY_Enter"); - await p; + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults(resultMethods, + URLBAR_SELECTED_RESULT_METHODS.arrowEnterSelection, + "FX_URLBAR_SELECTED_RESULT_METHOD"); - let resultMethods = resultMethodHist.snapshot(); - checkHistogramResults(resultMethods, - URLBAR_SELECTED_RESULT_METHODS.arrowEnterSelection, - "FX_URLBAR_SELECTED_RESULT_METHOD"); - - Services.search.currentEngine = previousEngine; - Services.search.removeEngine(suggestionEngine); - BrowserTestUtils.removeTab(tab); + BrowserTestUtils.removeTab(tab); + }); }); // Performs a search using a click on a one-off button. This only tests the // FX_URLBAR_SELECTED_RESULT_METHOD histogram since test_oneOff_enter covers // everything else. add_task(async function test_oneOff_click() { - // Let's reset the counts. Services.telemetry.clearScalars(); let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); info("Type a query."); let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); @@ -356,202 +367,168 @@ add_task(async function test_oneOff_clic URLBAR_SELECTED_RESULT_METHODS.click, "FX_URLBAR_SELECTED_RESULT_METHOD"); BrowserTestUtils.removeTab(tab); }); // Clicks the first suggestion offered by the test search engine. add_task(async function test_suggestion_click() { - // Let's reset the counts. Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); let resultIndexHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_INDEX"); let resultTypeHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_TYPE"); let resultIndexByTypeHist = getAndClearKeyedHistogram("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE"); let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS"); - // Create an engine to generate search suggestions and add it as default - // for this test. - const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml"; - let suggestionEngine = await new Promise((resolve, reject) => { - Services.search.addEngine(url, null, "", false, { - onSuccess(engine) { resolve(engine); }, - onError() { reject(); } - }); - }); + await withNewSearchEngine(async function(engine) { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); - let previousEngine = Services.search.currentEngine; - Services.search.currentEngine = suggestionEngine; + info("Type a query. Suggestions should be generated by the test engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInAwesomebar("query"); + info("Clicking the urlbar suggestion."); + await clickURLBarSuggestion("queryfoo"); + await p; - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); + // Check if the scalars contain the expected values. + const scalars = getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true, false); + checkKeyedScalar(scalars, SCALAR_URLBAR, "search_suggestion", 1); + Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1, + "This search must only increment one entry in the scalar."); - info("Type a query. Suggestions should be generated by the test engine."); - let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await searchInAwesomebar("query"); - info("Clicking the urlbar suggestion."); - await clickURLBarSuggestion("queryfoo"); - await p; - - // Check if the scalars contain the expected values. - const scalars = getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true, false); - checkKeyedScalar(scalars, SCALAR_URLBAR, "search_suggestion", 1); - Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1, - "This search must only increment one entry in the scalar."); + // Make sure SEARCH_COUNTS contains identical values. + let searchEngineId = "other-" + engine.name; + checkKeyedHistogram(search_hist, searchEngineId + ".urlbar", 1); - // Make sure SEARCH_COUNTS contains identical values. - let searchEngineId = "other-" + suggestionEngine.name; - checkKeyedHistogram(search_hist, searchEngineId + ".urlbar", 1); + // Also check events. + let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false); + events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search"); + checkEvents(events, [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]]); - // Also check events. - let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false); - events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search"); - checkEvents(events, [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]]); - - // Check the histograms as well. - let resultIndexes = resultIndexHist.snapshot(); - checkHistogramResults(resultIndexes, 3, "FX_URLBAR_SELECTED_RESULT_INDEX"); + // Check the histograms as well. + let resultIndexes = resultIndexHist.snapshot(); + checkHistogramResults(resultIndexes, 3, "FX_URLBAR_SELECTED_RESULT_INDEX"); - let resultTypes = resultTypeHist.snapshot(); - checkHistogramResults(resultTypes, - URLBAR_SELECTED_RESULT_TYPES.searchsuggestion, - "FX_URLBAR_SELECTED_RESULT_TYPE"); + let resultTypes = resultTypeHist.snapshot(); + checkHistogramResults(resultTypes, + URLBAR_SELECTED_RESULT_TYPES.searchsuggestion, + "FX_URLBAR_SELECTED_RESULT_TYPE"); - let resultIndexByType = resultIndexByTypeHist.snapshot("searchsuggestion"); - checkHistogramResults(resultIndexByType, - 3, - "FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE"); + let resultIndexByType = resultIndexByTypeHist.snapshot("searchsuggestion"); + checkHistogramResults(resultIndexByType, + 3, + "FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE"); - let resultMethods = resultMethodHist.snapshot(); - checkHistogramResults(resultMethods, - URLBAR_SELECTED_RESULT_METHODS.click, - "FX_URLBAR_SELECTED_RESULT_METHOD"); + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults(resultMethods, + URLBAR_SELECTED_RESULT_METHODS.click, + "FX_URLBAR_SELECTED_RESULT_METHOD"); - Services.search.currentEngine = previousEngine; - Services.search.removeEngine(suggestionEngine); - BrowserTestUtils.removeTab(tab); + BrowserTestUtils.removeTab(tab); + }); }); // Selects and presses the Return (Enter) key on the first suggestion offered by // the test search engine. This only tests the FX_URLBAR_SELECTED_RESULT_METHOD // histogram since test_suggestion_click covers everything else. add_task(async function test_suggestion_arrowEnterSelection() { - // Let's reset the counts. Services.telemetry.clearScalars(); - let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); - // Create an engine to generate search suggestions and add it as default - // for this test. - const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml"; - let suggestionEngine = await new Promise((resolve, reject) => { - Services.search.addEngine(url, null, "", false, { - onSuccess(engine) { resolve(engine); }, - onError() { reject(); } - }); - }); - - let previousEngine = Services.search.currentEngine; - Services.search.currentEngine = suggestionEngine; - - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); + await withNewSearchEngine(async function() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); - info("Type a query. Suggestions should be generated by the test engine."); - let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await searchInAwesomebar("query"); - info("Select the second result and press Return."); - EventUtils.synthesizeKey("KEY_ArrowDown"); - EventUtils.synthesizeKey("KEY_Enter"); - await p; + info("Type a query. Suggestions should be generated by the test engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInAwesomebar("query"); + info("Select the second result and press Return."); + EventUtils.synthesizeKey("KEY_ArrowDown"); + EventUtils.synthesizeKey("KEY_Enter"); + await p; - let resultMethods = resultMethodHist.snapshot(); - checkHistogramResults(resultMethods, - URLBAR_SELECTED_RESULT_METHODS.arrowEnterSelection, - "FX_URLBAR_SELECTED_RESULT_METHOD"); + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults(resultMethods, + URLBAR_SELECTED_RESULT_METHODS.arrowEnterSelection, + "FX_URLBAR_SELECTED_RESULT_METHOD"); - Services.search.currentEngine = previousEngine; - Services.search.removeEngine(suggestionEngine); - BrowserTestUtils.removeTab(tab); + BrowserTestUtils.removeTab(tab); + }); }); // Selects through tab and presses the Return (Enter) key on the first // suggestion offered by the test search engine. add_task(async function test_suggestion_tabEnterSelection() { - // Let's reset the counts. Services.telemetry.clearScalars(); - let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); - // Create an engine to generate search suggestions and add it as default - // for this test. - const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml"; - let suggestionEngine = await new Promise((resolve, reject) => { - Services.search.addEngine(url, null, "", false, { - onSuccess(engine) { resolve(engine); }, - onError() { reject(); } - }); - }); - - let previousEngine = Services.search.currentEngine; - Services.search.currentEngine = suggestionEngine; - - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); + await withNewSearchEngine(async function() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); - info("Type a query. Suggestions should be generated by the test engine."); - let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await searchInAwesomebar("query"); - info("Select the second result and press Return."); - EventUtils.synthesizeKey("KEY_Tab"); - EventUtils.synthesizeKey("KEY_Enter"); - await p; + info("Type a query. Suggestions should be generated by the test engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInAwesomebar("query"); + info("Select the second result and press Return."); + EventUtils.synthesizeKey("KEY_Tab"); + EventUtils.synthesizeKey("KEY_Enter"); + await p; - let resultMethods = resultMethodHist.snapshot(); - checkHistogramResults(resultMethods, - URLBAR_SELECTED_RESULT_METHODS.tabEnterSelection, - "FX_URLBAR_SELECTED_RESULT_METHOD"); + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults(resultMethods, + URLBAR_SELECTED_RESULT_METHODS.tabEnterSelection, + "FX_URLBAR_SELECTED_RESULT_METHOD"); - Services.search.currentEngine = previousEngine; - Services.search.removeEngine(suggestionEngine); - BrowserTestUtils.removeTab(tab); + BrowserTestUtils.removeTab(tab); + }); }); // Selects through code and presses the Return (Enter) key on the first // suggestion offered by the test search engine. add_task(async function test_suggestion_enterSelection() { - // Let's reset the counts. Services.telemetry.clearScalars(); - let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); - // Create an engine to generate search suggestions and add it as default - // for this test. - const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml"; - let suggestionEngine = await new Promise((resolve, reject) => { - Services.search.addEngine(url, null, "", false, { - onSuccess(engine) { resolve(engine); }, - onError() { reject(); } - }); + await withNewSearchEngine(async function() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); + + info("Type a query. Suggestions should be generated by the test engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInAwesomebar("query"); + info("Select the second result and press Return."); + gURLBar.popup.selectedIndex = 1; + EventUtils.synthesizeKey("KEY_Enter"); + await p; + + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults(resultMethods, + URLBAR_SELECTED_RESULT_METHODS.enterSelection, + "FX_URLBAR_SELECTED_RESULT_METHOD"); + + BrowserTestUtils.removeTab(tab); }); - - let previousEngine = Services.search.currentEngine; - Services.search.currentEngine = suggestionEngine; - - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); +}); - info("Type a query. Suggestions should be generated by the test engine."); - let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await searchInAwesomebar("query"); - info("Select the second result and press Return."); - gURLBar.popup.selectedIndex = 1; - EventUtils.synthesizeKey("KEY_Enter"); - await p; +// Selects through mouse right button and press the Return (Enter) key. +add_task(async function test_suggestion_rightclick() { + Services.telemetry.clearScalars(); + let resultMethodHist = getAndClearHistogram("FX_URLBAR_SELECTED_RESULT_METHOD"); + + await withNewSearchEngine(async function() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); - let resultMethods = resultMethodHist.snapshot(); - checkHistogramResults(resultMethods, - URLBAR_SELECTED_RESULT_METHODS.enterSelection, - "FX_URLBAR_SELECTED_RESULT_METHOD"); + info("Type a query. Suggestions should be generated by the test engine."); + let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await searchInAwesomebar("query"); + info("Right click the the second result and then press Return."); + await clickURLBarSuggestion("queryfoo", 2); + EventUtils.synthesizeKey("KEY_Enter"); + await p; - Services.search.currentEngine = previousEngine; - Services.search.removeEngine(suggestionEngine); - BrowserTestUtils.removeTab(tab); + let resultMethods = resultMethodHist.snapshot(); + checkHistogramResults(resultMethods, + URLBAR_SELECTED_RESULT_METHODS.rightClickEnter, + "FX_URLBAR_SELECTED_RESULT_METHOD"); + + BrowserTestUtils.removeTab(tab); + }); });
--- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -330,16 +330,20 @@ html|input.urlbar-input { } .urlbar-display { margin-top: 0; margin-bottom: 0; color: GrayText; } +#pageAction-panel-shareURL { + list-style-image: url("chrome://browser/skin/share.svg"); +} + %include ../shared/urlbarSearchSuggestionsNotification.inc.css /* ----- AUTOCOMPLETE ----- */ %include ../shared/autocomplete.inc.css %include ../shared/urlbar-autocomplete.inc.css :root {
--- a/browser/themes/osx/jar.mn +++ b/browser/themes/osx/jar.mn @@ -51,16 +51,17 @@ browser.jar: skin/classic/browser/places/livemark-item.png (places/livemark-item.png) skin/classic/browser/preferences/alwaysAsk.png (preferences/alwaysAsk.png) skin/classic/browser/preferences/application.png (preferences/application.png) skin/classic/browser/preferences/saveFile.png (preferences/saveFile.png) * skin/classic/browser/preferences/preferences.css (preferences/preferences.css) * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css) * skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css) skin/classic/browser/preferences/applications.css (preferences/applications.css) + skin/classic/browser/share.svg (share.svg) skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) skin/classic/browser/tabbrowser/tabDragIndicator@2x.png (tabbrowser/tabDragIndicator@2x.png) skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png) [extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar: % override chrome://browser/skin/feeds/audioFeedIcon.png chrome://browser/skin/feeds/feedIcon.png % override chrome://browser/skin/feeds/audioFeedIcon16.png chrome://browser/skin/feeds/feedIcon16.png % override chrome://browser/skin/feeds/videoFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
new file mode 100644 --- /dev/null +++ b/browser/themes/osx/share.svg @@ -0,0 +1,7 @@ +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <path fill="context-fill" d="M12.707 4.294l-4-4A1 1 0 0 0 8.38.077a.984.984 0 0 0-.246-.05A.938.938 0 0 0 8 0a.938.938 0 0 0-.134.027.984.984 0 0 0-.246.05A1 1 0 0 0 7.291.3l-4 4a1 1 0 0 0 1.416 1.408L7 3.415V11a1 1 0 0 0 2 0V3.415l2.293 2.293a1 1 0 0 0 1.414-1.414z"></path> + <path fill="context-fill" d="M14 9a1 1 0 0 0-1 1v3a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-3a1 1 0 0 0-2 0v3a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3v-3a1 1 0 0 0-1-1z"></path> +</svg>
--- a/devtools/client/framework/components/toolbox-tabs.js +++ b/devtools/client/framework/components/toolbox-tabs.js @@ -8,16 +8,19 @@ const dom = require("devtools/client/sha const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const {findDOMNode} = require("devtools/client/shared/vendor/react-dom"); const {button, div} = dom; const Menu = require("devtools/client/framework/menu"); const MenuItem = require("devtools/client/framework/menu-item"); const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab")); +// 26px is chevron devtools button width.(i.e. tools-chevronmenu) +const CHEVRON_BUTTON_WIDTH = 26; + class ToolboxTabs extends Component { // See toolbox-toolbar propTypes for details on the props used here. static get propTypes() { return { currentToolId: PropTypes.string, focusButton: PropTypes.func, focusedButton: PropTypes.string, highlightedTools: PropTypes.object, @@ -27,140 +30,237 @@ class ToolboxTabs extends Component { L10N: PropTypes.object, }; } constructor(props) { super(props); this.state = { - overflow: false, + // Array of overflowed tool id. + overflowedTabIds: [], }; - this.addFlowEvents = this.addFlowEvents.bind(this); - this.removeFlowEvents = this.removeFlowEvents.bind(this); - this.onOverflow = this.onOverflow.bind(this); - this.onUnderflow = this.onUnderflow.bind(this); + // Map with tool Id and its width size. This lifecycle is out of React's + // lifecycle. If a tool is registered, ToolboxTabs will add target tool id + // to this map. ToolboxTabs will never remove tool id from this cache. + this._cachedToolTabsWidthMap = new Map(); + + this._resizeTimerId = null; + this.resizeHandler = this.resizeHandler.bind(this); + } + + componentDidMount() { + window.addEventListener("resize", this.resizeHandler); + this.updateCachedToolTabsWidthMap(); + this.updateOverflowedTabs(); + } + + componentWillUpdate(nextProps, nextState) { + if (this.shouldUpdateToolboxTabs(this.props, nextProps)) { + // Force recalculate and render in this cycle if panel definition has + // changed or selected tool has changed. + nextState.overflowedTabIds = []; + } + } + + componentDidUpdate(prevProps, prevState) { + if (this.shouldUpdateToolboxTabs(prevProps, this.props)) { + this.updateCachedToolTabsWidthMap(); + this.updateOverflowedTabs(); + } } - componentDidUpdate() { - this.addFlowEvents(); + /** + * Check if two array of ids are the same or not. + */ + equalToolIdArray(prevPanels, nextPanels) { + if (prevPanels.length !== nextPanels.length) { + return false; + } + + // Check panel definitions even if both of array size is same. + // For example, the case of changing the tab's order. + return prevPanels.join("-") === nextPanels.join("-"); } - componentWillUnmount() { - this.removeFlowEvents(); + /** + * Return true if we should update the overflowed tabs. + */ + shouldUpdateToolboxTabs(prevProps, nextProps) { + if (prevProps.currentToolId !== nextProps.currentToolId) { + return true; + } + + let prevPanels = prevProps.panelDefinitions.map(def => def.id); + let nextPanels = nextProps.panelDefinitions.map(def => def.id); + return !this.equalToolIdArray(prevPanels, nextPanels); } - addFlowEvents() { - this.removeFlowEvents(); - let node = findDOMNode(this); - if (node) { - node.addEventListener("overflow", this.onOverflow); - node.addEventListener("underflow", this.onUnderflow); + /** + * Update the Map of tool id and tool tab width. + */ + updateCachedToolTabsWidthMap() { + let thisNode = findDOMNode(this); + for (let tab of thisNode.querySelectorAll(".devtools-tab")) { + let tabId = tab.id.replace("toolbox-tab-", ""); + if (!this._cachedToolTabsWidthMap.has(tabId)) { + let cs = getComputedStyle(tab); + this._cachedToolTabsWidthMap.set(tabId, parseInt(cs.width, 10)); + } } } - removeFlowEvents() { + /** + * Update the overflowed tab array from currently displayed tool tab. + * If calculated result is the same as the current overflowed tab array, this + * function will not update state. + */ + updateOverflowedTabs() { let node = findDOMNode(this); - if (node) { - node.removeEventListener("overflow", this.onOverflow); - node.removeEventListener("underflow", this.onUnderflow); + const toolboxWidth = parseInt(getComputedStyle(node).width, 10); + let { currentToolId } = this.props; + let enabledTabs = this.props.panelDefinitions.map(def => def.id); + let sumWidth = 0; + let visibleTabs = []; + + for (const id of enabledTabs) { + let width = this._cachedToolTabsWidthMap.get(id); + sumWidth += width; + if (sumWidth <= toolboxWidth) { + visibleTabs.push(id); + } else { + sumWidth = sumWidth - width + CHEVRON_BUTTON_WIDTH; + + // If toolbox can't display the Chevron, remove the last tool tab. + if (sumWidth > toolboxWidth) { + let removeTabId = visibleTabs.pop(); + sumWidth -= this._cachedToolTabsWidthMap.get(removeTabId); + } + break; + } + } + + // If the selected tab is in overflowed tabs, insert it into a visible + // toolbox. + if (!visibleTabs.includes(currentToolId) && + enabledTabs.includes(currentToolId)) { + let selectedToolWidth = this._cachedToolTabsWidthMap.get(currentToolId); + while ((sumWidth + selectedToolWidth) > toolboxWidth && + visibleTabs.length > 0) { + let removingToolId = visibleTabs.pop(); + let removingToolWidth = this._cachedToolTabsWidthMap.get(removingToolId); + sumWidth -= removingToolWidth; + } + visibleTabs.push(currentToolId); + } + + if (visibleTabs.length === 0) { + visibleTabs = [enabledTabs[0]]; + } + + let willOverflowTabs = enabledTabs.filter(id => !visibleTabs.includes(id)); + if (!this.equalToolIdArray(this.state.overflowedTabIds, willOverflowTabs)) { + this.setState({ overflowedTabIds: willOverflowTabs }); } } - onOverflow() { - this.setState({ - overflow: true - }); + resizeHandler(evt) { + window.cancelIdleCallback(this._resizeTimerId); + this._resizeTimerId = window.requestIdleCallback(() => { + this.updateOverflowedTabs(); + }, { timeout: 300 }); } - onUnderflow() { - this.setState({ - overflow: false + /** + * Render a button to access overflowed tools, displayed only when the toolbar + * presents an overflow. + */ + renderToolsChevronButton() { + let { + panelDefinitions, + selectTool, + toolbox, + L10N, + } = this.props; + + return button({ + className: "devtools-button tools-chevron-menu", + tabIndex: -1, + title: L10N.getStr("toolbox.allToolsButton.tooltip"), + id: "tools-chevron-menu-button", + onClick: ({ target }) => { + let menu = new Menu({ + id: "tools-chevron-menupopup" + }); + + panelDefinitions.forEach(({id, label}) => { + if (this.state.overflowedTabIds.includes(id)) { + menu.append(new MenuItem({ + click: () => { + selectTool(id); + }, + id: "tools-chevron-menupopup-" + id, + label, + type: "checkbox", + })); + } + }); + + let rect = target.getBoundingClientRect(); + let screenX = target.ownerDocument.defaultView.mozInnerScreenX; + let screenY = target.ownerDocument.defaultView.mozInnerScreenY; + + // Display the popup below the button. + menu.popup(rect.left + screenX, rect.bottom + screenY, toolbox); + return menu; + }, }); } /** * Render all of the tabs, based on the panel definitions and builds out - * a toolbox tab for each of them. Will render an all-tabs button if the + * a toolbox tab for each of them. Will render the chevron button if the * container has an overflow. */ render() { let { currentToolId, focusButton, focusedButton, highlightedTools, panelDefinitions, selectTool, } = this.props; - let tabs = panelDefinitions.map(panelDefinition => ToolboxTab({ - key: panelDefinition.id, - currentToolId, - focusButton, - focusedButton, - highlightedTools, - panelDefinition, - selectTool, - })); + let tabs = panelDefinitions.map(panelDefinition => { + // Don't display overflowed tab. + if (!this.state.overflowedTabIds.includes(panelDefinition.id)) { + return ToolboxTab({ + key: panelDefinition.id, + currentToolId, + focusButton, + focusedButton, + highlightedTools, + panelDefinition, + selectTool, + }); + } + return null; + }); - // A wrapper is needed to get flex sizing correct in XUL. return div( { className: "toolbox-tabs-wrapper" }, div( { className: "toolbox-tabs" }, - tabs - ), - this.state.overflow ? renderAllToolsButton(this.props) : null + tabs, + (this.state.overflowedTabIds.length > 0) + ? this.renderToolsChevronButton() : null + ) ); } } module.exports = ToolboxTabs; - -/** - * Render a button to access all tools, displayed only when the toolbar presents an - * overflow. - */ -function renderAllToolsButton(props) { - let { - currentToolId, - panelDefinitions, - selectTool, - toolbox, - L10N, - } = props; - - return button({ - className: "all-tools-menu all-tabs-menu", - tabIndex: -1, - title: L10N.getStr("toolbox.allToolsButton.tooltip"), - onClick: ({ target }) => { - let menu = new Menu({ - id: "all-tools-menupopup" - }); - panelDefinitions.forEach(({id, label}) => { - menu.append(new MenuItem({ - checked: currentToolId === id, - click: () => { - selectTool(id); - }, - id: "all-tools-menupopup-" + id, - label, - type: "checkbox", - })); - }); - - let rect = target.getBoundingClientRect(); - let screenX = target.ownerDocument.defaultView.mozInnerScreenX; - let screenY = target.ownerDocument.defaultView.mozInnerScreenY; - - // Display the popup below the button. - menu.popup(rect.left + screenX, rect.bottom + screenY, toolbox); - return menu; - }, - }); -}
--- a/devtools/client/framework/components/toolbox-toolbar.js +++ b/devtools/client/framework/components/toolbox-toolbar.js @@ -2,17 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const { Component, createFactory } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const {div, button} = dom; -const {openTrustedLink} = require("devtools/client/shared/link"); +const {openWebLink} = require("devtools/client/shared/link"); const Menu = require("devtools/client/framework/menu"); const MenuItem = require("devtools/client/framework/menu-item"); const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab")); const ToolboxTabs = createFactory(require("devtools/client/framework/components/toolbox-tabs")); /** * This is the overall component for the toolbox toolbar. It is designed to not know how @@ -172,26 +172,26 @@ function renderToolboxButtons({focusedBu onKeyDown(event); } }); }); // Add the appropriate separator, if needed. let children = renderedButtons; if (renderedButtons.length) { + if (isStart) { + children.push(renderSeparator()); // For the end group we add a separator *before* the RDM button if it - // exists. - if (rdmIndex !== -1) { + // exists, but only if it is not the only button. + } else if (rdmIndex !== -1 && visibleButtons.length > 1) { children.splice( children.length - 1, 0, renderSeparator() ); - } else { - children.push(renderSeparator()); } } return div({id: `toolbox-buttons-${isStart ? "start" : "end"}`}, ...children); } /** * Render a separator. @@ -389,29 +389,29 @@ function showMeatballMenu( })); if (menu.items.length) { menu.append(new MenuItem({ type: "separator" })); } // Getting started menu.append(new MenuItem({ - id: "toolbox-meatball-menu-gettingstarted", - label: L10N.getStr("toolbox.meatballMenu.gettingStarted.label"), + id: "toolbox-meatball-menu-documentation", + label: L10N.getStr("toolbox.meatballMenu.documentation.label"), click: () => { - openTrustedLink("https://developer.mozilla.org/docs/Tools", toolbox); + openWebLink("https://developer.mozilla.org/docs/Tools", toolbox); }, })); // Give feedback menu.append(new MenuItem({ - id: "toolbox-meatball-menu-feedback", - label: L10N.getStr("toolbox.meatballMenu.giveFeedback.label"), + id: "toolbox-meatball-menu-community", + label: L10N.getStr("toolbox.meatballMenu.community.label"), click: () => { - openTrustedLink("https://discourse.mozilla.org/c/devtools", toolbox); + openWebLink("https://discourse.mozilla.org/c/devtools", toolbox); }, })); const rect = menuButton.getBoundingClientRect(); const screenX = menuButton.ownerDocument.defaultView.mozInnerScreenX; const screenY = menuButton.ownerDocument.defaultView.mozInnerScreenY; // Display the popup below the button.
--- a/devtools/client/framework/test/browser.ini +++ b/devtools/client/framework/test/browser.ini @@ -108,18 +108,18 @@ skip-if = e10s # Bug 1069044 - destroyIn [browser_toolbox_telemetry_close.js] [browser_toolbox_textbox_context_menu.js] [browser_toolbox_theme.js] [browser_toolbox_theme_registration.js] [browser_toolbox_toggle.js] [browser_toolbox_tool_ready.js] [browser_toolbox_tool_remote_reopen.js] [browser_toolbox_toolbar_overflow.js] +[browser_toolbox_toolbar_reorder_by_width.js] [browser_toolbox_tools_per_toolbox_registration.js] -[browser_toolbox_transport_events.js] [browser_toolbox_view_source_01.js] [browser_toolbox_view_source_02.js] [browser_toolbox_view_source_03.js] [browser_toolbox_view_source_04.js] [browser_toolbox_window_reload_target.js] [browser_toolbox_window_shortcuts.js] skip-if = os == "mac" && os_version == "10.8" || os == "win" && os_version == "5.1" # Bug 851129 - Re-enable browser_toolbox_window_shortcuts.js test after leaks are fixed [browser_toolbox_window_title_changes.js]
--- a/devtools/client/framework/test/browser_toolbox_options.js +++ b/devtools/client/framework/test/browser_toolbox_options.js @@ -15,16 +15,17 @@ const {PrefObserver} = require("devtools add_task(async function() { const URL = "data:text/html;charset=utf8,test for dynamically registering " + "and unregistering tools"; registerNewTool(); let tab = await addTab(URL); let target = TargetFactory.forTab(tab); toolbox = await gDevTools.showToolbox(target); + doc = toolbox.doc; await registerNewPerToolboxTool(); await testSelectTool(); await testOptionsShortcut(); await testOptions(); await testToggleTools(); // Test that registered WebExtensions becomes entries in the @@ -424,21 +425,21 @@ function checkUnregistered(toolId, defer ok(!doc.getElementById("toolbox-tab-" + toolId), "Tab removed for " + toolId); } else { ok(false, "Something went wrong, " + toolId + " was not unregistered"); } deferred.resolve(); } -function checkRegistered(toolId, deferred, data) { +async function checkRegistered(toolId, deferred, data) { if (data == toolId) { ok(true, "Correct tool added back"); // checking tab on the toolbox - let button = doc.getElementById("toolbox-tab-" + toolId); + let button = await lookupButtonForToolId(toolId); ok(button, "Tab added back for " + toolId); } else { ok(false, "Something went wrong, " + toolId + " was not registered"); } deferred.resolve(); } function GetPref(name) { @@ -450,16 +451,36 @@ function GetPref(name) { return Services.prefs.getIntPref(name); case Services.prefs.PREF_BOOL: return Services.prefs.getBoolPref(name); default: throw new Error("Unknown type"); } } +/** + * Find the button from specified toolId. + * Generally, button which access to the tool panel is in toolbox or + * tools menu(in the Chevron menu). + */ +async function lookupButtonForToolId(toolId) { + let button = doc.getElementById("toolbox-tab-" + toolId); + if (!button) { + // search from the tools menu. + let menuPopup = await openChevronMenu(toolbox); + button = doc.querySelector("#tools-chevron-menupopup-" + toolId); + + info("Closing the tools-chevron-menupopup popup"); + let onPopupHidden = once(menuPopup, "popuphidden"); + menuPopup.hidePopup(); + await onPopupHidden; + } + return button; +} + async function cleanup() { gDevTools.unregisterTool("test-tool"); await toolbox.destroy(); gBrowser.removeCurrentTab(); for (let pref of modifiedPrefs) { Services.prefs.clearUserPref(pref); } toolbox = doc = panelWin = modifiedPrefs = null;
--- a/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js +++ b/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js @@ -1,17 +1,22 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -const TEST_URL = "data:text/html;charset=utf8,test for dynamically " + - "registering and unregistering tools"; +let TEST_URL = "data:text/html;charset=utf8,test for dynamically " + + "registering and unregistering tools"; + +// The frames button is only shown if the page has at least one iframe so we +// need to add one to the test page. +TEST_URL += "<iframe src=\"data:text/plain,iframe\"></iframe>"; + var doc = null, toolbox = null, panelWin = null, modifiedPrefs = []; function test() { addTab(TEST_URL).then(tab => { let target = TargetFactory.forTab(tab); gDevTools.showToolbox(target) .then(testSelectTool) .then(testToggleToolboxButtons) @@ -55,53 +60,43 @@ function testSelectTool(devtoolsToolbox) return deferred.promise; } function testPreferenceAndUIStateIsConsistent() { let checkNodes = [...panelWin.document.querySelectorAll( "#enabled-toolbox-buttons-box input[type=checkbox]")]; let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")]; - // The noautohide button is only displayed in the browser toolbox - let toolbarButtons = toolbox.toolbarButtons.filter( - tool => tool.id != "command-button-noautohide"); - - for (let tool of toolbarButtons) { + for (let tool of toolbox.toolbarButtons) { let isVisible = getBoolPref(tool.visibilityswitch); let button = toolboxButtonNodes.find(toolboxButton => toolboxButton.id === tool.id); is(!!button, isVisible, "Button visibility matches pref for " + tool.id); let check = checkNodes.filter(node => node.id === tool.id)[0]; is(check.checked, isVisible, "Checkbox should be selected based on current pref for " + tool.id); } } function testToggleToolboxButtons() { let checkNodes = [...panelWin.document.querySelectorAll( "#enabled-toolbox-buttons-box input[type=checkbox]")]; - // The noautohide button is only displayed in the browser toolbox, and the element - // picker button is not toggleable. - let toolbarButtons = toolbox.toolbarButtons.filter( - tool => tool.id != "command-button-noautohide"); - let visibleToolbarButtons = toolbox.toolbarButtons.filter(tool => tool.isVisible); - let toolbarButtonNodes = [...doc.querySelectorAll(".command-button")].filter( - btn => btn.id != "command-button-noautohide"); + let toolbarButtonNodes = [...doc.querySelectorAll(".command-button")]; - is(checkNodes.length, toolbarButtons.length, + is(checkNodes.length, toolbox.toolbarButtons.length, "All of the buttons are toggleable."); is(visibleToolbarButtons.length, toolbarButtonNodes.length, "All of the DOM buttons are toggleable."); - for (let tool of toolbarButtons) { + for (let tool of toolbox.toolbarButtons) { let id = tool.id; let matchedCheckboxes = checkNodes.filter(node => node.id === id); let matchedButtons = toolbarButtonNodes.filter(button => button.id === id); is(matchedCheckboxes.length, 1, "There should be a single toggle checkbox for: " + id); if (tool.isVisible) { is(matchedButtons.length, 1, "There should be a DOM button for the visible: " + id); @@ -112,24 +107,24 @@ function testToggleToolboxButtons() { "There should not be a DOM button for the invisible: " + id); } is(matchedCheckboxes[0].nextSibling.textContent, tool.description, "The label for checkbox matches the tool definition."); } // Store modified pref names so that they can be cleared on error. - for (let tool of toolbarButtons) { + for (let tool of toolbox.toolbarButtons) { let pref = tool.visibilityswitch; modifiedPrefs.push(pref); } // Try checking each checkbox, making sure that it changes the preference for (let node of checkNodes) { - let tool = toolbarButtons.filter( + let tool = toolbox.toolbarButtons.filter( commandButton => commandButton.id === node.id)[0]; let isVisible = getBoolPref(tool.visibilityswitch); testPreferenceAndUIStateIsConsistent(); node.click(); testPreferenceAndUIStateIsConsistent(); let isVisibleAfterClick = getBoolPref(tool.visibilityswitch);
--- a/devtools/client/framework/test/browser_toolbox_toolbar_overflow.js +++ b/devtools/client/framework/test/browser_toolbox_toolbar_overflow.js @@ -7,80 +7,67 @@ // Test that a button to access tools hidden by toolbar overflow is displayed when the // toolbar starts to present an overflow. let { Toolbox } = require("devtools/client/framework/toolbox"); add_task(async function() { let tab = await addTab("about:blank"); - info("Open devtools on the Inspector in a separate window"); - let toolbox = await openToolboxForTab(tab, "inspector", Toolbox.HostType.WINDOW); + info("Open devtools on the Inspector in a bottom dock"); + let toolbox = await openToolboxForTab(tab, "inspector", Toolbox.HostType.BOTTOM); let hostWindow = toolbox.win.parent; let originalWidth = hostWindow.outerWidth; let originalHeight = hostWindow.outerHeight; info("Resize devtools window to a width that should not trigger any overflow"); let onResize = once(hostWindow, "resize"); - hostWindow.resizeTo(640, 300); + hostWindow.resizeTo(1350, 300); await onResize; + waitUntil(() => { + // Wait for all buttons are displayed. + return toolbox.panelDefinitions.length !== + toolbox.doc.querySelectorAll(".devtools-tab").length; + }); - let allToolsButton = toolbox.doc.querySelector(".all-tools-menu"); - ok(!allToolsButton, "The all tools button is not displayed"); + let chevronMenuButton = toolbox.doc.querySelector(".tools-chevron-menu"); + ok(!chevronMenuButton, "The chevron menu button is not displayed"); info("Resize devtools window to a width that should trigger an overflow"); onResize = once(hostWindow, "resize"); - hostWindow.resizeTo(300, 300); + hostWindow.resizeTo(800, 300); await onResize; - - info("Wait until the all tools button is available"); - await waitUntil(() => toolbox.doc.querySelector(".all-tools-menu")); + waitUntil(() => !toolbox.doc.querySelector(".tools-chevron-menu")); - allToolsButton = toolbox.doc.querySelector(".all-tools-menu"); - ok(allToolsButton, "The all tools button is displayed"); + info("Wait until the chevron menu button is available"); + await waitUntil(() => toolbox.doc.querySelector(".tools-chevron-menu")); - info("Open the all-tools-menupopup and verify that the inspector button is checked"); - let menuPopup = await openAllToolsMenu(toolbox); + chevronMenuButton = toolbox.doc.querySelector(".tools-chevron-menu"); + ok(chevronMenuButton, "The chevron menu button is displayed"); + + info("Open the tools-chevron-menupopup and verify that the inspector button is checked"); + let menuPopup = await openChevronMenu(toolbox); - let inspectorButton = toolbox.doc.querySelector("#all-tools-menupopup-inspector"); - ok(inspectorButton, "The inspector button is available"); - ok(inspectorButton.getAttribute("checked"), "The inspector button is checked"); + let inspectorButton = toolbox.doc.querySelector("#tools-chevron-menupopup-inspector"); + ok(!inspectorButton, "The chevron menu doesn't have the inspector button."); + + let consoleButton = toolbox.doc.querySelector("#tools-chevron-menupopup-webconsole"); + ok(!consoleButton, "The chevron menu doesn't have the console button."); - let consoleButton = toolbox.doc.querySelector("#all-tools-menupopup-webconsole"); - ok(consoleButton, "The console button is available"); - ok(!consoleButton.getAttribute("checked"), "The console button is not checked"); + let storageButton = toolbox.doc.querySelector("#tools-chevron-menupopup-storage"); + ok(storageButton, "The chevron menu has the storage button."); - info("Switch to the webconsole using the all-tools-menupopup popup"); - let onSelected = toolbox.once("webconsole-selected"); - consoleButton.click(); + info("Switch to the performance using the tools-chevron-menupopup popup"); + let onSelected = toolbox.once("storage-selected"); + storageButton.click(); await onSelected; - info("Closing the all-tools-menupopup popup"); + info("Closing the tools-chevron-menupopup popup"); let onPopupHidden = once(menuPopup, "popuphidden"); menuPopup.hidePopup(); await onPopupHidden; - info("Re-open the all-tools-menupopup and verify that the console button is checked"); - menuPopup = await openAllToolsMenu(toolbox); - - inspectorButton = toolbox.doc.querySelector("#all-tools-menupopup-inspector"); - ok(!inspectorButton.getAttribute("checked"), "The inspector button is not checked"); - - consoleButton = toolbox.doc.querySelector("#all-tools-menupopup-webconsole"); - ok(consoleButton.getAttribute("checked"), "The console button is checked"); - info("Restore the original window size"); + onResize = once(hostWindow, "resize"); hostWindow.resizeTo(originalWidth, originalHeight); + await onResize; }); - -async function openAllToolsMenu(toolbox) { - let allToolsButton = toolbox.doc.querySelector(".all-tools-menu"); - EventUtils.synthesizeMouseAtCenter(allToolsButton, {}, toolbox.win); - - let menuPopup = toolbox.doc.querySelector("#all-tools-menupopup"); - ok(menuPopup, "all-tools-menupopup is available"); - - info("Waiting for the menu popup to be displayed"); - await waitUntil(() => menuPopup && menuPopup.state === "open"); - - return menuPopup; -}
new file mode 100644 --- /dev/null +++ b/devtools/client/framework/test/browser_toolbox_toolbar_reorder_by_width.js @@ -0,0 +1,106 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// This test will: +// +// * Confirm that currently selected button to access tools will not hide due to overflow. +// In this case, a button which is located on the left of a currently selected will hide. +// * Confirm that a button to access tool will hide when registering a new panel. +// +// Note that this test is based on the tab ordinal is fixed. +// i.e. After changed by Bug 1226272, this test might fail. + +let { Toolbox } = require("devtools/client/framework/toolbox"); + +add_task(async function() { + let tab = await addTab("about:blank"); + + info("Open devtools on the Storage in a sidebar."); + let toolbox = await openToolboxForTab(tab, "storage", Toolbox.HostType.BOTTOM); + + info("Waiting for the window to be resized"); + let {hostWin, originalWidth, originalHeight} = await resizeWindow(toolbox, 800); + + info("Wait until the tools menu button is available"); + await waitUntil(() => toolbox.doc.querySelector(".tools-chevron-menu")); + + let toolsMenuButton = toolbox.doc.querySelector(".tools-chevron-menu"); + ok(toolsMenuButton, "The tools menu button is displayed"); + + info("Confirm that selected tab is not hidden."); + let storageButton = toolbox.doc.querySelector("#toolbox-tab-storage"); + ok(storageButton, "The storage tab is on toolbox."); + + await resizeWindow(toolbox, originalWidth, originalHeight); +}); + +add_task(async function() { + let tab = await addTab("about:blank"); + + info("Open devtools on the Storage in a sidebar."); + let toolbox = await openToolboxForTab(tab, "storage", Toolbox.HostType.BOTTOM); + + info("Resize devtools window to a width that should trigger an overflow"); + let {hostWin, originalWidth, originalHeight} = await resizeWindow(toolbox, 800); + + info("Regist a new tab"); + let onRegistered = toolbox.once("tool-registered"); + gDevTools.registerTool({ + id: "test-tools", + label: "Test Tools", + isMenu: true, + isTargetSupported: () => true, + build: function() {}, + }); + await onRegistered; + + info("Open the tools menu button."); + let popup = await openChevronMenu(toolbox); + + info("The registered new tool tab should be in the tools menu."); + let testToolsButton = toolbox.doc.querySelector("#tools-chevron-menupopup-test-tools"); + ok(testToolsButton, "The tools menu has a registered new tool button."); + + info("Closing the tools-chevron-menupopup popup"); + let onPopupHidden = once(popup, "popuphidden"); + popup.hidePopup(); + await onPopupHidden; + + info("Unregistering test-tools"); + let onUnregistered = toolbox.once("tool-unregistered"); + gDevTools.unregisterTool("test-tools"); + await onUnregistered; + + info("Open the tools menu button."); + popup = await openChevronMenu(toolbox); + + info("An unregistered new tool tab should not be in the tools menu."); + testToolsButton = toolbox.doc.querySelector("#tools-chevron-menupopup-test-tools"); + ok(!testToolsButton, "The tools menu doesn't have a unregistered new tool button."); + + info("Closing the tools-chevron-menupopup popup"); + onPopupHidden = once(popup, "popuphidden"); + popup.hidePopup(); + await onPopupHidden; + + await resizeWindow(toolbox, originalWidth, originalHeight); +}); + +async function resizeWindow(toolbox, width, height) { + let hostWindow = toolbox.win.parent; + let originalWidth = hostWindow.outerWidth; + let originalHeight = hostWindow.outerHeight; + let toWidth = width || originalWidth; + let toHeight = height || originalHeight; + + info("Resize devtools window to a width that should trigger an overflow"); + let onResize = once(hostWindow, "resize"); + hostWindow.resizeTo(toWidth, toHeight); + await onResize; + + return {hostWindow, originalWidth, originalHeight}; +}
deleted file mode 100644 --- a/devtools/client/framework/test/browser_toolbox_transport_events.js +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const { on, off } = require("devtools/shared/event-emitter"); -const { DebuggerClient } = require("devtools/shared/client/debugger-client"); - -function test() { - gDevTools.on("toolbox-created", onToolboxCreated); - on(DebuggerClient, "connect", onDebuggerClientConnect); - - addTab("about:blank").then(function() { - let target = TargetFactory.forTab(gBrowser.selectedTab); - gDevTools.showToolbox(target, "webconsole").then(testResults); - }); -} - -function testResults(toolbox) { - testPackets(sent1, received1); - testPackets(sent2, received2); - - cleanUp(toolbox); -} - -function cleanUp(toolbox) { - gDevTools.off("toolbox-created", onToolboxCreated); - off(DebuggerClient, "connect", onDebuggerClientConnect); - - toolbox.destroy().then(function() { - // TODO: fixme. - // eslint-disable-next-line mozilla/no-arbitrary-setTimeout - setTimeout(() => { - gBrowser.removeCurrentTab(); - executeSoon(function() { - finish(); - }); - }, 1000); - }); -} - -function testPackets(sent, received) { - ok(sent.length > 0, "There must be at least one sent packet"); - ok(received.length > 0, "There must be at leaset one received packet"); - - if (!sent.length || received.length) { - return; - } - - let sentPacket = sent[0]; - let receivedPacket = received[0]; - - is(receivedPacket.from, "root", - "The first received packet is from the root"); - is(receivedPacket.applicationType, "browser", - "The first received packet has browser type"); - is(sentPacket.type, "listTabs", - "The first sent packet is for list of tabs"); -} - -// Listen to the transport object that is associated with the -// default Toolbox debugger client -var sent1 = []; -var received1 = []; - -function send1(packet) { - sent1.push(packet); -} - -function onPacket1(packet) { - received1.push(packet); -} - -function onToolboxCreated(toolbox) { - toolbox.target.makeRemote(); - let client = toolbox.target.client; - let transport = client._transport; - - transport.on("send", send1); - transport.on("packet", onPacket1); - - client.addOneTimeListener("closed", () => { - transport.off("send", send1); - transport.off("packet", onPacket1); - }); -} - -// Listen to all debugger client object protocols. -var sent2 = []; -var received2 = []; - -function send2(packet) { - sent2.push(packet); -} - -function onPacket2(packet) { - received2.push(packet); -} - -function onDebuggerClientConnect(client) { - let transport = client._transport; - - transport.on("send", send2); - transport.on("packet", onPacket2); - - client.addOneTimeListener("closed", () => { - transport.off("send", send2); - transport.off("packet", onPacket2); - }); -}
--- a/devtools/client/framework/test/head.js +++ b/devtools/client/framework/test/head.js @@ -242,8 +242,21 @@ DevToolPanel.prototype = { /** * Create a simple devtools test panel that implements the minimum API needed to be * registered and opened in the toolbox. */ function createTestPanel(iframeWindow, toolbox) { return new DevToolPanel(iframeWindow, toolbox); } + +async function openChevronMenu(toolbox) { + let chevronMenuButton = toolbox.doc.querySelector(".tools-chevron-menu"); + EventUtils.synthesizeMouseAtCenter(chevronMenuButton, {}, toolbox.win); + + let menuPopup = toolbox.doc.querySelector("#tools-chevron-menupopup"); + ok(menuPopup, "tools-chevron-menupopup is available"); + + info("Waiting for the menu popup to be displayed"); + await waitUntil(() => menuPopup && menuPopup.state === "open"); + + return menuPopup; +}
--- a/devtools/client/framework/toolbox-options.js +++ b/devtools/client/framework/toolbox-options.js @@ -179,17 +179,17 @@ OptionsPanel.prototype = { let createCommandCheckbox = button => { let checkboxLabel = this.panelDoc.createElement("label"); let checkboxSpanLabel = this.panelDoc.createElement("span"); checkboxSpanLabel.textContent = button.description; let checkboxInput = this.panelDoc.createElement("input"); checkboxInput.setAttribute("type", "checkbox"); checkboxInput.setAttribute("id", button.id); - if (button.isVisible) { + if (Services.prefs.getBoolPref(button.visibilityswitch, true)) { checkboxInput.setAttribute("checked", true); } checkboxInput.addEventListener("change", onCheckboxClick.bind(this, checkboxInput)); checkboxLabel.appendChild(checkboxInput); checkboxLabel.appendChild(checkboxSpanLabel); return checkboxLabel;
--- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -761,32 +761,35 @@ Toolbox.prototype = { * argument, to be called whenever the checked state changes. * @property {Function} teardown - Function run on toolbox close to let a chance to * unregister listeners set when `setup` was called and avoid * memory leaks. The same arguments than `setup` function are * passed to `teardown`. * @property {Function} isTargetSupported - Function to automatically enable/disable * the button based on the target. If the target don't support * the button feature, this method should return false. + * @property {Function} isCurrentlyVisible - Function to automatically + * hide/show the button based on current state. * @property {Function} isChecked - Optional function called to known if the button * is toggled or not. The function should return true when * the button should be displayed as toggled on. */ _createButtonState: function(options) { let isCheckedValue = false; const { id, className, description, disabled, onClick, isInStartContainer, setup, teardown, isTargetSupported, + isCurrentlyVisible, isChecked, onKeyDown } = options; const toolbox = this; const button = { id, className, description, @@ -797,16 +800,17 @@ Toolbox.prototype = { } }, onKeyDown(event) { if (typeof onKeyDown == "function") { onKeyDown(event, toolbox); } }, isTargetSupported, + isCurrentlyVisible, get isChecked() { if (typeof isChecked == "function") { return isChecked(toolbox); } return isCheckedValue; }, set isChecked(value) { // Note that if options.isChecked is given, this is ignored @@ -1235,16 +1239,19 @@ Toolbox.prototype = { _buildFrameButton() { this.frameButton = this._createButtonState({ id: "command-button-frames", description: L10N.getStr("toolbox.frames.tooltip"), onClick: this.showFramesMenu, isTargetSupported: target => { return target.activeTab && target.activeTab.traits.frames; }, + isCurrentlyVisible: () => { + return this.frameMap.size > 1; + }, onKeyDown: this.handleKeyDownOnFramesButton }); return this.frameButton; }, /** * Toggle the picker, but also decide whether or not the highlighter should @@ -1376,26 +1383,33 @@ Toolbox.prototype = { }, /** * Ensure the visibility of each toolbox button matches the preference value. */ _commandIsVisible: function(button) { const { isTargetSupported, + isCurrentlyVisible, visibilityswitch } = button; - let visible = Services.prefs.getBoolPref(visibilityswitch, true); - - if (isTargetSupported) { - return visible && isTargetSupported(this.target); + if (!Services.prefs.getBoolPref(visibilityswitch, true)) { + return false; + } + + if (isTargetSupported && !isTargetSupported(this.target)) { + return false; } - return visible; + if (isCurrentlyVisible && !isCurrentlyVisible()) { + return false; + } + + return true; }, /** * Build a panel for a tool definition. * * @param {string} toolDefinition * Tool definition of the tool to build a tab for. */ @@ -2247,20 +2261,16 @@ Toolbox.prototype = { * id {Number}: frame ID * url {String}: frame URL * title {String}: frame title * destroy {Boolean}: Set to true if destroyed * parentID {Number}: ID of the parent frame (not set * for top level window) */ _updateFrames: function(data) { - if (!Services.prefs.getBoolPref("devtools.command-button-frames.enabled")) { - return; - } - // We may receive this event before the toolbox is ready. if (!this.isReady) { return; } // Store (synchronize) data about all existing frames on the backend if (data.destroyAll) { this.frameMap.clear(); @@ -2297,16 +2307,20 @@ Toolbox.prototype = { let topFrameSelected = frame ? !frame.parentID : false; this._framesButtonChecked = false; // If non-top level frame is selected the toolbar button is // marked as 'checked' indicating that a child frame is active. if (!topFrameSelected && this.selectedFrameId) { this._framesButtonChecked = false; } + + // We may need to hide/show the frames button now. + this.frameButton.isVisible = this._commandIsVisible(this.frameButton); + this.component.setToolboxButtons(this.toolbarButtons); }, /** * Returns a 0-based selected frame depth. * * For example, if the root frame is selected, the returned value is 0. For a sub-frame * of the root document, the returned value is 1, and so on. */
--- a/devtools/client/jar.mn +++ b/devtools/client/jar.mn @@ -145,16 +145,17 @@ devtools.jar: skin/images/command-screenshot.svg (themes/images/command-screenshot.svg) skin/images/command-responsivemode.svg (themes/images/command-responsivemode.svg) skin/images/command-pick.svg (themes/images/command-pick.svg) skin/images/command-pick-accessibility.svg (themes/images/command-pick-accessibility.svg) skin/images/command-frames.svg (themes/images/command-frames.svg) skin/images/command-eyedropper.svg (themes/images/command-eyedropper.svg) skin/images/command-rulers.svg (themes/images/command-rulers.svg) skin/images/command-measure.svg (themes/images/command-measure.svg) + skin/images/command-chevron.svg (themes/images/command-chevron.svg) skin/markup.css (themes/markup.css) skin/images/editor-error.png (themes/images/editor-error.png) skin/images/breakpoint.svg (themes/images/breakpoint.svg) skin/webconsole.css (themes/webconsole.css) skin/images/webconsole.svg (themes/images/webconsole.svg) skin/images/breadcrumbs-scrollbutton.svg (themes/images/breadcrumbs-scrollbutton.svg) skin/animation.css (themes/animation.css) skin/animationinspector.css (themes/animationinspector.css)
--- a/devtools/client/locales/en-US/toolbox.properties +++ b/devtools/client/locales/en-US/toolbox.properties @@ -168,23 +168,23 @@ toolbox.meatballMenu.hideconsole.label=H toolbox.meatballMenu.noautohide.label=Disable popup auto-hide # LOCALIZATION NOTE (toolbox.meatballMenu.settings.label): This is the label for # the item in the "..." menu in the toolbox that brings up the Settings # (Options) panel. # The keyboard shortcut will be shown to the side of the label. toolbox.meatballMenu.settings.label=Settings -# LOCALIZATION NOTE (toolbox.meatballMenu.gettingStarted.label): This is the -# label for the Getting Started menu item. -toolbox.meatballMenu.gettingStarted.label=Getting started +# LOCALIZATION NOTE (toolbox.meatballMenu.documentation.label): This is the +# label for the Documentation menu item. +toolbox.meatballMenu.documentation.label=Documentation… -# LOCALIZATION NOTE (toolbox.meatballMenu.giveFeedback.label): This is the label -# for the Give feedback menu item. -toolbox.meatballMenu.giveFeedback.label=Give feedback +# LOCALIZATION NOTE (toolbox.meatballMenu.community.label): This is the label +# for the Community menu item. +toolbox.meatballMenu.community.label=Community… # LOCALIZATION NOTE (toolbox.closebutton.tooltip): This is the tooltip for # the close button the developer tools toolbox. toolbox.closebutton.tooltip=Close Developer Tools # LOCALIZATION NOTE (toolbox.allToolsButton.tooltip): This is the tooltip for the # "all tools" button displayed when some tools are hidden by overflow of the toolbar. toolbox.allToolsButton.tooltip=Select another tool
--- a/devtools/client/themes/common.css +++ b/devtools/client/themes/common.css @@ -233,17 +233,17 @@ checkbox:-moz-focusring { .devtools-menulist, .devtools-toolbarbutton, .devtools-button { -moz-appearance: none; background: transparent; border: 1px solid var(--toolbarbutton-border-color); border-radius: 2px; color: var(--theme-body-color); - transition: background 0.05s ease-in-out; + transition: background-color 0.05s ease-in-out; -moz-box-align: center; text-shadow: none; padding: 1px; margin: 1px; /* Button text should not wrap on multiple lines */ white-space: nowrap; } @@ -258,17 +258,16 @@ checkbox:-moz-focusring { color: var(--theme-toolbar-color); direction: ltr; font-size: 11px; } .devtools-button:empty::before { content: ""; display: inline-block; - background-size: cover; background-repeat: no-repeat; vertical-align: middle; } .devtools-button.checked:empty::before { color: var(--theme-toolbar-checked-color); }
new file mode 100644 --- /dev/null +++ b/devtools/client/themes/images/command-chevron.svg @@ -0,0 +1,6 @@ +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 16 16"> + <path fill="context-fill" d="M8.707 7.293l-5-5a1 1 0 0 0-1.414 1.414L6.586 8l-4.293 4.293a1 1 0 1 0 1.414 1.414l5-5a1 1 0 0 0 0-1.414zm6 0l-5-5a1 1 0 0 0-1.414 1.414L12.586 8l-4.293 4.293a1 1 0 1 0 1.414 1.414l5-5a1 1 0 0 0 0-1.414z"></path> +</svg>
--- a/devtools/client/themes/toolbox.css +++ b/devtools/client/themes/toolbox.css @@ -11,16 +11,17 @@ --command-screenshot-image: url(images/command-screenshot.svg); --command-responsive-image: url(images/command-responsivemode.svg); --command-scratchpad-image: url(images/tool-scratchpad.svg); --command-pick-image: url(images/command-pick.svg); --command-pick-accessibility-image: url(images/command-pick-accessibility.svg); --command-frames-image: url(images/command-frames.svg); --command-rulers-image: url(images/command-rulers.svg); --command-measure-image: url(images/command-measure.svg); + --command-chevron-image: url(images/command-chevron.svg); } /* Toolbox tabbar */ .devtools-tabbar { -moz-appearance: none; display: flex; background: var(--theme-tab-toolbar-background); @@ -30,18 +31,17 @@ } .toolbox-tabs-wrapper { position: relative; display: flex; flex: 1; } -.toolbox-tabs-wrapper .all-tools-menu { - border-inline-end: 1px solid var(--theme-splitter-color); +.toolbox-tabs-wrapper .tools-chevron-menu { border-top-width: 0; border-bottom-width: 0; } .toolbox-tabs { position: absolute; top: 0; left: 0; @@ -63,56 +63,39 @@ } /* Toolbox tabs */ .devtools-tab { position: relative; display: flex; align-items: center; - min-width: 32px; min-height: 24px; margin: 0; padding: 0; border: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; background-color: transparent; + flex-shrink: 0; } .devtools-tab-label { font-size: 12px; mask-image: linear-gradient(to left, transparent 0, black 6px); /* Set the end padding on the label to make sure the label gets faded out properly */ padding-inline-end: 10px; min-width: 1px; } .devtools-tab-label:-moz-locale-dir(rtl) { mask-image: linear-gradient(to right, transparent 0, black 6px); } -/* Hide tab icons when the viewport width is limited */ -@media (max-width: 700px) { - .devtools-tab-label { - /* Set the end padding on the label to make sure the label gets faded out properly */ - padding-inline-end: 5px; - } - - .devtools-tab:not(.devtools-tab-icon-only) { - padding-inline-start: 5px !important; - } - - /* Hide the icons */ - .devtools-tab:not(.devtools-tab-icon-only) > img { - display: none; - } -} - .devtools-tab-icon-only { min-width: 24px; } .devtools-tab { color: var(--theme-toolbar-color); } @@ -152,18 +135,30 @@ .devtools-tab.selected > img { fill: var(--theme-toolbar-selected-color); } .devtools-tab.highlighted > img { fill: var(--theme-toolbar-highlighted-color); } +#devtools-chevron-menu-button::before { + -moz-context-properties: fill; + fill: var(--theme-toolbar-photon-icon-color); +} + /* Toolbox controls */ +#tools-chevron-menu-button::before { + top: 0; + offset-inline-end: 0; + background-image: var(--command-chevron-image); + background-position: center; +} + #toolbox-controls { margin-right: 3px; } #toolbox-buttons-end > .devtools-separator { margin-inline-start: 5px; margin-inline-end: 5px; }
--- a/devtools/client/webconsole/new-webconsole.js +++ b/devtools/client/webconsole/new-webconsole.js @@ -250,16 +250,17 @@ NewWebConsoleFrame.prototype = { Services.scriptloader.loadSubScript( "chrome://browser/content/browser-development-helpers.js", this.window); shortcuts.on("CmdOrCtrl+Alt+R", this.window.DevelopmentHelpers.quickRestart); } } else if (Services.prefs.getBoolPref(PREF_SIDEBAR_ENABLED)) { shortcuts.on("Esc", event => { if (!this.jsterm.autocompletePopup || !this.jsterm.autocompletePopup.isOpen) { this.newConsoleOutput.dispatchSidebarClose(); + this.jsterm.focus(); } }); } }, /** * Handler for page location changes. * * @param string uri
--- a/devtools/client/webconsole/test/mochitest/browser.ini +++ b/devtools/client/webconsole/test/mochitest/browser.ini @@ -260,16 +260,17 @@ subsuite = clipboard [browser_webconsole_context_menu_open_url.js] [browser_webconsole_context_menu_store_as_global.js] [browser_webconsole_csp_ignore_reflected_xss_message.js] skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows [browser_webconsole_csp_violation.js] [browser_webconsole_cspro.js] [browser_webconsole_document_focus.js] [browser_webconsole_duplicate_errors.js] +[browser_webconsole_error_with_unicode.js] [browser_webconsole_errors_after_page_reload.js] [browser_webconsole_eval_in_debugger_stackframe.js] [browser_webconsole_eval_in_debugger_stackframe2.js] [browser_webconsole_execution_scope.js] [browser_webconsole_external_script_errors.js] [browser_webconsole_file_uri.js] skip-if = true # Bug 1404382 [browser_webconsole_filter_by_input.js]
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_close_sidebar.js +++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_close_sidebar.js @@ -64,16 +64,18 @@ add_task(async function() { await showSidebar(hud); info("Send escape to hide sidebar"); onSidebarShown = waitForNodeMutation(wrapper, { childList: true }); EventUtils.synthesizeKey("KEY_Escape"); await onSidebarShown; sidebar = hud.ui.document.querySelector(".sidebar"); ok(!sidebar, "Sidebar hidden after sending esc"); + let inputNode = hud.jsterm.inputNode; + ok(hasFocus(inputNode), "console input is focused after closing the sidebar"); }); async function showSidebar(hud) { let onMessage = waitForMessage(hud, "Object"); ContentTask.spawn(gBrowser.selectedBrowser, {}, function() { content.wrappedJSObject.console.log({a: 1}); }); await onMessage;
new file mode 100644 --- /dev/null +++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_error_with_unicode.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Check if an error with Unicode characters is reported correctly. + +"use strict"; + +const TEST_URI = "data:text/html;charset=utf8,<script>\u6e2c</script>"; +const EXPECTED_REPORT = "ReferenceError: \u6e2c is not defined"; + +add_task(async function() { + let hud = await openNewTabAndConsole(TEST_URI); + + // On e10s, the exception is triggered in child process + // and is ignored by test harness + if (!Services.appinfo.browserTabsRemoteAutostart) { + expectUncaughtException(); + } + + info("generate exception and wait for the message"); + + let msg = await waitFor(() => findMessage(hud, EXPECTED_REPORT)); + ok(msg, `Message found: "${EXPECTED_REPORT}"`); +});
--- a/devtools/shared/DevToolsUtils.js +++ b/devtools/shared/DevToolsUtils.js @@ -352,24 +352,32 @@ exports.isSafeJSObject = function(obj) { if (proto && !exports.isSafeJSObject(proto)) { return false; } // Allow non-problematic chrome objects. return true; }; +/** + * Dump with newline - This is a logging function that will only output when + * the preference "devtools.debugger.log" is set to true. Typically it is used + * for logging the remote debugging protocol calls. + */ exports.dumpn = function(str) { if (flags.wantLogging) { dump("DBG-SERVER: " + str + "\n"); } }; /** - * A verbose logger for low-level tracing. + * Dump verbose - This is a verbose logger for low-level tracing, that is typically + * used to provide information about the remote debugging protocol's transport + * mechanisms. The logging can be enabled by changing the preferences + * "devtools.debugger.log" and "devtools.debugger.log.verbose" to true. */ exports.dumpv = function(msg) { if (flags.wantVerbose) { exports.dumpn(msg); } }; /**
--- a/devtools/shared/client/debugger-client.js +++ b/devtools/shared/client/debugger-client.js @@ -169,21 +169,16 @@ DebuggerClient.prototype = { * @return Promise * Resolves once connected with an array whose first element * is the application type, by default "browser", and the second * element is the traits object (help figure out the features * and behaviors of the server we connect to. See RootActor). */ connect: function(onConnected) { let deferred = promise.defer(); - this.emit("connect"); - - // Also emit the event on the |DebuggerClient| object (not on the instance), - // so it's possible to track all instances. - EventEmitter.emit(DebuggerClient, "connect", this); this.addOneTimeListener("connected", (name, applicationType, traits) => { this.traits = traits; if (onConnected) { onConnected(applicationType, traits); } deferred.resolve([applicationType, traits]); });
--- a/devtools/shared/flags.js +++ b/devtools/shared/flags.js @@ -1,18 +1,29 @@ "use strict"; const Services = require("Services"); -/* - * Create a writable property by tracking it with a private variable. +/** + * This module controls various global flags that can be toggled on and off. + * These flags are generally used to change the behavior of the code during + * testing. They are tracked by preferences so that they are propagated + * between the parent and content processes. The flags are exposed via a module + * as a conveniene and to stop from littering preference names throughout the + * code ase. + * + * Each of the flags is documented where it is defined. + */ + +/** * We cannot make a normal property writeable on `exports` because - * the module system freezes it. + * the module system freezes it. This function observes a preference + * and provides the latest value through a getter. */ -function makeWritableFlag(exports, name, pref) { +function makePrefTrackedFlag(exports, name, pref) { let flag; // We don't have access to pref in worker, so disable all logs by default if (isWorker) { flag = false; } else { flag = Services.prefs.getBoolPref(pref, false); let prefObserver = () => { flag = Services.prefs.getBoolPref(pref, false); @@ -28,15 +39,27 @@ function makeWritableFlag(exports, name, } Object.defineProperty(exports, name, { get: function() { return flag; } }); } -makeWritableFlag(exports, "wantLogging", "devtools.debugger.log"); -makeWritableFlag(exports, "wantVerbose", "devtools.debugger.log.verbose"); +/** + * Setting the "devtools.debugger.log" preference to true will enable logging of + * the RDP calls to the debugger server. + */ +makePrefTrackedFlag(exports, "wantLogging", "devtools.debugger.log"); -// When the testing flag is set, various behaviors may be altered from -// production mode, typically to enable easier testing or enhanced -// debugging. -makeWritableFlag(exports, "testing", "devtools.testing"); +/** + * Setting the "devtools.debugger.log.verbose" preference to true will enable a + * more verbose logging of the the RDP. The "devtools.debugger.log" preference + * must be set to true as well for this to have any effect. + */ +makePrefTrackedFlag(exports, "wantVerbose", "devtools.debugger.log.verbose"); + +/** + * Setting the "devtools.testing" preference to true will toggle on certain + * behaviors that can differ from the production version of the code. These + * behaviors typically enable easier testing or enhanced debugging features. + */ +makePrefTrackedFlag(exports, "testing", "devtools.testing");
deleted file mode 100644 --- a/devtools/shared/transport/tests/unit/test_transport_events.js +++ /dev/null @@ -1,70 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -function run_test() { - initTestDebuggerServer(); - - add_task(async function() { - await test_transport_events("socket", socket_transport); - await test_transport_events("local", local_transport); - DebuggerServer.destroy(); - }); - - run_next_test(); -} - -async function test_transport_events(name, transportFactory) { - info(`Started testing of transport: ${name}`); - - Assert.equal(Object.keys(DebuggerServer._connections).length, 0); - - let transport = await transportFactory(); - - // Transport expects the hooks to be not null - transport.hooks = { - onPacket: () => {}, - onClosed: () => {}, - }; - - let rootReceived = transport.once("packet", packet => { - info(`Packet event: ${JSON.stringify(packet)}`); - Assert.equal(packet.from, "root"); - }); - - transport.ready(); - await rootReceived; - - let echoSent = transport.once("send", packet => { - info(`Send event: ${JSON.stringify(packet)}`); - Assert.equal(packet.to, "root"); - Assert.equal(packet.type, "echo"); - }); - - let echoReceived = transport.once("packet", packet => { - info(`Packet event: ${JSON.stringify(packet)}`); - Assert.equal(packet.from, "root"); - Assert.equal(packet.type, "echo"); - }); - - transport.send({ to: "root", type: "echo" }); - await echoSent; - await echoReceived; - - let clientClosed = transport.once("close", () => { - info(`Close event`); - }); - - let serverClosed = DebuggerServer.once("connectionchange", type => { - info(`Server closed`); - Assert.equal(type, "closed"); - }); - - transport.close(); - - await clientClosed; - await serverClosed; - - info(`Finished testing of transport: ${name}`); -}
--- a/devtools/shared/transport/tests/unit/xpcshell.ini +++ b/devtools/shared/transport/tests/unit/xpcshell.ini @@ -12,9 +12,8 @@ support-files = [test_client_server_bulk.js] [test_dbgsocket.js] [test_dbgsocket_connection_drop.js] [test_delimited_read.js] [test_no_bulk.js] [test_packet.js] [test_queue.js] [test_transport_bulk.js] -[test_transport_events.js]
--- a/devtools/shared/transport/transport.js +++ b/devtools/shared/transport/transport.js @@ -25,17 +25,16 @@ const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const { dumpn, dumpv } = DevToolsUtils; const flags = require("devtools/shared/flags"); const StreamUtils = require("devtools/shared/transport/stream-utils"); const { Packet, JSONPacket, BulkPacket } = require("devtools/shared/transport/packets"); const promise = require("promise"); const defer = require("devtools/shared/defer"); - const EventEmitter = require("devtools/shared/event-emitter"); DevToolsUtils.defineLazyGetter(this, "Pipe", () => { return CC("@mozilla.org/pipe;1", "nsIPipe", "init"); }); DevToolsUtils.defineLazyGetter(this, "ScriptableInputStream", () => { return CC("@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream", "init"); @@ -96,18 +95,16 @@ * - onClosed(reason) - called when the connection is closed. |reason| is * an optional nsresult or object, typically passed when the transport is * closed due to some error in a underlying stream. * * See ./packets.js and the Remote Debugging Protocol specification for more * details on the format of these packets. */ function DebuggerTransport(input, output) { - EventEmitter.decorate(this); - this._input = input; this._scriptableInput = new ScriptableInputStream(input); this._output = output; // The current incoming (possibly partial) header, which will determine which // type of Packet |_incoming| below will become. this._incomingHeader = ""; // The current incoming Packet object @@ -129,18 +126,16 @@ * Transmit an object as a JSON packet. * * This method returns immediately, without waiting for the entire * packet to be transmitted, registering event handlers as needed to * transmit the entire packet. Packets are transmitted in the order * they are passed to this method. */ send: function(object) { - this.emit("send", object); - let packet = new JSONPacket(this); packet.object = object; this._outgoing.push(packet); this._flushOutgoing(); }, /** * Transmit streaming data via a bulk packet. @@ -179,34 +174,30 @@ * The stream to copy from. * @return Promise * The promise is resolved when copying completes or * rejected if any (unexpected) errors occur. * This object also emits "progress" events for each chunk * that is copied. See stream-utils.js. */ startBulkSend: function(header) { - this.emit("startbulksend", header); - let packet = new BulkPacket(this); packet.header = header; this._outgoing.push(packet); this._flushOutgoing(); return packet.streamReadyForWriting; }, /** * Close the transport. * @param reason nsresult / object (optional) * The status code or error message that corresponds to the reason for * closing the transport (likely because a stream closed or failed). */ close: function(reason) { - this.emit("close", reason); - this.active = false; this._input.close(); this._scriptableInput.close(); this._output.close(); this._destroyIncoming(); this._destroyAllOutgoing(); if (this.hooks) { this.hooks.onClosed(reason); @@ -473,33 +464,31 @@ /** * Handler triggered by an incoming JSONPacket completing it's |read| method. * Delivers the packet to this.hooks.onPacket. */ _onJSONObjectReady: function(object) { DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => { // Ensure the transport is still alive by the time this runs. if (this.active) { - this.emit("packet", object); this.hooks.onPacket(object); } }, "DebuggerTransport instance's this.hooks.onPacket")); }, /** * Handler triggered by an incoming BulkPacket entering the |read| phase for * the stream portion of the packet. Delivers info about the incoming * streaming data to this.hooks.onBulkPacket. See the main comment on the * transport at the top of this file for more details. */ _onBulkReadReady: function(...args) { DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => { // Ensure the transport is still alive by the time this runs. if (this.active) { - this.emit("bulkpacket", ...args); this.hooks.onBulkPacket(...args); } }, "DebuggerTransport instance's this.hooks.onBulkPacket")); }, /** * Remove all handlers and references related to the current incoming packet, * either because it is now complete or because the transport is closing. @@ -523,35 +512,31 @@ * connection it merely calls the packet dispatcher of the other side. * * @param other LocalDebuggerTransport * The other endpoint for this debugger connection. * * @see DebuggerTransport */ function LocalDebuggerTransport(other) { - EventEmitter.decorate(this); - this.other = other; this.hooks = null; // A packet number, shared between this and this.other. This isn't used by the // protocol at all, but it makes the packet traces a lot easier to follow. this._serial = this.other ? this.other._serial : { count: 0 }; this.close = this.close.bind(this); } LocalDebuggerTransport.prototype = { /** * Transmit a message by directly calling the onPacket handler of the other * endpoint. */ send: function(packet) { - this.emit("send", packet); - let serial = this._serial.count++; if (flags.wantLogging) { // Check 'from' first, as 'echo' packets have both. if (packet.from) { dumpn("Packet " + serial + " sent from " + uneval(packet.from)); } else if (packet.to) { dumpn("Packet " + serial + " sent to " + uneval(packet.to)); } @@ -560,35 +545,32 @@ let other = this.other; if (other) { DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => { // Avoid the cost of JSON.stringify() when logging is disabled. if (flags.wantLogging) { dumpn("Received packet " + serial + ": " + JSON.stringify(packet, null, 2)); } if (other.hooks) { - other.emit("packet", packet); other.hooks.onPacket(packet); } }, "LocalDebuggerTransport instance's this.other.hooks.onPacket")); } }, /** * Send a streaming bulk packet directly to the onBulkPacket handler of the * other endpoint. * * This case is much simpler than the full DebuggerTransport, since there is * no primary stream we have to worry about managing while we hand it off to * others temporarily. Instead, we can just make a single use pipe and be * done with it. */ startBulkSend: function({actor, type, length}) { - this.emit("startbulksend", {actor, type, length}); - let serial = this._serial.count++; dumpn("Sent bulk packet " + serial + " for actor " + actor); if (!this.other) { let error = new Error("startBulkSend: other side of transport missing"); return promise.reject(error); } @@ -611,17 +593,16 @@ StreamUtils.copyStream(pipe.inputStream, output, length); deferred.resolve(copying); return copying; }, stream: pipe.inputStream, done: deferred }; - this.other.emit("bulkpacket", packet); this.other.hooks.onBulkPacket(packet); // Await the result of reading from the stream deferred.promise.then(() => pipe.inputStream.close(), this.close); }, "LocalDebuggerTransport instance's this.other.hooks.onBulkPacket")); // Sender let sendDeferred = defer(); @@ -648,18 +629,16 @@ return sendDeferred.promise; }, /** * Close the transport. */ close: function() { - this.emit("close"); - if (this.other) { // Remove the reference to the other endpoint before calling close(), to // avoid infinite recursion. let other = this.other; this.other = null; other.close(); } if (this.hooks) { @@ -707,18 +686,16 @@ * * |prefix| is a string included in the message names, to distinguish * multiple servers running in the same child process. * * This transport exchanges messages named 'debug:<prefix>:packet', where * <prefix> is |prefix|, whose data is the protocol packet. */ function ChildDebuggerTransport(mm, prefix) { - EventEmitter.decorate(this); - this._mm = mm; this._messageName = "debug:" + prefix + ":packet"; } /* * To avoid confusion, we use 'message' to mean something that * nsIMessageSender conveys, and 'packet' to mean a remote debugging * protocol packet. @@ -746,22 +723,20 @@ }, ready: function() { this._addListener(); }, close: function() { this._removeListener(); - this.emit("close"); this.hooks.onClosed(); }, receiveMessage: function({data}) { - this.emit("packet", data); this.hooks.onPacket(data); }, /** * Helper method to ensure a given `object` can be sent across message manager * without being serialized to JSON. * See https://searchfox.org/mozilla-central/rev/6bfadf95b4a6aaa8bb3b2a166d6c3545983e179a/dom/base/nsFrameMessageManager.cpp#458-469 */ @@ -784,17 +759,16 @@ } return [key]; } } return []; }, send: function(packet) { - this.emit("send", packet); if (flags.testing && !this._canBeSerialized(packet)) { let attributes = this.pathToUnserializable(packet); let msg = "Following packet can't be serialized: " + JSON.stringify(packet); msg += "\nBecause of attributes: " + attributes.join(", ") + "\n"; msg += "Did you pass a function or an XPCOM object in it?"; throw new Error(msg); } try {
--- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -79,21 +79,16 @@ static const RedirEntry kRedirMap[] = { nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT }, { "networking", "chrome://global/content/aboutNetworking.xhtml", nsIAboutModule::ALLOW_SCRIPT }, { - "newaddon", "chrome://mozapps/content/extensions/newaddon.xul", - nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT - }, - { "performance", "chrome://global/content/aboutPerformance.xhtml", nsIAboutModule::ALLOW_SCRIPT }, { "plugins", "chrome://global/content/plugins.html", nsIAboutModule::URI_MUST_LOAD_IN_CHILD }, {
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -13685,17 +13685,17 @@ nsDocShell::OnOverLink(nsIContent* aCont if (!browserChrome2) { browserChrome = do_GetInterface(mTreeOwner); if (!browserChrome) { return rv; } } nsAutoCString spec; - rv = aURI->GetSpec(spec); + rv = aURI->GetDisplaySpec(spec); NS_ENSURE_SUCCESS(rv, rv); NS_ConvertUTF8toUTF16 uStr(spec); mozilla::net::PredictorPredict(aURI, mCurrentURI, nsINetworkPredictor::PREDICT_LINK, aContent->NodePrincipal()->OriginAttributesRef(), nullptr);
--- a/docshell/build/nsDocShellModule.cpp +++ b/docshell/build/nsDocShellModule.cpp @@ -180,17 +180,16 @@ const mozilla::Module::ContractIDEntry k #endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "credits", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "license", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "logo", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "memory", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "mozilla", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "networking", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, - { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newaddon", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "performance", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "plugins", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "serviceworkers", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, #ifndef ANDROID { NS_ABOUT_MODULE_CONTRACTID_PREFIX "profiles", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, #endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "srcdoc", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "support", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
--- a/dom/animation/KeyframeUtils.cpp +++ b/dom/animation/KeyframeUtils.cpp @@ -43,206 +43,27 @@ namespace mozilla { // // ------------------------------------------------------------------ // For the aAllowList parameter of AppendStringOrStringSequence and // GetPropertyValuesPairs. enum class ListAllowance { eDisallow, eAllow }; /** - * A comparator to sort nsCSSPropertyID values such that longhands are sorted - * before shorthands, and shorthands with fewer components are sorted before - * shorthands with more components. - * - * Using this allows us to prioritize values specified by longhands (or smaller - * shorthand subsets) when longhands and shorthands are both specified - * on the one keyframe. - * - * Example orderings that result from this: - * - * margin-left, margin - * - * and: - * - * border-top-color, border-color, border-top, border - */ -class PropertyPriorityComparator -{ -public: - PropertyPriorityComparator() - : mSubpropertyCountInitialized(false) {} - - bool Equals(nsCSSPropertyID aLhs, nsCSSPropertyID aRhs) const - { - return aLhs == aRhs; - } - - bool LessThan(nsCSSPropertyID aLhs, - nsCSSPropertyID aRhs) const - { - bool isShorthandLhs = nsCSSProps::IsShorthand(aLhs); - bool isShorthandRhs = nsCSSProps::IsShorthand(aRhs); - - if (isShorthandLhs) { - if (isShorthandRhs) { - // First, sort shorthands by the number of longhands they have. - uint32_t subpropCountLhs = SubpropertyCount(aLhs); - uint32_t subpropCountRhs = SubpropertyCount(aRhs); - if (subpropCountLhs != subpropCountRhs) { - return subpropCountLhs < subpropCountRhs; - } - // Otherwise, sort by IDL name below. - } else { - // Put longhands before shorthands. - return false; - } - } else { - if (isShorthandRhs) { - // Put longhands before shorthands. - return true; - } - } - // For two longhand properties, or two shorthand with the same number - // of longhand components, sort by IDL name. - return nsCSSProps::PropertyIDLNameSortPosition(aLhs) < - nsCSSProps::PropertyIDLNameSortPosition(aRhs); - } - - uint32_t SubpropertyCount(nsCSSPropertyID aProperty) const - { - if (!mSubpropertyCountInitialized) { - PodZero(&mSubpropertyCount); - mSubpropertyCountInitialized = true; - } - if (mSubpropertyCount[aProperty] == 0) { - uint32_t count = 0; - CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES( - p, aProperty, CSSEnabledState::eForAllContent) { - ++count; - } - mSubpropertyCount[aProperty] = count; - } - return mSubpropertyCount[aProperty]; - } - -private: - // Cache of shorthand subproperty counts. - mutable RangedArray< - uint32_t, - eCSSProperty_COUNT_no_shorthands, - eCSSProperty_COUNT - eCSSProperty_COUNT_no_shorthands> mSubpropertyCount; - mutable bool mSubpropertyCountInitialized; -}; - -/** - * Adaptor for PropertyPriorityComparator to sort objects which have - * a mProperty member. - */ -template <typename T> -class TPropertyPriorityComparator : PropertyPriorityComparator -{ -public: - bool Equals(const T& aLhs, const T& aRhs) const - { - return PropertyPriorityComparator::Equals(aLhs.mProperty, aRhs.mProperty); - } - bool LessThan(const T& aLhs, const T& aRhs) const - { - return PropertyPriorityComparator::LessThan(aLhs.mProperty, aRhs.mProperty); - } -}; - -/** - * Iterator to walk through a PropertyValuePair array using the ordering - * provided by PropertyPriorityComparator. - */ -class PropertyPriorityIterator -{ -public: - explicit PropertyPriorityIterator( - const nsTArray<PropertyValuePair>& aProperties) - : mProperties(aProperties) - { - mSortedPropertyIndices.SetCapacity(mProperties.Length()); - for (size_t i = 0, len = mProperties.Length(); i < len; ++i) { - PropertyAndIndex propertyIndex = { mProperties[i].mProperty, i }; - mSortedPropertyIndices.AppendElement(propertyIndex); - } - mSortedPropertyIndices.Sort(PropertyAndIndex::Comparator()); - } - - class Iter - { - public: - explicit Iter(const PropertyPriorityIterator& aParent) - : mParent(aParent) - , mIndex(0) { } - - static Iter EndIter(const PropertyPriorityIterator &aParent) - { - Iter iter(aParent); - iter.mIndex = aParent.mSortedPropertyIndices.Length(); - return iter; - } - - bool operator!=(const Iter& aOther) const - { - return mIndex != aOther.mIndex; - } - - Iter& operator++() - { - MOZ_ASSERT(mIndex + 1 <= mParent.mSortedPropertyIndices.Length(), - "Should not seek past end iterator"); - mIndex++; - return *this; - } - - const PropertyValuePair& operator*() - { - MOZ_ASSERT(mIndex < mParent.mSortedPropertyIndices.Length(), - "Should not try to dereference an end iterator"); - return mParent.mProperties[mParent.mSortedPropertyIndices[mIndex].mIndex]; - } - - private: - const PropertyPriorityIterator& mParent; - size_t mIndex; - }; - - Iter begin() { return Iter(*this); } - Iter end() { return Iter::EndIter(*this); } - -private: - struct PropertyAndIndex - { - nsCSSPropertyID mProperty; - size_t mIndex; // Index of mProperty within mProperties - - typedef TPropertyPriorityComparator<PropertyAndIndex> Comparator; - }; - - const nsTArray<PropertyValuePair>& mProperties; - nsTArray<PropertyAndIndex> mSortedPropertyIndices; -}; - -/** * A property-values pair obtained from the open-ended properties * discovered on a regular keyframe or property-indexed keyframe object. * * Single values (as required by a regular keyframe, and as also supported * on property-indexed keyframes) are stored as the only element in * mValues. */ struct PropertyValuesPair { nsCSSPropertyID mProperty; nsTArray<nsString> mValues; - - typedef TPropertyPriorityComparator<PropertyValuesPair> Comparator; }; /** * An additional property (for a property-values pair) found on a * BaseKeyframe or BasePropertyIndexedKeyframe object. */ struct AdditionalProperty {
--- a/dom/base/gen-usecounters.py +++ b/dom/base/gen-usecounters.py @@ -56,22 +56,20 @@ def generate_list(f, counters): print_optional_macro_undeclare('USE_COUNTER_CSS_PROPERTY') print_optional_macro_undeclare('USE_COUNTER_CUSTOM') def generate_property_map(f, counters): print(AUTOGENERATED_WARNING_COMMENT, file=f) print(''' enum { #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_ - #define CSS_PROP_LIST_INCLUDE_LOGICAL #define CSS_PROP(name_, id_, method_, ...) \\ USE_COUNTER_FOR_CSS_PROPERTY_##method_ = eUseCounter_UNKNOWN, #include "nsCSSPropList.h" #undef CSS_PROP - #undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP_PUBLIC_OR_PRIVATE }; ''', file=f) for counter in counters: if counter['type'] == 'property': prop = counter['property_name'] print('#define USE_COUNTER_FOR_CSS_PROPERTY_%s eUseCounter_property_%s' % (prop, prop), file=f)
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -271,16 +271,17 @@ nsIBidiKeyboard *nsContentUtils::sBidiKe uint32_t nsContentUtils::sScriptBlockerCount = 0; uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = nullptr; uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; bool nsContentUtils::sIsHandlingKeyBoardEvent = false; bool nsContentUtils::sAllowXULXBL_for_file = false; +bool nsContentUtils::sDisablePopups = false; nsString* nsContentUtils::sShiftText = nullptr; nsString* nsContentUtils::sControlText = nullptr; nsString* nsContentUtils::sMetaText = nullptr; nsString* nsContentUtils::sOSText = nullptr; nsString* nsContentUtils::sAltText = nullptr; nsString* nsContentUtils::sModifierSeparator = nullptr; @@ -728,16 +729,19 @@ nsContentUtils::Init() "dom.placeholder.show_on_focus", true); Preferences::AddBoolVarCache(&sAutoFocusEnabled, "browser.autofocus", true); Preferences::AddBoolVarCache(&sIsBytecodeCacheEnabled, "dom.script_loader.bytecode_cache.enabled", false); + Preferences::AddBoolVarCache(&sDisablePopups, + "dom.disable_open_during_load", false); + Preferences::AddIntVarCache(&sBytecodeCacheStrategy, "dom.script_loader.bytecode_cache.strategy", 0); nsDependentCString buildID(mozilla::PlatformBuildID()); sJSBytecodeMimeType = new nsCString(NS_LITERAL_CSTRING("javascript/moz-bytecode-") + buildID); Element::InitCCCallbacks(); @@ -11008,8 +11012,29 @@ nsContentUtils::InnerOrOuterWindowCreate /* static */ void nsContentUtils::InnerOrOuterWindowDestroyed() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(sInnerOrOuterWindowCount > 0); --sInnerOrOuterWindowCount; } + +/* static */ bool +nsContentUtils::CanShowPopup(nsIPrincipal* aPrincipal) +{ + MOZ_ASSERT(aPrincipal); + uint32_t permit; + nsCOMPtr<nsIPermissionManager> permissionManager = + services::GetPermissionManager(); + + if (permissionManager && + NS_SUCCEEDED(permissionManager->TestPermissionFromPrincipal(aPrincipal, "popup", &permit))) { + if (permit == nsIPermissionManager::ALLOW_ACTION) { + return true; + } + if (permit == nsIPermissionManager::DENY_ACTION) { + return false; + } + } + + return !sDisablePopups; +}
--- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -3286,16 +3286,18 @@ public: // Get a serial number for a newly created inner or outer window. static uint32_t InnerOrOuterWindowCreated(); // Record that an inner or outer window has been destroyed. static void InnerOrOuterWindowDestroyed(); // Get the current number of inner or outer windows. static int32_t GetCurrentInnerOrOuterWindowCount() { return sInnerOrOuterWindowCount; } + static bool CanShowPopup(nsIPrincipal* aPrincipal); + private: static bool InitializeEventTable(); static nsresult EnsureStringBundle(PropertiesFile aFile); static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal, nsIPrincipal* aPrincipal); @@ -3413,16 +3415,17 @@ private: static AutoTArray<nsCOMPtr<nsIRunnable>, 8>* sBlockedScriptRunners; static uint32_t sRunnersCountAtFirstBlocker; static uint32_t sScriptBlockerCountWhereRunnersPrevented; static nsIInterfaceRequestor* sSameOriginChecker; static bool sIsHandlingKeyBoardEvent; static bool sAllowXULXBL_for_file; + static bool sDisablePopups; static bool sIsFullScreenApiEnabled; static bool sIsUnprefixedFullscreenApiEnabled; static bool sTrustedFullScreenOnly; static bool sIsCutCopyAllowed; static uint32_t sHandlingInputTimeout; static bool sIsPerformanceTimingEnabled; static bool sIsResourceTimingEnabled; static bool sIsPerformanceNavigationTimingEnabled;
--- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -177,20 +177,16 @@ #include "nsWindowRoot.h" #include "nsNetCID.h" #include "nsIArray.h" #include "nsBindingManager.h" #include "nsXBLService.h" -// used for popup blocking, needs to be converted to something -// belonging to the back-end like nsIContentPolicy -#include "nsIPopupWindowManager.h" - #include "nsIDragService.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Selection.h" #include "nsFrameLoader.h" #include "nsISupportsPrimitives.h" #include "nsXPCOMCID.h" #include "mozilla/Logging.h" #include "prenv.h"
--- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -178,20 +178,16 @@ #include "nsIArray.h" #include "XULDocument.h" #include "nsIDOMXULCommandDispatcher.h" #include "nsBindingManager.h" #include "nsXBLService.h" -// used for popup blocking, needs to be converted to something -// belonging to the back-end like nsIContentPolicy -#include "nsIPopupWindowManager.h" - #include "nsIDragService.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Selection.h" #include "nsFrameLoader.h" #include "nsISupportsPrimitives.h" #include "nsXPCOMCID.h" #include "mozilla/Logging.h" #include "prenv.h" @@ -5342,35 +5338,16 @@ nsGlobalWindowOuter::GetTopWindowRoot() if (!piWin) { return nullptr; } nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler()); return window.forget(); } -static -bool IsPopupBlocked(nsIDocument* aDoc) -{ - nsCOMPtr<nsIPopupWindowManager> pm = - do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID); - - if (!pm) { - return false; - } - - if (!aDoc) { - return true; - } - - uint32_t permission = nsIPopupWindowManager::ALLOW_POPUP; - pm->TestPermission(aDoc->NodePrincipal(), &permission); - return permission == nsIPopupWindowManager::DENY_POPUP; -} - void nsGlobalWindowOuter::FirePopupBlockedEvent(nsIDocument* aDoc, nsIURI* aPopupURI, const nsAString& aPopupWindowName, const nsAString& aPopupWindowFeatures) { MOZ_ASSERT(aDoc); @@ -5408,18 +5385,20 @@ nsGlobalWindowOuter::CanSetProperty(cons // If the pref is set to true, we can not set the property // and vice versa. return !Preferences::GetBool(aPrefName, true); } bool nsGlobalWindowOuter::PopupWhitelisted() { - if (!IsPopupBlocked(mDoc)) + if (mDoc && nsContentUtils::CanShowPopup(mDoc->NodePrincipal())) + { return true; + } nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent(); if (parent == this) { return false; } return nsGlobalWindowOuter::Cast(parent)->PopupWhitelisted();
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp +++ b/dom/canvas/WebGLContextFramebufferOperations.cpp @@ -28,17 +28,17 @@ WebGLContext::Clear(GLbitfield mask) GenerateWarning("Calling gl.clear(0) has no effect."); } else if (mRasterizerDiscardEnabled) { GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects."); } if (mask & LOCAL_GL_COLOR_BUFFER_BIT && mBoundDrawFramebuffer) { if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { for (const auto& cur : mBoundDrawFramebuffer->ColorDrawBuffers()) { - if (!cur->IsDefined()) + if (!cur->HasImage()) continue; switch (cur->Format()->format->componentType) { case webgl::ComponentType::Float: case webgl::ComponentType::NormInt: case webgl::ComponentType::NormUInt: break;
--- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -82,17 +82,16 @@ #include "mozilla/dom/FileSystem.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FileList.h" #include "nsIFile.h" #include "nsDirectoryServiceDefs.h" #include "nsIContentPrefService2.h" #include "nsIMIMEService.h" #include "nsIObserverService.h" -#include "nsIPopupWindowManager.h" #include "nsGlobalWindow.h" // input type=image #include "nsImageLoadingContent.h" #include "imgRequestProxy.h" #include "mozAutoDocUpdate.h" #include "nsContentCreatorFunctions.h" @@ -690,24 +689,17 @@ HTMLInputElement::IsPopupBlocked() const return true; } // Check if page can open a popup without abuse regardless of allowed events if (win->GetPopupControlState() <= openBlocked) { return false; } - nsCOMPtr<nsIPopupWindowManager> pm = do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID); - if (!pm) { - return true; - } - - uint32_t permission; - pm->TestPermission(OwnerDoc()->NodePrincipal(), &permission); - return permission == nsIPopupWindowManager::DENY_POPUP; + return !nsContentUtils::CanShowPopup(OwnerDoc()->NodePrincipal()); } nsresult HTMLInputElement::InitColorPicker() { if (mPickerRunning) { NS_WARNING("Just one nsIColorPicker is allowed"); return NS_ERROR_FAILURE;
--- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -1286,21 +1286,21 @@ nsGenericHTMLElement::sBackgroundColorAt void nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes, GenericSpecifiedValues* aData) { const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align); if (value && value->Type() == nsAttrValue::eEnum) { int32_t align = value->GetEnumValue(); - if (!aData->PropertyIsSet(eCSSProperty_float_)) { + if (!aData->PropertyIsSet(eCSSProperty_float)) { if (align == NS_STYLE_TEXT_ALIGN_LEFT) { - aData->SetKeywordValue(eCSSProperty_float_, StyleFloat::Left); + aData->SetKeywordValue(eCSSProperty_float, StyleFloat::Left); } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT) { - aData->SetKeywordValue(eCSSProperty_float_, StyleFloat::Right); + aData->SetKeywordValue(eCSSProperty_float, StyleFloat::Right); } } if (!aData->PropertyIsSet(eCSSProperty_vertical_align)) { switch (align) { case NS_STYLE_TEXT_ALIGN_LEFT: case NS_STYLE_TEXT_ALIGN_RIGHT: break; default:
--- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -14,17 +14,16 @@ #include "nsArray.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" #include "nsHashPropertyBag.h" #include "nsIEventTarget.h" #include "nsIUUIDGenerator.h" #include "nsIScriptGlobalObject.h" #include "nsIPermissionManager.h" -#include "nsIPopupWindowManager.h" #include "nsIDocShell.h" #include "nsIDocument.h" #include "nsISupportsPrimitives.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIIDNService.h" #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsICryptoHash.h"
--- a/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs +++ b/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs @@ -21,30 +21,30 @@ const FRAME = ` </body> </html>`; function handleRequest(request, response) { // avoid confusing cache behaviors response.setHeader("Cache-Control", "no-cache", false); - if (request.queryString === "setSameSiteCookie") { + if (request.queryString.includes("setSameSiteCookie")) { response.setHeader("Set-Cookie", "myKey=strictSameSiteCookie; samesite=strict", true); response.setHeader("Content-Type", "image/png"); response.write(IMG_BYTES); return; } - if (request.queryString === "setRegularCookie") { + if (request.queryString.includes("setRegularCookie")) { response.setHeader("Set-Cookie", "myKey=regularCookie;", true); response.setHeader("Content-Type", "image/png"); response.write(IMG_BYTES); return; } - if (request.queryString === "loadFrame") { + if (request.queryString.includes("loadFrame")) { response.write(FRAME); return; } // we should never get here, but just in case return something unexpected response.write("D'oh"); }
--- a/dom/security/test/general/file_same_site_cookies_from_script.sjs +++ b/dom/security/test/general/file_same_site_cookies_from_script.sjs @@ -29,21 +29,21 @@ const GET_COOKIE_FRAME = ` </body> </html>`; function handleRequest(request, response) { // avoid confusing cache behaviors response.setHeader("Cache-Control", "no-cache", false); - if (request.queryString === "setSameSiteCookieUsingInlineScript") { + if (request.queryString.includes("setSameSiteCookieUsingInlineScript")) { response.write(SET_COOKIE_FRAME); return; } - if (request.queryString === "getCookieFrame") { + if (request.queryString.includes("getCookieFrame")) { response.write(GET_COOKIE_FRAME); return; } // we should never get here, but just in case return something unexpected response.write("D'oh"); }
--- a/dom/security/test/general/file_same_site_cookies_subrequest.sjs +++ b/dom/security/test/general/file_same_site_cookies_subrequest.sjs @@ -16,44 +16,44 @@ const FRAME = ` </body> </html>`; function handleRequest(request, response) { // avoid confusing cache behaviors response.setHeader("Cache-Control", "no-cache", false); - if (request.queryString === "setStrictSameSiteCookie") { + if (request.queryString.includes("setStrictSameSiteCookie")) { response.setHeader("Set-Cookie", "myKey=strictSameSiteCookie; samesite=strict", true); response.setHeader("Content-Type", "image/png"); response.write(IMG_BYTES); return; } - if (request.queryString === "setLaxSameSiteCookie") { + if (request.queryString.includes("setLaxSameSiteCookie")) { response.setHeader("Set-Cookie", "myKey=laxSameSiteCookie; samesite=lax", true); response.setHeader("Content-Type", "image/png"); response.write(IMG_BYTES); return; } // save the object state of the initial request, which returns // async once the server has processed the img request. - if (request.queryString === "queryresult") { + if (request.queryString.includes("queryresult")) { response.processAsync(); setObjectState("queryResult", response); return; } - if (request.queryString === "loadFrame") { + if (request.queryString.includes("loadFrame")) { response.write(FRAME); return; } - if (request.queryString === "checkCookie") { + if (request.queryString.includes("checkCookie")) { var cookie = "unitialized"; if (request.hasHeader("Cookie")) { cookie = request.getHeader("Cookie"); } else { cookie = "myKey=noCookie"; } response.setHeader("Content-Type", "image/png");
--- a/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs +++ b/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs @@ -29,44 +29,44 @@ const WIN = ` </body> </html>`; function handleRequest(request, response) { // avoid confusing cache behaviors response.setHeader("Cache-Control", "no-cache", false); - if (request.queryString === "setStrictSameSiteCookie") { + if (request.queryString.includes("setStrictSameSiteCookie")) { response.setHeader("Set-Cookie", "myKey=strictSameSiteCookie; samesite=strict", true); response.setHeader("Content-Type", "image/png"); response.write(IMG_BYTES); return; } - if (request.queryString === "setLaxSameSiteCookie") { + if (request.queryString.includes("setLaxSameSiteCookie")) { response.setHeader("Set-Cookie", "myKey=laxSameSiteCookie; samesite=lax", true); response.setHeader("Content-Type", "image/png"); response.write(IMG_BYTES); return; } // save the object state of the initial request, which returns // async once the server has processed the img request. - if (request.queryString === "queryresult") { + if (request.queryString.includes("queryresult")) { response.processAsync(); setObjectState("queryResult", response); return; } - if (request.queryString === "loadFrame") { + if (request.queryString.includes("loadFrame")) { response.write(FRAME); return; } - if (request.queryString === "loadWin") { + if (request.queryString.includes("loadWin")) { var cookie = "unitialized"; if (request.hasHeader("Cookie")) { cookie = request.getHeader("Cookie"); } else { cookie = "myKey=noCookie"; } response.write(WIN);
--- a/dom/security/test/general/test_same_site_cookies_cross_origin_context.html +++ b/dom/security/test/general/test_same_site_cookies_cross_origin_context.html @@ -19,69 +19,89 @@ * in the context of http://mochi.test * 2) We load an iframe from http://example.com and check if the cookie * is available. * 3) We observe that: * (a) same site cookie has been discarded in a cross origin context. * (b) the regular cookie is available. */ +SimpleTest.registerCleanupFunction(() => { + SpecialPowers.clearUserPref("network.cookie.same-site.enabled"); +}); SimpleTest.waitForExplicitFinish(); const CROSS_ORIGIN = "http://example.com/"; const PATH = "tests/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs"; let curTest = 0; var tests = [ { - description: "regular cookie in cross origin context", + description: "regular cookie in cross origin context (same-site: on)", imgSRC: CROSS_ORIGIN + PATH + "?setRegularCookie", frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "myKey=regularCookie", }, { - description: "same-site cookie in cross origin context", + description: "same-site cookie in cross origin context (same-site: on)", imgSRC: CROSS_ORIGIN + PATH + "?setSameSiteCookie", frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "", // no cookie should be set }, + { + description: "regular cookie in cross origin context (same-site: off)", + imgSRC: CROSS_ORIGIN + PATH + "?setRegularCookie", + frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=regularCookie", + }, + { + description: "same-site cookie in cross origin context (same-site: off)", + imgSRC: CROSS_ORIGIN + PATH + "?setSameSiteCookie", + frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=strictSameSiteCookie", + }, ]; window.addEventListener("message", receiveMessage); function receiveMessage(event) { is(event.data.result, tests[curTest].result, tests[curTest].description); curTest += 1; - // // lets see if we ran all the tests + // lets see if we ran all the tests if (curTest == tests.length) { window.removeEventListener("message", receiveMessage); SimpleTest.finish(); return; } // otherwise it's time to run the next test setCookieAndInitTest(); } function setupQueryResultAndRunTest() { let testframe = document.getElementById("testframe"); - testframe.src = tests[curTest].frameSRC; + testframe.src = tests[curTest].frameSRC + curTest; } function setCookieAndInitTest() { + SpecialPowers.setBoolPref("network.cookie.same-site.enabled", tests[curTest].sameSiteEnabled); var cookieImage = document.getElementById("cookieImage"); cookieImage.onload = function() { ok(true, "trying to set cookie for test (" + tests[curTest].description + ")"); setupQueryResultAndRunTest(); } cookieImage.onerror = function() { ok(false, "could not load image for test (" + tests[curTest].description + ")"); } - cookieImage.src = tests[curTest].imgSRC; + cookieImage.src = tests[curTest].imgSRC + curTest; } // fire up the test setCookieAndInitTest(); </script> </body> </html>
--- a/dom/security/test/general/test_same_site_cookies_from_script.html +++ b/dom/security/test/general/test_same_site_cookies_from_script.html @@ -18,37 +18,56 @@ * inline script in top-level context of http://mochi.test. * 2) We load an iframe from http://example.com and check if the cookie * is available. * 3) We observe that: * (a) same site cookie is available in same origin context. * (a) same site cookie has been discarded in a cross origin context. */ +SimpleTest.registerCleanupFunction(() => { + SpecialPowers.clearUserPref("network.cookie.same-site.enabled"); +}); SimpleTest.waitForExplicitFinish(); const SAME_ORIGIN = "http://mochi.test:8888/"; const CROSS_ORIGIN = "http://example.com/"; const PATH = "tests/dom/security/test/general/file_same_site_cookies_from_script.sjs"; let curTest = 0; var tests = [ { description: "same-site cookie inline script within same-site context", setCookieSrc: SAME_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript", getCookieSrc: SAME_ORIGIN + PATH + "?getCookieFrame", + sameSiteEnabled: true, result: "myKey=sameSiteCookieInlineScript", }, { description: "same-site cookie inline script within cross-site context", setCookieSrc: CROSS_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript", getCookieSrc: CROSS_ORIGIN + PATH + "?getCookieFrame", + sameSiteEnabled: true, result: "", // same-site cookie should be discarded in cross site context }, + { + description: "same-site cookie inline script within same-site context", + setCookieSrc: SAME_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript", + getCookieSrc: SAME_ORIGIN + PATH + "?getCookieFrame", + sameSiteEnabled: false, + result: "myKey=sameSiteCookieInlineScript", + }, + { + description: "same-site cookie inline script within cross-site context", + setCookieSrc: CROSS_ORIGIN + PATH + "?setSameSiteCookieUsingInlineScript", + getCookieSrc: CROSS_ORIGIN + PATH + "?getCookieFrame", + sameSiteEnabled: false, + result: "myKey=sameSiteCookieInlineScript", + }, ]; window.addEventListener("message", receiveMessage); function receiveMessage(event) { is(event.data.result, tests[curTest].result, tests[curTest].description); curTest += 1; // lets see if we ran all the tests @@ -58,29 +77,30 @@ function receiveMessage(event) { return; } // otherwise it's time to run the next test setCookieAndInitTest(); } function setupQueryResultAndRunTest() { let getCookieFrame = document.getElementById("getCookieFrame"); - getCookieFrame.src = tests[curTest].getCookieSrc; + getCookieFrame.src = tests[curTest].getCookieSrc + curTest; } function setCookieAndInitTest() { + SpecialPowers.setBoolPref("network.cookie.same-site.enabled", tests[curTest].sameSiteEnabled); var cookieFrame = document.getElementById("setCookieFrame"); setCookieFrame.onload = function() { ok(true, "trying to set cookie for test (" + tests[curTest].description + ")"); setupQueryResultAndRunTest(); } setCookieFrame.onerror = function() { ok(false, "could not load image for test (" + tests[curTest].description + ")"); } - cookieFrame.src = tests[curTest].setCookieSrc; + cookieFrame.src = tests[curTest].setCookieSrc + curTest; } // fire up the test setCookieAndInitTest(); </script> </body> </html>
--- a/dom/security/test/general/test_same_site_cookies_subrequest.html +++ b/dom/security/test/general/test_same_site_cookies_subrequest.html @@ -22,49 +22,84 @@ * * In detail: * We perform an XHR request to the *.sjs file which is processed async on * the server and waits till the image request has been processed by the server. * Once the image requets was processed, the server responds to the initial * XHR request with the expecuted result (the cookie value). */ +SimpleTest.registerCleanupFunction(() => { + SpecialPowers.clearUserPref("network.cookie.same-site.enabled"); +}); SimpleTest.waitForExplicitFinish(); const SAME_ORIGIN = "http://mochi.test:8888/"; const CROSS_ORIGIN = "http://example.com/"; const PATH = "tests/dom/security/test/general/file_same_site_cookies_subrequest.sjs"; let curTest = 0; var tests = [ { description: "same origin site using cookie policy 'samesite=strict'", imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie", frameSRC: SAME_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "myKey=strictSameSiteCookie", }, { description: "cross origin site using cookie policy 'samesite=strict'", imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie", frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "myKey=noCookie", }, { description: "same origin site using cookie policy 'samesite=lax'", imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie", frameSRC: SAME_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "myKey=laxSameSiteCookie", }, { description: "cross origin site using cookie policy 'samesite=lax'", imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie", frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "myKey=noCookie", }, + { + description: "same origin site using cookie policy 'samesite=strict'", + imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie", + frameSRC: SAME_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=strictSameSiteCookie", + }, + { + description: "cross origin site using cookie policy 'samesite=strict'", + imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie", + frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=strictSameSiteCookie", + }, + { + description: "same origin site using cookie policy 'samesite=lax'", + imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie", + frameSRC: SAME_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=laxSameSiteCookie", + }, + { + description: "cross origin site using cookie policy 'samesite=lax'", + imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie", + frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=laxSameSiteCookie", + }, ]; function checkResult(aCookieVal) { is(aCookieVal, tests[curTest].result, tests[curTest].description); curTest += 1; // lets see if we ran all the tests if (curTest == tests.length) { @@ -72,42 +107,43 @@ function checkResult(aCookieVal) { return; } // otherwise it's time to run the next test setCookieAndInitTest(); } function setupQueryResultAndRunTest() { var myXHR = new XMLHttpRequest(); - myXHR.open("GET", "file_same_site_cookies_subrequest.sjs?queryresult"); + myXHR.open("GET", "file_same_site_cookies_subrequest.sjs?queryresult" + curTest); myXHR.onload = function(e) { checkResult(myXHR.responseText); } myXHR.onerror = function(e) { ok(false, "could not query results from server (" + e.message + ")"); } myXHR.send(); // give it some time and load the test frame SimpleTest.executeSoon(function() { let testframe = document.getElementById("testframe"); - testframe.src = tests[curTest].frameSRC; + testframe.src = tests[curTest].frameSRC + curTest; }); } function setCookieAndInitTest() { + SpecialPowers.setBoolPref("network.cookie.same-site.enabled", tests[curTest].sameSiteEnabled); var cookieImage = document.getElementById("cookieImage"); cookieImage.onload = function() { ok(true, "set cookie for test (" + tests[curTest].description + ")"); setupQueryResultAndRunTest(); } cookieImage.onerror = function() { ok(false, "could not set cookie for test (" + tests[curTest].description + ")"); } - cookieImage.src = tests[curTest].imgSRC; + cookieImage.src = tests[curTest].imgSRC + curTest; } // fire up the test setCookieAndInitTest(); </script> </body> </html>
--- a/dom/security/test/general/test_same_site_cookies_toplevel_nav.html +++ b/dom/security/test/general/test_same_site_cookies_toplevel_nav.html @@ -23,47 +23,82 @@ * * In detail: * We perform an XHR request to the *.sjs file which is processed async on * the server and waits till the image request has been processed by the server. * Once the image requets was processed, the server responds to the initial * XHR request with the expecuted result (the cookie value). */ +SimpleTest.registerCleanupFunction(() => { + SpecialPowers.clearUserPref("network.cookie.same-site.enabled"); +}); SimpleTest.waitForExplicitFinish(); const SAME_ORIGIN = "http://mochi.test:8888/"; const CROSS_ORIGIN = "http://example.com/"; const PATH = "tests/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs"; let curTest = 0; var tests = [ { description: "same origin navigation using cookie policy 'samesite=strict'", imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie", frameSRC: SAME_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "myKey=strictSameSiteCookie", }, { description: "cross origin navigation using cookie policy 'samesite=strict'", imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie", frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "myKey=noCookie", }, { description: "same origin navigation using cookie policy 'samesite=lax'", imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie", frameSRC: SAME_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, result: "myKey=laxSameSiteCookie", }, { description: "cross origin navigation using cookie policy 'samesite=lax'", imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie", frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: true, + result: "myKey=laxSameSiteCookie", + }, + { + description: "same origin navigation using cookie policy 'samesite=strict'", + imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie", + frameSRC: SAME_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=strictSameSiteCookie", + }, + { + description: "cross origin navigation using cookie policy 'samesite=strict'", + imgSRC: SAME_ORIGIN + PATH + "?setStrictSameSiteCookie", + frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=strictSameSiteCookie", + }, + { + description: "same origin navigation using cookie policy 'samesite=lax'", + imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie", + frameSRC: SAME_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, + result: "myKey=laxSameSiteCookie", + }, + { + description: "cross origin navigation using cookie policy 'samesite=lax'", + imgSRC: SAME_ORIGIN + PATH + "?setLaxSameSiteCookie", + frameSRC: CROSS_ORIGIN + PATH + "?loadFrame", + sameSiteEnabled: false, result: "myKey=laxSameSiteCookie", }, ]; function checkResult(aCookieVal) { is(aCookieVal, tests[curTest].result, tests[curTest].description); curTest += 1; @@ -73,42 +108,43 @@ function checkResult(aCookieVal) { return; } // otherwise it's time to run the next test setCookieAndInitTest(); } function setupQueryResultAndRunTest() { var myXHR = new XMLHttpRequest(); - myXHR.open("GET", "file_same_site_cookies_toplevel_nav.sjs?queryresult"); + myXHR.open("GET", "file_same_site_cookies_toplevel_nav.sjs?queryresult" + curTest); myXHR.onload = function(e) { checkResult(myXHR.responseText); } myXHR.onerror = function(e) { ok(false, "could not query results from server (" + e.message + ")"); } myXHR.send(); // give it some time and load the test window SimpleTest.executeSoon(function() { let testframe = document.getElementById("testframe"); - testframe.src = tests[curTest].frameSRC; + testframe.src = tests[curTest].frameSRC + curTest; }); } function setCookieAndInitTest() { + SpecialPowers.setBoolPref("network.cookie.same-site.enabled", tests[curTest].sameSiteEnabled); var cookieImage = document.getElementById("cookieImage"); cookieImage.onload = function() { ok(true, "set cookie for test (" + tests[curTest].description + ")"); setupQueryResultAndRunTest(); } cookieImage.onerror = function() { ok(false, "could not set cookie for test (" + tests[curTest].description + ")"); } - cookieImage.src = tests[curTest].imgSRC; + cookieImage.src = tests[curTest].imgSRC + curTest; } // fire up the test setCookieAndInitTest(); </script> </body> </html>
--- a/extensions/cookie/moz.build +++ b/extensions/cookie/moz.build @@ -6,17 +6,16 @@ TEST_DIRS += ['test'] UNIFIED_SOURCES += [ 'nsCookieModule.cpp', 'nsCookiePermission.cpp', 'nsPermission.cpp', 'nsPermissionManager.cpp', - 'nsPopupWindowManager.cpp', ] LOCAL_INCLUDES += [ '/caps', ] include('/ipc/chromium/chromium-config.mozbuild')
--- a/extensions/cookie/nsCookieModule.cpp +++ b/extensions/cookie/nsCookieModule.cpp @@ -2,42 +2,37 @@ /* 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 "mozilla/ModuleUtils.h" #include "nsIServiceManager.h" #include "nsPermissionManager.h" -#include "nsPopupWindowManager.h" #include "nsICategoryManager.h" #include "nsCookiePermission.h" #include "nsString.h" // Define the constructor function for the objects NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPermissionManager, nsPermissionManager::GetXPCOMSingleton) -NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPopupWindowManager, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookiePermission) NS_DEFINE_NAMED_CID(NS_PERMISSIONMANAGER_CID); -NS_DEFINE_NAMED_CID(NS_POPUPWINDOWMANAGER_CID); NS_DEFINE_NAMED_CID(NS_COOKIEPERMISSION_CID); static const mozilla::Module::CIDEntry kCookieCIDs[] = { { &kNS_PERMISSIONMANAGER_CID, false, nullptr, nsIPermissionManagerConstructor }, - { &kNS_POPUPWINDOWMANAGER_CID, false, nullptr, nsPopupWindowManagerConstructor }, { &kNS_COOKIEPERMISSION_CID, false, nullptr, nsCookiePermissionConstructor }, { nullptr } }; static const mozilla::Module::ContractIDEntry kCookieContracts[] = { { NS_PERMISSIONMANAGER_CONTRACTID, &kNS_PERMISSIONMANAGER_CID }, - { NS_POPUPWINDOWMANAGER_CONTRACTID, &kNS_POPUPWINDOWMANAGER_CID }, { NS_COOKIEPERMISSION_CONTRACTID, &kNS_COOKIEPERMISSION_CID }, { nullptr } }; static const mozilla::Module kCookieModule = { mozilla::Module::kVersion, kCookieCIDs, kCookieContracts
deleted file mode 100644 --- a/extensions/cookie/nsPopupWindowManager.cpp +++ /dev/null @@ -1,111 +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 "nsPopupWindowManager.h" - -#include "nsCRT.h" -#include "nsIServiceManager.h" -#include "nsIPrefService.h" -#include "nsIPrefBranch.h" -#include "nsIPrincipal.h" -#include "nsIURI.h" -#include "mozilla/Services.h" - -/** - * The Popup Window Manager maintains popup window permissions by website. - */ - -static const char kPopupDisablePref[] = "dom.disable_open_during_load"; - -//***************************************************************************** -//*** nsPopupWindowManager object management and nsISupports -//***************************************************************************** - -nsPopupWindowManager::nsPopupWindowManager() : - mPolicy(ALLOW_POPUP) -{ -} - -nsPopupWindowManager::~nsPopupWindowManager() -{ -} - -NS_IMPL_ISUPPORTS(nsPopupWindowManager, - nsIPopupWindowManager, - nsIObserver, - nsISupportsWeakReference) - -nsresult -nsPopupWindowManager::Init() -{ - nsresult rv; - mPermissionManager = mozilla::services::GetPermissionManager(); - - nsCOMPtr<nsIPrefBranch> prefBranch = - do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); - if (NS_SUCCEEDED(rv)) { - bool permission; - rv = prefBranch->GetBoolPref(kPopupDisablePref, &permission); - if (NS_FAILED(rv)) { - permission = true; - } - mPolicy = permission ? (uint32_t) DENY_POPUP : (uint32_t) ALLOW_POPUP; - - prefBranch->AddObserver(kPopupDisablePref, this, true); - } - - return NS_OK; -} - -//***************************************************************************** -//*** nsPopupWindowManager::nsIPopupWindowManager -//***************************************************************************** - -NS_IMETHODIMP -nsPopupWindowManager::TestPermission(nsIPrincipal* aPrincipal, - uint32_t *aPermission) -{ - NS_ENSURE_ARG_POINTER(aPrincipal); - NS_ENSURE_ARG_POINTER(aPermission); - - uint32_t permit; - *aPermission = mPolicy; - - if (mPermissionManager) { - if (NS_SUCCEEDED(mPermissionManager->TestPermissionFromPrincipal(aPrincipal, "popup", &permit))) { - // Share some constants between interfaces? - if (permit == nsIPermissionManager::ALLOW_ACTION) { - *aPermission = ALLOW_POPUP; - } else if (permit == nsIPermissionManager::DENY_ACTION) { - *aPermission = DENY_POPUP; - } - } - } - - return NS_OK; -} - -//***************************************************************************** -//*** nsPopupWindowManager::nsIObserver -//***************************************************************************** -NS_IMETHODIMP -nsPopupWindowManager::Observe(nsISupports *aSubject, - const char *aTopic, - const char16_t *aData) -{ - nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject); - NS_ASSERTION(!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic), - "unexpected topic - we only deal with pref changes!"); - - if (prefBranch) { - // refresh our local copy of the "disable popups" pref - bool permission = true; - prefBranch->GetBoolPref(kPopupDisablePref, &permission); - - mPolicy = permission ? (uint32_t) DENY_POPUP : (uint32_t) ALLOW_POPUP; - } - - return NS_OK; -}
deleted file mode 100644 --- a/extensions/cookie/nsPopupWindowManager.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsPopupWindowManager_h__ -#define nsPopupWindowManager_h__ - -#include "nsCOMPtr.h" - -#include "nsIObserver.h" -#include "nsIPermissionManager.h" -#include "nsIPopupWindowManager.h" -#include "nsWeakReference.h" - -class nsPopupWindowManager : public nsIPopupWindowManager, - public nsIObserver, - public nsSupportsWeakReference { - -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIPOPUPWINDOWMANAGER - NS_DECL_NSIOBSERVER - - nsPopupWindowManager(); - nsresult Init(); - -private: - virtual ~nsPopupWindowManager(); - - uint32_t mPolicy; - nsCOMPtr<nsIPermissionManager> mPermissionManager; -}; - -// {822bcd11-6432-48be-9e9d-36f7804b7747} -#define NS_POPUPWINDOWMANAGER_CID \ - {0x822bcd11, 0x6432, 0x48be, {0x9e, 0x9d, 0x36, 0xf7, 0x80, 0x4b, 0x77, 0x47}} - -#endif /* nsPopupWindowManager_h__ */
--- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -1130,20 +1130,52 @@ struct ScrollableLayerGuid { } if (mPresShellId == other.mPresShellId) { return mScrollId < other.mScrollId; } } return false; } - PLDHashNumber Hash() const + // Helper structs to use as hash/equality functions in std::unordered_map. e.g. + // std::unordered_map<ScrollableLayerGuid, + // ValueType, + // ScrollableLayerGuid::HashFn> myMap; + // std::unordered_map<ScrollableLayerGuid, + // ValueType, + // ScrollableLayerGuid::HashIgnoringPresShellFn, + // ScrollableLayerGuid::EqualIgnoringPresShellFn> myMap; + + struct HashFn { - return HashGeneric(uint64_t(mLayersId), mPresShellId, mScrollId); - } + std::size_t operator()(const ScrollableLayerGuid& aGuid) const + { + return HashGeneric(uint64_t(aGuid.mLayersId), + aGuid.mPresShellId, + aGuid.mScrollId); + } + }; + + struct HashIgnoringPresShellFn + { + std::size_t operator()(const ScrollableLayerGuid& aGuid) const + { + return HashGeneric(uint64_t(aGuid.mLayersId), + aGuid.mScrollId); + } + }; + + struct EqualIgnoringPresShellFn + { + bool operator()(const ScrollableLayerGuid& lhs, const ScrollableLayerGuid& rhs) const + { + return lhs.mLayersId == rhs.mLayersId + && lhs.mScrollId == rhs.mScrollId; + } + }; }; template <int LogLevel> gfx::Log<LogLevel>& operator<<(gfx::Log<LogLevel>& log, const ScrollableLayerGuid& aGuid) { return log << '(' << uint64_t(aGuid.mLayersId) << ',' << aGuid.mPresShellId << ',' << aGuid.mScrollId << ')'; } struct ZoomConstraints { @@ -1194,23 +1226,15 @@ struct ZoomConstraints { } bool operator!=(const ZoomConstraints& other) const { return !(*this == other); } }; -struct ScrollableLayerGuidHash -{ - std::size_t operator()(const ScrollableLayerGuid& Guid) const - { - return Guid.Hash(); - } -}; - typedef Maybe<ZoomConstraints> MaybeZoomConstraints; } // namespace layers } // namespace mozilla #endif /* GFX_FRAMEMETRICS_H */
--- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -96,18 +96,24 @@ struct APZCTreeManager::TreeBuildingStat // A list of nodes that need to be destroyed at the end of the tree building. // This is initialized with all nodes in the old tree, and nodes are removed // from it as we reuse them in the new tree. nsTArray<RefPtr<HitTestingTreeNode>> mNodesToDestroy; // This map is populated as we place APZCs into the new tree. Its purpose is // to facilitate re-using the same APZC for different layers that scroll - // together (and thus have the same ScrollableLayerGuid). - std::unordered_map<ScrollableLayerGuid, AsyncPanZoomController*, ScrollableLayerGuidHash> mApzcMap; + // together (and thus have the same ScrollableLayerGuid). The presShellId + // doesn't matter for this purpose, and we move the map to the APZCTreeManager + // after we're done building, so it's useful to have the presshell-ignoring + // map for that. + std::unordered_map<ScrollableLayerGuid, + RefPtr<AsyncPanZoomController>, + ScrollableLayerGuid::HashIgnoringPresShellFn, + ScrollableLayerGuid::EqualIgnoringPresShellFn> mApzcMap; // As the tree is traversed, the top element of this stack tracks whether // the parent scroll node has a perspective transform. std::stack<bool> mParentHasPerspective; // During the tree building process, the perspective transform component // of the ancestor transforms of some APZCs can be "deferred" to their // children, meaning they are added to the children's ancestor transforms @@ -224,16 +230,17 @@ private: }; APZCTreeManager::APZCTreeManager(LayersId aRootLayersId) : mInputQueue(new InputQueue()), mRootLayersId(aRootLayersId), mSampler(nullptr), mUpdater(nullptr), mTreeLock("APZCTreeLock"), + mMapLock("APZCMapLock"), mHitResultForInputBlock(CompositorHitTestInfo::eInvisibleToHitTest), mRetainedTouchIdentifier(-1), mInScrollbarTouchDrag(false), mApzcTreeLog("apzctree"), mTestDataLock("APZTestDataLock"), mDPI(160.0) { RefPtr<APZCTreeManager> self(this); @@ -468,16 +475,22 @@ APZCTreeManager::UpdateHitTestingTreeImp } }); } } // We do not support tree structures where the root node has siblings. MOZ_ASSERT(!(mRootNode && mRootNode->GetPrevSibling())); + { // scope lock and update our mApzcMap before we destroy all the unused + // APZC instances + MutexAutoLock lock(mMapLock); + mApzcMap = Move(state.mApzcMap); + } + for (size_t i = 0; i < state.mNodesToDestroy.Length(); i++) { APZCTM_LOG("Destroying node at %p with APZC %p\n", state.mNodesToDestroy[i].get(), state.mNodesToDestroy[i]->GetApzc()); state.mNodesToDestroy[i]->Destroy(); } #if ENABLE_APZCTM_LOGGING @@ -538,17 +551,22 @@ APZCTreeManager::PushStateToWR(wr::Trans RecursiveMutexAutoLock lock(mTreeLock); // During the first pass through the tree, we build a cache of guid->HTTN so // that we can find the relevant APZC instances quickly in subsequent passes, // such as the one below to generate scrollbar transforms. Without this, perf // could end up being O(n^2) instead of O(n log n) because we'd have to search // the tree to find the corresponding APZC every time we hit a thumb node. - std::unordered_map<ScrollableLayerGuid, HitTestingTreeNode*, ScrollableLayerGuidHash> httnMap; + // We use the presShell-ignoring map because when we do a lookup in the map + // for the scrollbar, we don't have (or care about) the presShellId. + std::unordered_map<ScrollableLayerGuid, + HitTestingTreeNode*, + ScrollableLayerGuid::HashIgnoringPresShellFn, + ScrollableLayerGuid::EqualIgnoringPresShellFn> httnMap; bool activeAnimations = false; LayersId lastLayersId{(uint64_t)-1}; wr::WrPipelineId lastPipelineId; // We iterate backwards here because the HitTestingTreeNode is optimized // for backwards iteration. The equivalent code in AsyncCompositionManager // iterates forwards, but the direction shouldn't really matter in practice @@ -577,20 +595,17 @@ APZCTreeManager::PushStateToWR(wr::Trans // that has already been torn down. In that case just skip over // those layers. return; } lastPipelineId = wrBridge->PipelineId(); lastLayersId = aNode->GetLayersId(); } - // Use a 0 presShellId because when we do a lookup in this map for the - // scrollbar below we don't have (or care about) the presShellId. - ScrollableLayerGuid guid(lastLayersId, 0, apzc->GetGuid().mScrollId); - httnMap.emplace(guid, aNode); + httnMap.emplace(apzc->GetGuid(), aNode); ParentLayerPoint layerTranslation = apzc->GetCurrentAsyncTransform( AsyncPanZoomController::eForCompositing).mTranslation; // The positive translation means the painted content is supposed to // move down (or to the right), and that corresponds to a reduction in // the scroll offset. Since we are effectively giving WR the async // scroll delta here, we want to negate the translation. ParentLayerPoint asyncScrollDelta = -layerTranslation; @@ -2339,21 +2354,20 @@ GuidComparatorIgnoringPresShell(const Sc return aOne.mLayersId == aTwo.mLayersId && aOne.mScrollId == aTwo.mScrollId; } already_AddRefed<AsyncPanZoomController> APZCTreeManager::GetTargetAPZC(const LayersId& aLayersId, const FrameMetrics::ViewID& aScrollId) { - RecursiveMutexAutoLock lock(mTreeLock); + MutexAutoLock lock(mMapLock); ScrollableLayerGuid guid(aLayersId, 0, aScrollId); - RefPtr<HitTestingTreeNode> node = GetTargetNode(guid, &GuidComparatorIgnoringPresShell); - MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC - RefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr; + auto it = mApzcMap.find(guid); + RefPtr<AsyncPanZoomController> apzc = (it != mApzcMap.end() ? it->second : nullptr); return apzc.forget(); } already_AddRefed<HitTestingTreeNode> APZCTreeManager::GetTargetNode(const ScrollableLayerGuid& aGuid, GuidComparator aComparator) const { mTreeLock.AssertCurrentThreadIn(); @@ -2425,21 +2439,17 @@ APZCTreeManager::GetAPZCAtPointWR(const gfx::CompositorHitTestInfo hitInfo; bool hitSomething = wr->HitTest(wr::ToWorldPoint(aHitTestPoint), pipelineId, scrollId, hitInfo); if (!hitSomething) { return result.forget(); } LayersId layersId = wr::AsLayersId(pipelineId); - RefPtr<HitTestingTreeNode> node = GetTargetNode( - ScrollableLayerGuid(layersId, 0, scrollId), - &GuidComparatorIgnoringPresShell); - MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC - result = node ? node->GetApzc() : nullptr; + result = GetTargetAPZC(layersId, scrollId); if (!result) { // It falls back to the root // Re-enable these assertions once bug 1391318 is fixed. For now there are // race conditions with the WR hit-testing code that make these assertions // fail. //MOZ_ASSERT(scrollId == FrameMetrics::NULL_SCROLL_ID); result = FindRootApzcForLayersId(layersId); //MOZ_ASSERT(result); @@ -2497,41 +2507,19 @@ APZCTreeManager::BuildOverscrollHandoffC } apzc = apzc->GetParent(); continue; } // Guard against a possible infinite-loop condition. If we hit this, the // layout code that generates the handoff parents did something wrong. MOZ_ASSERT(apzc->GetScrollHandoffParentId() != apzc->GetGuid().mScrollId); - - // Find the AsyncPanZoomController instance with a matching layersId and - // the scroll id that matches apzc->GetScrollHandoffParentId(). - // As an optimization, we start by walking up the APZC tree from 'apzc' - // until we reach the top of the layer subtree for this layers id. - AsyncPanZoomController* scrollParent = nullptr; - AsyncPanZoomController* parent = apzc; - while (!parent->HasNoParentWithSameLayersId()) { - parent = parent->GetParent(); - // While walking up to find the root of the subtree, if we encounter the - // handoff parent, we don't actually need to do the search so we can - // just abort here. - if (parent->GetGuid().mScrollId == apzc->GetScrollHandoffParentId()) { - scrollParent = parent; - break; - } - } - // If that heuristic didn't turn up the scroll parent, do a full tree search. - if (!scrollParent) { - ScrollableLayerGuid guid(parent->GetGuid().mLayersId, 0, apzc->GetScrollHandoffParentId()); - RefPtr<HitTestingTreeNode> node = GetTargetNode(guid, &GuidComparatorIgnoringPresShell); - MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC - scrollParent = node ? node->GetApzc() : nullptr; - } - apzc = scrollParent; + RefPtr<AsyncPanZoomController> scrollParent = + GetTargetAPZC(apzc->GetGuid().mLayersId, apzc->GetScrollHandoffParentId()); + apzc = scrollParent.get(); } // Now adjust the chain to account for scroll grabbing. Sorting is a bit // of an overkill here, but scroll grabbing will likely be generalized // to scroll priorities, so we might as well do it this way. result->SortByScrollPriority(); // Print the overscroll chain for debugging. @@ -2572,20 +2560,20 @@ APZCTreeManager::GetTargetApzcForNode(Hi for (const HitTestingTreeNode* n = aNode; n && n->GetLayersId() == aNode->GetLayersId(); n = n->GetParent()) { if (n->GetApzc()) { APZCTM_LOG("Found target %p using ancestor lookup\n", n->GetApzc()); return n->GetApzc(); } if (n->GetFixedPosTarget() != FrameMetrics::NULL_SCROLL_ID) { - ScrollableLayerGuid guid(n->GetLayersId(), 0, n->GetFixedPosTarget()); - RefPtr<HitTestingTreeNode> fpNode = GetTargetNode(guid, &GuidComparatorIgnoringPresShell); - APZCTM_LOG("Found target node %p using fixed-pos lookup on %" PRIu64 "\n", fpNode.get(), n->GetFixedPosTarget()); - return fpNode ? fpNode->GetApzc() : nullptr; + RefPtr<AsyncPanZoomController> fpTarget = + GetTargetAPZC(n->GetLayersId(), n->GetFixedPosTarget()); + APZCTM_LOG("Found target APZC %p using fixed-pos lookup on %" PRIu64 "\n", fpTarget.get(), n->GetFixedPosTarget()); + return fpTarget.get(); } } return nullptr; } AsyncPanZoomController* APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode, const ScreenPoint& aHitTestPoint, @@ -2655,20 +2643,20 @@ APZCTreeManager::GetAPZCAtPoint(HitTesti if (n->GetScrollbarDirection() == ScrollDirection::eVertical) { *aOutHitResult |= CompositorHitTestInfo::eScrollbarVertical; } // If we hit a scrollbar, target the APZC for the content scrolled // by the scrollbar. (The scrollbar itself doesn't scroll with the // scrolled content, so it doesn't carry the scrolled content's // scroll metadata). - ScrollableLayerGuid guid(n->GetLayersId(), 0, n->GetScrollTargetId()); - if (RefPtr<HitTestingTreeNode> scrollTarget = GetTargetNode(guid, &GuidComparatorIgnoringPresShell)) { - MOZ_ASSERT(scrollTarget->GetApzc()); - return scrollTarget->GetApzc(); + RefPtr<AsyncPanZoomController> scrollTarget = + GetTargetAPZC(n->GetLayersId(), n->GetScrollTargetId()); + if (scrollTarget) { + return scrollTarget.get(); } } } AsyncPanZoomController* result = GetTargetApzcForNode(resultNode); if (!result) { result = FindRootApzcForLayersId(resultNode->GetLayersId()); MOZ_ASSERT(result);
--- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -47,35 +47,35 @@ class AsyncPanZoomController; class APZCTreeManagerParent; class APZSampler; class APZUpdater; class CompositorBridgeParent; class OverscrollHandoffChain; struct OverscrollHandoffState; class FocusTarget; struct FlingHandoffState; -struct ScrollableLayerGuidHash; class LayerMetricsWrapper; class InputQueue; class GeckoContentController; class HitTestingTreeNode; class WebRenderScrollDataWrapper; struct AncestorTransform; struct ScrollThumbData; /** * ****************** NOTE ON LOCK ORDERING IN APZ ************************** * * There are two main kinds of locks used by APZ: APZCTreeManager::mTreeLock * ("the tree lock") and AsyncPanZoomController::mRecursiveMutex ("APZC locks"). - * There is also the APZCTreeManager::mTestDataLock ("test lock"). + * There is also the APZCTreeManager::mTestDataLock ("test lock") and + * APZCTreeManager::mMapLock ("map lock"). * * To avoid deadlock, we impose a lock ordering between these locks, which is: * - * tree lock -> APZC locks -> test lock + * tree lock -> map lock -> APZC locks -> test lock * * The interpretation of the lock ordering is that if lock A precedes lock B * in the ordering sequence, then you must NOT wait on A while holding B. * * ************************************************************************** */ /** @@ -728,20 +728,32 @@ private: * This lock does not need to be held while manipulating a single APZC instance in * isolation (that is, if its tree pointers are not being accessed or mutated). The * lock also needs to be held when accessing the mRootNode instance variable, as that * is considered part of the APZC tree management state. * IMPORTANT: See the note about lock ordering at the top of this file. */ mutable mozilla::RecursiveMutex mTreeLock; RefPtr<HitTestingTreeNode> mRootNode; + /* A map for quick access to get APZC instances by guid, without having to + * acquire the tree lock. mMapLock must be acquired while accessing or + * modifying mApzcMap. + */ + mutable mozilla::Mutex mMapLock; + std::unordered_map<ScrollableLayerGuid, + RefPtr<AsyncPanZoomController>, + ScrollableLayerGuid::HashIgnoringPresShellFn, + ScrollableLayerGuid::EqualIgnoringPresShellFn> mApzcMap; + /* Holds the zoom constraints for scrollable layers, as determined by the * the main-thread gecko code. This can only be accessed on the updater * thread. */ - std::unordered_map<ScrollableLayerGuid, ZoomConstraints, ScrollableLayerGuidHash> mZoomConstraints; + std::unordered_map<ScrollableLayerGuid, + ZoomConstraints, + ScrollableLayerGuid::HashFn> mZoomConstraints; /* A list of keyboard shortcuts to use for translating keyboard inputs into * keyboard actions. This is gathered on the main thread from XBL bindings. * This must only be accessed on the controller thread. */ KeyboardMap mKeyboardMap; /* This tracks the focus targets of chrome and content and whether we have * a current focus target or whether we are waiting for a new confirmation. */
--- a/gfx/webrender_bindings/src/moz2d_renderer.rs +++ b/gfx/webrender_bindings/src/moz2d_renderer.rs @@ -233,17 +233,19 @@ fn dump_blob_index(blob: &[u8], dirty_re "" } ); } } fn check_result(result: &[u8]) -> () { let mut index = BlobReader::new(result); - assert!(index.reader.has_more(), "Unexpectedly empty result. This blob should just have been deleted"); + // we might get an empty result here because sub groups are not tightly bound + // and we'll sometimes have display items that end up with empty bounds in + // the blob image. while index.reader.has_more() { let e = index.read_entry(); dlog!("result bounds: {} {} {:?}", e.end, e.extra_end, e.bounds); } } // We use a BTree as a kind of multi-map, by appending an integer "cache_order" to the key. // This lets us use multiple items with matching bounds in the map and allows
--- a/js/src/vm/BytecodeUtil.cpp +++ b/js/src/vm/BytecodeUtil.cpp @@ -1172,17 +1172,17 @@ ToDisassemblySource(JSContext* cx, Handl if (obj.is<RegExpObject>()) { JSString* source = obj.as<RegExpObject>().toString(cx); if (!source) return false; return bytes->encodeLatin1(cx, source); } } - return !!ValueToPrintable(cx, v, bytes, true); + return !!ValueToPrintableLatin1(cx, v, bytes, true); } static bool ToDisassemblySource(JSContext* cx, HandleScope scope, JSAutoByteString* bytes) { UniqueChars source = JS_smprintf("%s {", ScopeKindString(scope->kind())); if (!source) { ReportOutOfMemory(cx);
--- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -1413,17 +1413,17 @@ LiveEnvironmentVal::staticAsserts() /*****************************************************************************/ namespace { static void ReportOptimizedOut(JSContext* cx, HandleId id) { JSAutoByteString printable; - if (ValueToPrintable(cx, IdToValue(id), &printable)) { + if (ValueToPrintableLatin1(cx, IdToValue(id), &printable)) { JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_OPTIMIZED_OUT, printable.ptr()); } } /* * DebugEnvironmentProxy is the handler for DebugEnvironmentProxy proxy * objects. Having a custom handler (rather than trying to reuse js::Wrapper)
--- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -175,17 +175,18 @@ enum class GetNameMode { Normal, TypeOf template <GetNameMode mode> inline bool FetchName(JSContext* cx, HandleObject receiver, HandleObject holder, HandlePropertyName name, Handle<PropertyResult> prop, MutableHandleValue vp) { if (!prop) { switch (mode) { case GetNameMode::Normal: - return ReportIsNotDefined(cx, name); + ReportIsNotDefined(cx, name); + return false; case GetNameMode::TypeOf: vp.setUndefined(); return true; } } /* Take the slow path if shape was not found in a native object. */ if (!receiver->isNative() || !holder->isNative()) {
--- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -5061,17 +5061,17 @@ js::NewArrayOperationWithTemplate(JSCont } void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandleId id) { MOZ_ASSERT(errorNumber == JSMSG_UNINITIALIZED_LEXICAL || errorNumber == JSMSG_BAD_CONST_ASSIGN); JSAutoByteString printable; - if (ValueToPrintable(cx, IdToValue(id), &printable)) + if (ValueToPrintableLatin1(cx, IdToValue(id), &printable)) JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, printable.ptr()); } void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandlePropertyName name) { RootedId id(cx, NameToId(name)); ReportRuntimeLexicalError(cx, errorNumber, id);
--- a/js/src/vm/JSContext.cpp +++ b/js/src/vm/JSContext.cpp @@ -875,32 +875,30 @@ js::ReportErrorNumberUCArray(JSContext* return false; } ReportError(cx, &report, callback, userRef); return warning; } -bool +void js::ReportIsNotDefined(JSContext* cx, HandleId id) { JSAutoByteString printable; - if (ValueToPrintable(cx, IdToValue(id), &printable)) { - JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, - printable.ptr()); - } - return false; + if (!ValueToPrintableUTF8(cx, IdToValue(id), &printable)) + return; + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, printable.ptr()); } -bool +void js::ReportIsNotDefined(JSContext* cx, HandlePropertyName name) { RootedId id(cx, NameToId(name)); - return ReportIsNotDefined(cx, id); + ReportIsNotDefined(cx, id); } bool js::ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v, HandleString fallback) { bool ok;
--- a/js/src/vm/JSContext.h +++ b/js/src/vm/JSContext.h @@ -1026,20 +1026,20 @@ ReportUsageErrorASCII(JSContext* cx, Han * and the report doesn't have the JSREPORT_WARNING flag set or reportWarnings * is true. * Returns false otherwise. */ extern bool PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, JSErrorReport* report, bool reportWarnings); -extern bool +extern void ReportIsNotDefined(JSContext* cx, HandlePropertyName name); -extern bool +extern void ReportIsNotDefined(JSContext* cx, HandleId id); /* * Report an attempt to access the property of a null or undefined value (v). */ extern bool ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v, HandleString fallback);
--- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -2306,18 +2306,20 @@ enum IsNameLookup { NotNameLookup = fals * Gecko code.) */ static bool GetNonexistentProperty(JSContext* cx, HandleId id, IsNameLookup nameLookup, MutableHandleValue vp) { vp.setUndefined(); // If we are doing a name lookup, this is a ReferenceError. - if (nameLookup) - return ReportIsNotDefined(cx, id); + if (nameLookup) { + ReportIsNotDefined(cx, id); + return false; + } // Give a strict warning if foo.bar is evaluated by a script for an object // foo with no property named 'bar'. // // Don't warn if extra warnings not enabled or for random getprop // operations. if (MOZ_LIKELY(!cx->compartment()->behaviors().extraWarnings(cx))) return true; @@ -2376,18 +2378,20 @@ GeneralizedGetProperty(JSContext* cx, Ha // // If we get here, we've reached a non-native object. Fall back on the // algorithm as specified, with two separate lookups. (Note that we // throw ReferenceErrors regardless of strictness, technically a bug.) bool found; if (!HasProperty(cx, obj, id, &found)) return false; - if (!found) - return ReportIsNotDefined(cx, id); + if (!found) { + ReportIsNotDefined(cx, id); + return false; + } } return GetProperty(cx, obj, receiver, id, vp); } static inline bool GeneralizedGetProperty(JSContext* cx, JSObject* obj, jsid id, const Value& receiver, IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
--- a/js/src/vm/StringType.cpp +++ b/js/src/vm/StringType.cpp @@ -1904,32 +1904,47 @@ JSString::fillWithRepresentatives(JSCont MOZ_ASSERT(index == 22); return true; } /*** Conversions *********************************************************************************/ const char* -js::ValueToPrintable(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource) +js::ValueToPrintableLatin1(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, + bool asSource) { RootedValue v(cx, vArg); JSString* str; if (asSource) str = ValueToSource(cx, v); else str = ToString<CanGC>(cx, v); if (!str) return nullptr; str = QuoteString(cx, str, 0); if (!str) return nullptr; return bytes->encodeLatin1(cx, str); } +const char* +js::ValueToPrintableUTF8(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource) +{ + RootedValue v(cx, vArg); + JSString* str; + if (asSource) + str = ValueToSource(cx, v); + else + str = ToString<CanGC>(cx, v); + if (!str) + return nullptr; + return bytes->encodeUtf8(cx, RootedString(cx, str)); +} + template <AllowGC allowGC> JSString* js::ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg) { /* As with ToObjectSlow, callers must verify that |arg| isn't a string. */ MOZ_ASSERT(!arg.isString()); Value v = arg;
--- a/js/src/vm/StringType.h +++ b/js/src/vm/StringType.h @@ -1583,19 +1583,31 @@ HasSubstringAt(JSLinearString* text, JSL JSString* SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t lengthInt); /*** Conversions *********************************************************************************/ /* * Convert a value to a printable C string. + * + * As the function name implies, any characters in a converted printable string will be Latin1 + * characters. If there are any non-Latin1 characters in the original value, then those characters + * will be changed to Unicode escape sequences(I.e. \udddd, dddd are 4 hex digits) in the printable + * string. */ extern const char* -ValueToPrintable(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false); +ValueToPrintableLatin1(JSContext* cx, const Value&, JSAutoByteString* bytes, + bool asSource = false); + +/* + * Convert a value to a printable C string encoded in UTF-8. + */ +extern const char* +ValueToPrintableUTF8(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false); /* * Convert a non-string value to a string, returning null after reporting an * error, otherwise returning a new string reference. */ template <AllowGC allowGC> extern JSString* ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg);
--- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -442,36 +442,31 @@ nsSubDocumentFrame::BuildDisplayList(nsD haveDisplayPort || presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive(aBuilder))) { needsOwnLayer = true; } if (aBuilder->IsRetainingDisplayList()) { - // The value of needsOwnLayer can change between builds without - // an invalidation recorded for this frame (like if the root - // scrollframe becomes active). If this happens, - // then we need to notify the builder so that merging can - // happen correctly. - if (!mPreviouslyNeededLayer || - mPreviouslyNeededLayer.value() != needsOwnLayer) { - dirty = visible; - aBuilder->MarkCurrentFrameModifiedDuringBuilding(); - } - mPreviouslyNeededLayer = Some(needsOwnLayer); - // Caret frame changed, rebuild the entire subdoc. // We could just invalidate the old and new frame // areas and save some work here. RetainedDisplayListBuilder // does this, so we could teach it to find and check all // subdocs in advance. if (mPreviousCaret != aBuilder->GetCaretFrame()) { dirty = visible; - aBuilder->MarkCurrentFrameModifiedDuringBuilding(); + aBuilder->RebuildAllItemsInCurrentSubtree(); + // Mark the old caret frame as invalid so that we remove the + // old nsDisplayCaret. We don't mark the current frame as invalid + // since we want the nsDisplaySubdocument to retain it's place + // in the retained display list. + if (mPreviousCaret) { + aBuilder->MarkFrameModifiedDuringBuilding(mPreviousCaret); + } } mPreviousCaret = aBuilder->GetCaretFrame(); } nsDisplayList childItems; { DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
--- a/layout/generic/nsSubDocumentFrame.h +++ b/layout/generic/nsSubDocumentFrame.h @@ -163,17 +163,16 @@ protected: nsIFrame* ObtainIntrinsicSizeFrame(); nsView* GetViewInternal() const override { return mOuterView; } void SetViewInternal(nsView* aView) override { mOuterView = aView; } RefPtr<nsFrameLoader> mFrameLoader; nsView* mOuterView; nsView* mInnerView; - Maybe<bool> mPreviouslyNeededLayer; bool mIsInline; bool mPostedReflowCallback; bool mDidCreateDoc; bool mCallingShow; WeakFrame mPreviousCaret; }; #endif /* NSSUBDOCUMENTFRAME_H_ */
--- a/layout/painting/RetainedDisplayListBuilder.cpp +++ b/layout/painting/RetainedDisplayListBuilder.cpp @@ -66,29 +66,16 @@ MarkFramesWithItemsAndImagesModified(nsD } } if (i->GetChildren()) { MarkFramesWithItemsAndImagesModified(i->GetChildren()); } } } -static bool -IsAnyAncestorModified(nsIFrame* aFrame) -{ - nsIFrame* f = aFrame; - while (f) { - if (f->IsFrameModified()) { - return true; - } - f = nsLayoutUtils::GetCrossDocParentFrame(f); - } - return false; -} - static AnimatedGeometryRoot* SelectAGRForFrame(nsIFrame* aFrame, AnimatedGeometryRoot* aParentAGR) { if (!aFrame->IsStackingContext()) { return aParentAGR; } if (!aFrame->HasOverrideDirtyRegion()) { @@ -192,16 +179,34 @@ RetainedDisplayListBuilder::IncrementSub MOZ_ASSERT(subDocFrame); nsIPresShell* presShell = subDocFrame->GetSubdocumentPresShellForPainting(0); MOZ_ASSERT(presShell); mBuilder.IncrementPresShellPaintCount(presShell); } +static bool +AnyContentAncestorModified(nsIFrame* aFrame, + nsIFrame* aStopAtFrame = nullptr) +{ + for (nsIFrame* f = aFrame; f; + f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) { + if (f->IsFrameModified()) { + return true; + } + + if (aStopAtFrame && f == aStopAtFrame) { + break; + } + } + + return false; +} + static void UpdateASR(nsDisplayItem* aItem, Maybe<const ActiveScrolledRoot*>& aContainerASR) { if (!aContainerASR) { return; } @@ -300,17 +305,17 @@ public: result.AppendToTop(&mMergedItems); result.mDAG = Move(mMergedDAG); result.mKeyLookup.SwapElements(mMergedKeyLookup); return result; } bool IsChanged(nsDisplayItem* aItem) { return aItem->HasDeletedFrame() || !aItem->CanBeReused() || - IsAnyAncestorModified(aItem->FrameForInvalidation()); + AnyContentAncestorModified(aItem->FrameForInvalidation()); } void UpdateContainerASR(nsDisplayItem* aItem) { const ActiveScrolledRoot* itemClipASR = aItem->GetClipChain() ? aItem->GetClipChain()->mASR : nullptr; const ActiveScrolledRoot* finiteBoundsASR = ActiveScrolledRoot::PickDescendant( @@ -742,17 +747,18 @@ ProcessFrame(nsIFrame* aFrame, nsDisplay aOverflow.IntersectRect(aOverflow, currentFrame->GetVisualOverflowRectRelativeToSelf()); } if (aOverflow.IsEmpty()) { break; } if (currentFrame != aBuilder.RootReferenceFrame() && - currentFrame->IsStackingContext()) { + currentFrame->IsStackingContext() && + currentFrame->IsFixedPosContainingBlock()) { CRR_LOG("Frame belongs to stacking context frame %p\n", currentFrame); // If we found an intermediate stacking context with an existing display item // then we can store the dirty rect there and stop. If we couldn't find one then // we need to keep bubbling up to the next stacking context. nsDisplayItem* wrapperItem = GetFirstDisplayItemWithChildren(currentFrame); if (!wrapperItem) { continue; }
--- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -1742,16 +1742,22 @@ public: if (MarkFrameModifiedDuringBuilding(const_cast<nsIFrame*>(mCurrentFrame))) { mInInvalidSubtree = true; mDirtyRect = mVisibleRect; return true; } return false; } + void RebuildAllItemsInCurrentSubtree() + { + mInInvalidSubtree = true; + mDirtyRect = mVisibleRect; + } + /** * This is a convenience function to ease the transition until AGRs and ASRs * are unified. */ AnimatedGeometryRoot* AnimatedGeometryRootForASR(const ActiveScrolledRoot* aASR); bool HitTestIsForVisibility() const { return mHitTestIsForVisibility;
--- a/layout/reftests/display-list/retained-dl-style-change-stacking-context-1.html +++ b/layout/reftests/display-list/retained-dl-style-change-stacking-context-1.html @@ -12,22 +12,18 @@ } </style> </head> <body> <div id="first" style="background-color:green; width:200px; height:200px" class="reftest-no-display-list"></div> <div style="transform:translateZ(1px)"> <div id="second" style="background-color:red"></div> </div> - <div style="position:fixed; left:100px"> - <div id="third" style="background-color:red"></div> - </div> </body> <script> function doTest() { document.getElementById("second").style.backgroundColor = "green"; - document.getElementById("third").style.backgroundColor = "green"; document.documentElement.removeAttribute("class"); } window.addEventListener("MozReftestInvalidate", doTest); </script> </html>
--- a/layout/style/GenerateCSSPropsGenerated.py +++ b/layout/style/GenerateCSSPropsGenerated.py @@ -13,22 +13,22 @@ def get_properties(preprocessorHeader): cpp = list(buildconfig.substs['CPP']) cpp += shellutil.split(buildconfig.substs['ACDEFINES']) cpp.append(preprocessorHeader) preprocessed = subprocess.check_output(cpp) properties = [{"name":p[0], "prop":p[1], "id":p[2], "flags":p[3], "pref":p[4], "proptype":p[5]} for (i, p) in enumerate(eval(preprocessed))] - # Sort the list so that longhand and logical properties are intermingled - # first, shorthand properties follow, then aliases appear last. This matches - # the order of the nsCSSPropertyID enum. + # Sort the list so that longhand properties are intermingled first, + # shorthand properties follow, then aliases appear last. + # This matches the order of the nsCSSPropertyID enum. def property_compare(x, y): - property_order = {"longhand": 0, "logical": 0, "shorthand": 1, "alias": 2} + property_order = {"longhand": 0, "shorthand": 1, "alias": 2} return property_order[x["proptype"]] - property_order[y["proptype"]] properties = sorted(properties, cmp=property_compare) for i, p in enumerate(properties): p["index"] = i # Record each property's IDL name.
--- a/layout/style/PythonCSSProps.h +++ b/layout/style/PythonCSSProps.h @@ -15,24 +15,21 @@ #define PROP_STRINGIFY(X) PROP_STRINGIFY_INTERNAL(X) #define DO_PROP(name, method, id, flags, pref, proptype) \ [ #name, #method, #id, PROP_STRINGIFY(flags), pref, proptype ], #define CSS_PROP(name, id, method, flags, pref, ...) \ DO_PROP(name, method, id, flags, pref, "longhand") #define CSS_PROP_SHORTHAND(name, id, method, flags, pref) \ DO_PROP(name, method, id, flags, pref, "shorthand") -#define CSS_PROP_LOGICAL(name, id, method, flags, pref, ...) \ - DO_PROP(name, method, id, flags, pref, "logical") #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_ #include "nsCSSPropList.h" #undef CSS_PROP_PUBLIC_OR_PRIVATE -#undef CSS_PROP_LOGICAL #undef CSS_PROP_SHORTHAND #undef CSS_PROP #define CSS_PROP_ALIAS(name, aliasid_, id, method, pref) \ DO_PROP(name, method, id, 0, pref, "alias") #include "nsCSSPropAliasList.h"
--- a/layout/style/ServoBindings.toml +++ b/layout/style/ServoBindings.toml @@ -44,17 +44,16 @@ args = [ "-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1", ] "arch=x86" = ["--target=i686-pc-win32"] "arch=x86_64" = ["--target=x86_64-pc-win32"] [structs] headers = [ "nsStyleStruct.h", - "mozilla/ServoPropPrefList.h", "mozilla/StyleAnimationValue.h", "gfxFontConstants.h", "gfxFontFeatures.h", "nsThemeConstants.h", "mozilla/css/Loader.h", "mozilla/css/SheetLoadData.h", "mozilla/dom/AnimationEffectReadOnlyBinding.h", "mozilla/dom/HTMLSlotElement.h", @@ -200,17 +199,16 @@ whitelist-vars = [ "NODE_.*", "ELEMENT_.*", "NS_FONT_.*", "NS_STYLE_.*", "NS_MATHML_.*", "NS_RADIUS_.*", "BORDER_COLOR_.*", "BORDER_STYLE_.*", - "mozilla::SERVO_PREF_.*", "CSS_PSEUDO_ELEMENT_.*", "SERVO_CSS_PSEUDO_ELEMENT_FLAGS_.*", "kNameSpaceID_.*", "kGenericFont_.*", "kPresContext_.*", "nsContentUtils_.*", "GECKO_IS_NIGHTLY", ]
deleted file mode 100644 --- a/layout/style/ServoPropPrefList.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_ServoPropPrefList_h -#define mozilla_ServoPropPrefList_h - -namespace mozilla { - -#define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \ - const bool SERVO_PREF_ENABLED_##id_ = !(sizeof(pref_) == 1); -#define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \ - const bool SERVO_PREF_ENABLED_##id_ = !(sizeof(pref_) == 1); -#define CSS_PROP_LIST_INCLUDE_LOGICAL -#include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL -#undef CSS_PROP -#undef CSS_PROP_SHORTHAND - -#define CSS_PROP_ALIAS(aliasname_, aliasid_, id_, method_, pref_) \ - const bool SERVO_PREF_ENABLED_##aliasid_ = !(sizeof(pref_) == 1); -#define CSS_PROP_ALIAS_LIST_INCLUDE_LOGICAL -#include "nsCSSPropAliasList.h" -#undef CSS_PROP_ALIAS_LIST_INCLUDE_LOGICAL -#undef CSS_PROP_ALIAS - -} - -#endif // mozilla_ServoPropPrefList_h
new file mode 100644 --- /dev/null +++ b/layout/style/crashtests/1454140.html @@ -0,0 +1,4 @@ +<!-- A --> +<table background=" +#"><base href=Y: +<!-- A -->
--- a/layout/style/crashtests/crashtests.list +++ b/layout/style/crashtests/crashtests.list @@ -267,8 +267,9 @@ load 1418059.html test-pref(dom.animations-api.core.enabled,true) load 1418867.html pref(dom.webcomponents.shadowdom.enabled,true) load 1419554.html load 1426312.html load 1439793.html load 1409183.html pref(dom.webcomponents.shadowdom.enabled,true) load 1445682.html load 1450691.html pref(dom.webcomponents.shadowdom.enabled,true) load 1453206.html +load 1454140.html
--- a/layout/style/moz.build +++ b/layout/style/moz.build @@ -93,17 +93,16 @@ EXPORTS.mozilla += [ 'ServoFontFeatureValuesRule.h', 'ServoImportRule.h', 'ServoKeyframeRule.h', 'ServoKeyframesRule.h', 'ServoMediaList.h', 'ServoMediaRule.h', 'ServoNamespaceRule.h', 'ServoPageRule.h', - 'ServoPropPrefList.h', 'ServoSpecifiedValues.h', 'ServoStyleRule.h', 'ServoStyleSet.h', 'ServoStyleSetInlines.h', 'ServoStyleSheet.h', 'ServoSupportsRule.h', 'ServoTraversalStatistics.h', 'ServoTypes.h',
--- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -13,17 +13,17 @@ This file contains the list of all parsed CSS properties. It is designed to be used as inline input through the magic of C preprocessing. All entries must be enclosed in the appropriate CSS_PROP_* macro which will have cruel and unusual things done to it. It is recommended (but not strictly necessary) to keep all entries in alphabetical order. - The arguments to CSS_PROP, CSS_PROP_LOGICAL and CSS_PROP_* are: + The arguments to CSS_PROP are: -. 'name' entries represent a CSS property name and *must* use only lowercase characters. -. 'id' should be the same as 'name' except that all hyphens ('-') in 'name' are converted to underscores ('_') in 'id'. For properties on a standards track, any '-moz-' prefix is removed in 'id'. This lets us do nice things with the macros without having to copy/convert @@ -47,29 +47,21 @@ or if the boolean property whose name is 'pref' is set to true. -. 'parsevariant', to be passed to ParseVariant in the parser. -. 'kwtable', which is either nullptr or the name of the appropriate keyword table member of class nsCSSProps, for use in nsCSSProps::LookupPropertyValue. - -. 'stylestruct_' [used only for CSS_PROP and CSS_PROP_LOGICAL, not - CSS_PROP_*] gives the name of the style struct. Can be used to make - nsStyle##stylestruct_ and eStyleStruct_##stylestruct_ - -. 'animtype_' gives the animation type (see nsStyleAnimType) of this property. CSS_PROP_SHORTHAND only takes 1-5. - CSS_PROP_LOGICAL should be used instead of CSS_PROP_struct when - defining logical properties. Logical shorthand properties should - still be defined with CSS_PROP_SHORTHAND. - ******/ /*************************************************************************/ // All includers must explicitly define CSS_PROP_SHORTHAND if they // want it. @@ -82,36 +74,16 @@ CSS_PROP_PUBLIC_OR_PRIVATE(Moz ## name_, name_) // Callers may define CSS_PROP_LIST_EXCLUDE_INTERNAL if they want to // exclude internal properties that are not represented in the DOM (only // the DOM style code defines this). All properties defined in an // #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL section must have the // CSS_PROPERTY_INTERNAL flag set. -// When capturing all properties by defining CSS_PROP, callers must also -// define one of the following three macros: -// -// CSS_PROP_LIST_EXCLUDE_LOGICAL -// Does not include logical properties (defined with CSS_PROP_LOGICAL, -// such as margin-inline-start) when capturing properties to CSS_PROP. -// -// CSS_PROP_LIST_INCLUDE_LOGICAL -// Does include logical properties when capturing properties to -// CSS_PROP. -// -// CSS_PROP_LOGICAL -// Captures logical properties separately to CSS_PROP_LOGICAL. -// -// (CSS_PROP_LIST_EXCLUDE_LOGICAL is used for example to ensure -// gPropertyCountInStruct and gPropertyIndexInStruct do not allocate any -// storage to logical properties, since the result of the cascade, stored -// in an nsRuleData, does not need to store both logical and physical -// property values.) - // Callers may also define CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND // to exclude properties that are not considered to be components of the 'all' // shorthand property. Currently this excludes 'direction' and 'unicode-bidi', // as required by the CSS Cascading and Inheritance specification, and any // internal properties that cannot be changed by using CSS syntax. For example, // the internal '-moz-system-font' property is not excluded, as it is set by the // 'font' shorthand, while '-x-lang' is excluded as there is no way to set this // internal property from a style sheet. @@ -120,53 +92,24 @@ // macro. #ifdef CSS_PROP #define USED_CSS_PROP // We still need this extra level so that CSS_PROP_DOMPROP_PREFIXED has // a chance to be expanded. #define CSS_PROP_(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) -// And similarly for logical properties. An includer can define -// CSS_PROP_LOGICAL to capture all logical properties, but otherwise they -// are included in CSS_PROP (as long as CSS_PROP_LIST_INCLUDE_LOGICAL is -// defined). -#if defined(CSS_PROP_LOGICAL) && defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) || defined(CSS_PROP_LOGICAL) && defined(CSS_PROP_LIST_INCLUDE_LOGICAL) || defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) && defined(CSS_PROP_LIST_INCLUDE_LOGICAL) -#error Do not define more than one of CSS_PROP_LOGICAL, CSS_PROP_LIST_EXCLUDE_LOGICAL and CSS_PROP_LIST_INCLUDE_LOGICAL when capturing properties using CSS_PROP. -#endif - -#ifndef CSS_PROP_LOGICAL -#ifdef CSS_PROP_LIST_INCLUDE_LOGICAL -#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) -#else -#ifndef CSS_PROP_LIST_EXCLUDE_LOGICAL -#error Must define exactly one of CSS_PROP_LOGICAL, CSS_PROP_LIST_EXCLUDE_LOGICAL and CSS_PROP_LIST_INCLUDE_LOGICAL when capturing properties using CSS_PROP. -#endif -#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) /* nothing */ -#endif -#define DEFINED_CSS_PROP_LOGICAL -#endif - #else /* !defined(CSS_PROP) */ // An includer who does not define CSS_PROP can define any or all of the // per-struct macros that are equivalent to it, and the rest will be // ignored. -#if defined(CSS_PROP_LIST_EXCLUDE_LOGICAL) || defined(CSS_PROP_LIST_INCLUDE_LOGICAL) -#error Do not define CSS_PROP_LIST_EXCLUDE_LOGICAL or CSS_PROP_LIST_INCLUDE_LOGICAL when not capturing properties using CSS_PROP. -#endif - #define CSS_PROP_(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) /* nothing */ -#ifndef CSS_PROP_LOGICAL -#define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, animtype_) /* nothing */ -#define DEFINED_CSS_PROP_LOGICAL -#endif - #endif /* !defined(CSS_PROP) */ /*************************************************************************/ // For notes XXX bug 3935 below, the names being parsed do not correspond // to the constants used internally. It would be nice to bring the // constants into line sometime. @@ -438,17 +381,17 @@ CSS_PROP_( -moz-binding, _moz_binding, CSS_PROP_DOMPROP_PREFIXED(Binding), 0, "", VARIANT_HUO, nullptr, eStyleAnimType_None) // XXX bug 3935 -CSS_PROP_LOGICAL( +CSS_PROP_( block-size, block_size, BlockSize, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) @@ -459,68 +402,68 @@ CSS_PROP_SHORTHAND( CSS_PROPERTY_PARSE_FUNCTION, "") CSS_PROP_SHORTHAND( border-block-end, border_block_end, BorderBlockEnd, CSS_PROPERTY_PARSE_FUNCTION, "") -CSS_PROP_LOGICAL( +CSS_PROP_( border-block-end-color, border_block_end_color, BorderBlockEndColor, 0, "", VARIANT_HC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( border-block-end-style, border_block_end_style, BorderBlockEndStyle, 0, "", VARIANT_HK, kBorderStyleKTable, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( border-block-end-width, border_block_end_width, BorderBlockEndWidth, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HKL | VARIANT_CALC, kBorderWidthKTable, eStyleAnimType_None) CSS_PROP_SHORTHAND( border-block-start, border_block_start, BorderBlockStart, CSS_PROPERTY_PARSE_FUNCTION, "") -CSS_PROP_LOGICAL( +CSS_PROP_( border-block-start-color, border_block_start_color, BorderBlockStartColor, 0, "", VARIANT_HC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( border-block-start-style, border_block_start_style, BorderBlockStartStyle, 0, "", VARIANT_HK, kBorderStyleKTable, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( border-block-start-width, border_block_start_width, BorderBlockStartWidth, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HKL | VARIANT_CALC, kBorderWidthKTable, eStyleAnimType_None) @@ -642,68 +585,68 @@ CSS_PROP_( nullptr, eStyleAnimType_Discrete) CSS_PROP_SHORTHAND( border-inline-end, border_inline_end, BorderInlineEnd, CSS_PROPERTY_PARSE_FUNCTION, "") -CSS_PROP_LOGICAL( +CSS_PROP_( border-inline-end-color, border_inline_end_color, BorderInlineEndColor, 0, "", VARIANT_HC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( border-inline-end-style, border_inline_end_style, BorderInlineEndStyle, 0, "", VARIANT_HK, kBorderStyleKTable, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( border-inline-end-width, border_inline_end_width, BorderInlineEndWidth, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HKL | VARIANT_CALC, kBorderWidthKTable, eStyleAnimType_None) CSS_PROP_SHORTHAND( border-inline-start, border_inline_start, BorderInlineStart, CSS_PROPERTY_PARSE_FUNCTION, "") -CSS_PROP_LOGICAL( +CSS_PROP_( border-inline-start-color, border_inline_start_color, BorderInlineStartColor, 0, "", VARIANT_HC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( border-inline-start-style, border_inline_start_style, BorderInlineStartStyle, 0, "", VARIANT_HK, kBorderStyleKTable, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( border-inline-start-width, border_inline_start_width, BorderInlineStartWidth, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HKL | VARIANT_CALC, kBorderWidthKTable, eStyleAnimType_None) @@ -1324,17 +1267,17 @@ CSS_PROP_( FlexWrap, 0, "", VARIANT_HK, kFlexWrapKTable, eStyleAnimType_Discrete) CSS_PROP_( float, - float_, + float, CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float), 0, "", VARIANT_HK, kFloatKTable, eStyleAnimType_Discrete) CSS_PROP_( -moz-float-edge, @@ -1766,17 +1709,17 @@ CSS_PROP_( ime-mode, ime_mode, ImeMode, 0, "", VARIANT_HK, kIMEModeKTable, eStyleAnimType_Discrete) -CSS_PROP_LOGICAL( +CSS_PROP_( inline-size, inline_size, InlineSize, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHKLP | VARIANT_CALC, kWidthKTable, eStyleAnimType_None) @@ -1901,26 +1844,26 @@ CSS_PROP_( nullptr, eStyleAnimType_Discrete) CSS_PROP_SHORTHAND( margin, margin, Margin, CSS_PROPERTY_PARSE_FUNCTION, "") -CSS_PROP_LOGICAL( +CSS_PROP_( margin-block-end, margin_block_end, MarginBlockEnd, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( margin-block-start, margin_block_start, MarginBlockStart, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) @@ -1928,26 +1871,26 @@ CSS_PROP_( margin-bottom, margin_bottom, MarginBottom, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_Sides_Bottom) -CSS_PROP_LOGICAL( +CSS_PROP_( margin-inline-end, margin_inline_end, MarginInlineEnd, 0, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( margin-inline-start, margin_inline_start, MarginInlineStart, 0, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) @@ -2136,17 +2079,17 @@ CSS_PROP_( CSS_PROPERTY_INTERNAL | CSS_PROPERTY_PARSE_INACCESSIBLE, "", VARIANT_HK, kMathVariantKTable, eStyleAnimType_None) #endif // CSS_PROP_LIST_EXCLUDE_INTERNAL #endif // CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND -CSS_PROP_LOGICAL( +CSS_PROP_( max-block-size, max_block_size, MaxBlockSize, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HLPO | VARIANT_CALC, nullptr, eStyleAnimType_None) @@ -2154,17 +2097,17 @@ CSS_PROP_( max-height, max_height, MaxHeight, 0, "", VARIANT_HKLPO | VARIANT_CALC, kWidthKTable, eStyleAnimType_Coord) -CSS_PROP_LOGICAL( +CSS_PROP_( max-inline-size, max_inline_size, MaxInlineSize, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HKLPO | VARIANT_CALC, kWidthKTable, eStyleAnimType_None) @@ -2172,17 +2115,17 @@ CSS_PROP_( max-width, max_width, MaxWidth, 0, "", VARIANT_HKLPO | VARIANT_CALC, kWidthKTable, eStyleAnimType_Coord) -CSS_PROP_LOGICAL( +CSS_PROP_( min-block-size, min_block_size, MinBlockSize, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) @@ -2202,17 +2145,17 @@ CSS_PROP_( min-height, min_height, MinHeight, 0, "", VARIANT_AHKLP | VARIANT_CALC, kWidthKTable, eStyleAnimType_Coord) -CSS_PROP_LOGICAL( +CSS_PROP_( min-inline-size, min_inline_size, MinInlineSize, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHKLP | VARIANT_CALC, kWidthKTable, eStyleAnimType_None) @@ -2247,44 +2190,44 @@ CSS_PROP_( object-position, object_position, ObjectPosition, CSS_PROPERTY_PARSE_FUNCTION, "", VARIANT_CALC, kImageLayerPositionKTable, eStyleAnimType_Custom) -CSS_PROP_LOGICAL( +CSS_PROP_( offset-block-end, offset_block_end, OffsetBlockEnd, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( offset-block-start, offset_block_start, OffsetBlockStart, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( offset-inline-end, offset_inline_end, OffsetInlineEnd, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( offset-inline-start, offset_inline_start, OffsetInlineStart, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_AHLP | VARIANT_CALC, nullptr, eStyleAnimType_None) @@ -2458,26 +2401,26 @@ CSS_PROP_( kOverflowSubKTable, eStyleAnimType_Discrete) CSS_PROP_SHORTHAND( padding, padding, Padding, CSS_PROPERTY_PARSE_FUNCTION, "") -CSS_PROP_LOGICAL( +CSS_PROP_( padding-block-end, padding_block_end, PaddingBlockEnd, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HLP | VARIANT_CALC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( padding-block-start, padding_block_start, PaddingBlockStart, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HLP | VARIANT_CALC, nullptr, eStyleAnimType_None) @@ -2485,26 +2428,26 @@ CSS_PROP_( padding-bottom, padding_bottom, PaddingBottom, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HLP | VARIANT_CALC, nullptr, eStyleAnimType_Sides_Bottom) -CSS_PROP_LOGICAL( +CSS_PROP_( padding-inline-end, padding_inline_end, PaddingInlineEnd, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HLP | VARIANT_CALC, nullptr, eStyleAnimType_None) -CSS_PROP_LOGICAL( +CSS_PROP_( padding-inline-start, padding_inline_start, PaddingInlineStart, CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, "", VARIANT_HLP | VARIANT_CALC, nullptr, eStyleAnimType_None) @@ -3537,14 +3480,10 @@ CSS_PROP_( eStyleAnimType_Coord) #undef CSS_PROP_ #ifdef DEFINED_CSS_PROP_SHORTHAND #undef CSS_PROP_SHORTHAND #undef DEFINED_CSS_PROP_SHORTHAND #endif -#ifdef DEFINED_CSS_PROP_LOGICAL -#undef CSS_PROP_LOGICAL -#undef DEFINED_CSS_PROP_LOGICAL -#endif #undef CSS_PROP_DOMPROP_PREFIXED
--- a/layout/style/nsCSSPropertyID.h +++ b/layout/style/nsCSSPropertyID.h @@ -17,19 +17,17 @@ To change the list of properties, see nsCSSPropList.h */ enum nsCSSPropertyID { eCSSProperty_UNKNOWN = -1, #define CSS_PROP(name_, id_, ...) eCSSProperty_##id_, - #define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" - #undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP eCSSProperty_COUNT_no_shorthands, // Make the count continue where it left off: eCSSProperty_COUNT_DUMMY = eCSSProperty_COUNT_no_shorthands - 1, #define CSS_PROP_SHORTHAND(name_, id_, ...) eCSSProperty_##id_, #include "nsCSSPropList.h"
--- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -36,42 +36,36 @@ typedef nsCSSProps::KTableEntry KTableEn // By wrapping internal-only properties in this macro, we are not // exposing them in the CSSOM. Since currently it is not necessary to // allow accessing them in that way, it is easier and cheaper to just // do this rather than exposing them conditionally. #define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \ static_assert(!((flags_) & CSS_PROPERTY_ENABLED_MASK) || pref_[0], \ "Internal-only property '" #name_ "' should be wrapped in " \ "#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL"); -#define CSS_PROP_LIST_INCLUDE_LOGICAL #define CSS_PROP_LIST_EXCLUDE_INTERNAL #include "nsCSSPropList.h" #undef CSS_PROP_LIST_EXCLUDE_INTERNAL -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \ static_assert(!((flags_) & CSS_PROPERTY_ENABLED_IN_CHROME) || \ ((flags_) & CSS_PROPERTY_ENABLED_IN_UA_SHEETS), \ "Property '" #name_ "' is enabled in chrome, so it should " \ "also be enabled in UA sheets"); -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP // required to make the symbol external, so that TestCSSPropertyLookup.cpp can link with it extern const char* const kCSSRawProperties[]; // define an array of all CSS properties const char* const kCSSRawProperties[eCSSProperty_COUNT_with_aliases] = { #define CSS_PROP(name_, ...) #name_, -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) #name_, #include "nsCSSPropList.h" #undef CSS_PROP_SHORTHAND #define CSS_PROP_ALIAS(aliasname_, aliasid_, id_, method_, pref_) #aliasname_, #include "nsCSSPropAliasList.h" #undef CSS_PROP_ALIAS }; @@ -184,19 +178,17 @@ nsCSSProps::AddRefTable(void) #define OBSERVE_PROP(pref_, id_) \ if (pref_[0]) { \ Preferences::AddBoolVarCache(&gPropertyEnabled[id_], \ pref_); \ } #define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \ OBSERVE_PROP(pref_, eCSSProperty_##id_) - #define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" - #undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \ OBSERVE_PROP(pref_, eCSSProperty_##id_) #include "nsCSSPropList.h" #undef CSS_PROP_SHORTHAND #define CSS_PROP_ALIAS(aliasname_, aliasid_, propid_, aliasmethod_, pref_) \ @@ -237,21 +229,19 @@ nsCSSProps::AddRefTable(void) } // Assert that CSS_PROPERTY_INTERNAL is used on properties in // #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL sections of nsCSSPropList.h // and on no others. static nsCSSPropertyID nonInternalProperties[] = { #define CSS_PROP(name_, id_, ...) eCSSProperty_##id_, #define CSS_PROP_SHORTHAND(name_, id_, ...) eCSSProperty_##id_, - #define CSS_PROP_LIST_INCLUDE_LOGICAL #define CSS_PROP_LIST_EXCLUDE_INTERNAL #include "nsCSSPropList.h" #undef CSS_PROP_LIST_EXCLUDE_INTERNAL - #undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP_SHORTHAND #undef CSS_PROP }; MOZ_ASSERT(ArrayLength(nonInternalProperties) <= eCSSProperty_COUNT); bool found[eCSSProperty_COUNT]; PodArrayZero(found); for (nsCSSPropertyID p : nonInternalProperties) { @@ -2223,19 +2213,17 @@ nsCSSProps::ValueToKeyword(int32_t aValu return nsCSSKeywords::GetStringValue(keyword); } } /* static */ const KTableEntry* const nsCSSProps::kKeywordTableTable[eCSSProperty_COUNT_no_shorthands] = { #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, \ kwtable_, ...) kwtable_, - #define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" - #undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP }; const nsCString& nsCSSProps::LookupPropertyValue(nsCSSPropertyID aProp, int32_t aValue) { MOZ_ASSERT(aProp >= 0 && aProp < eCSSProperty_COUNT, "property out of range"); @@ -2272,40 +2260,34 @@ bool nsCSSProps::GetColorName(int32_t aP return rv; } const nsStyleAnimType nsCSSProps::kAnimTypeTable[eCSSProperty_COUNT_no_shorthands] = { #define CSS_PROP(name_, id_, method_, flags_, pref_, \ parsevariant_, kwtable_, animtype_) \ animtype_, -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP }; const uint32_t nsCSSProps::kFlagsTable[eCSSProperty_COUNT] = { #define CSS_PROP(name_, id_, method_, flags_, ...) flags_, -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) flags_, #include "nsCSSPropList.h" #undef CSS_PROP_SHORTHAND }; static const nsCSSPropertyID gAllSubpropTable[] = { #define CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND -#define CSS_PROP_LIST_INCLUDE_LOGICAL #define CSS_PROP(name_, id_, ...) eCSSProperty_##id_, #include "nsCSSPropList.h" #undef CSS_PROP -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND eCSSProperty_UNKNOWN }; static const nsCSSPropertyID gAnimationSubpropTable[] = { eCSSProperty_animation_duration, eCSSProperty_animation_timing_function, eCSSProperty_animation_delay, @@ -2749,19 +2731,17 @@ nsCSSProps::gPropertyEnabled[eCSSPropert // value is, it will later be changed in nsCSSProps::AddRefTable(). // If the property has "ENABLED_IN" flags but doesn't have a pref, // it is an internal property which is disabled elsewhere. #define IS_ENABLED_BY_DEFAULT(flags_) \ (!((flags_) & CSS_PROPERTY_ENABLED_MASK)) #define CSS_PROP(name_, id_, method_, flags_, ...) \ IS_ENABLED_BY_DEFAULT(flags_), - #define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" - #undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) \ IS_ENABLED_BY_DEFAULT(flags_), #include "nsCSSPropList.h" #undef CSS_PROP_SHORTHAND #define CSS_PROP_ALIAS(aliasname_, aliasid_, propid_, aliasmethod_, pref_) \ @@ -2772,28 +2752,24 @@ nsCSSProps::gPropertyEnabled[eCSSPropert #undef IS_ENABLED_BY_DEFAULT }; #include "../../dom/base/PropertyUseCounterMap.inc" /* static */ const UseCounter nsCSSProps::gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands] = { #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_ - #define CSS_PROP_LIST_INCLUDE_LOGICAL #define CSS_PROP(name_, id_, method_, ...) \ static_cast<UseCounter>(USE_COUNTER_FOR_CSS_PROPERTY_##method_), #include "nsCSSPropList.h" #undef CSS_PROP - #undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP_PUBLIC_OR_PRIVATE }; const uint32_t nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = { #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, ...) \ parsevariant_, -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP }; #include "nsCSSPropsGenerated.inc"
--- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -7178,31 +7178,27 @@ nsComputedDOMStyle::RegisterPrefChangeCa // entries iterated in nsComputedDOMStylePropertyList.h. ComputedStyleMap* data = GetComputedStyleMap(); #define REGISTER_CALLBACK(pref_) \ if (pref_[0]) { \ Preferences::RegisterCallback(MarkComputedStyleMapDirty, pref_, data); \ } #define CSS_PROP(prop_, id_, method_, flags_, pref_, ...) \ REGISTER_CALLBACK(pref_) -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #undef REGISTER_CALLBACK } /* static */ void nsComputedDOMStyle::UnregisterPrefChangeCallbacks() { ComputedStyleMap* data = GetComputedStyleMap(); #define UNREGISTER_CALLBACK(pref_) \ if (pref_[0]) { \ Preferences::UnregisterCallback(MarkComputedStyleMapDirty, pref_, data); \ } #define CSS_PROP(prop_, id_, method_, flags_, pref_, ...) \ UNREGISTER_CALLBACK(pref_) -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #undef UNREGISTER_CALLBACK }
--- a/layout/style/nsComputedDOMStylePropertyList.h +++ b/layout/style/nsComputedDOMStylePropertyList.h @@ -124,17 +124,17 @@ COMPUTED_STYLE_PROP(cursor, COMPUTED_STYLE_PROP(direction, Direction) COMPUTED_STYLE_PROP(display, Display) COMPUTED_STYLE_PROP(empty_cells, EmptyCells) COMPUTED_STYLE_PROP(flex_basis, FlexBasis) COMPUTED_STYLE_PROP(flex_direction, FlexDirection) COMPUTED_STYLE_PROP(flex_grow, FlexGrow) COMPUTED_STYLE_PROP(flex_shrink, FlexShrink) COMPUTED_STYLE_PROP(flex_wrap, FlexWrap) -COMPUTED_STYLE_PROP(float_, Float) +COMPUTED_STYLE_PROP(float, Float) //// COMPUTED_STYLE_PROP(font, Font) COMPUTED_STYLE_PROP(font_family, FontFamily) COMPUTED_STYLE_PROP(font_feature_settings, FontFeatureSettings) COMPUTED_STYLE_PROP(font_kerning, FontKerning) COMPUTED_STYLE_PROP(font_language_override, FontLanguageOverride) COMPUTED_STYLE_PROP(font_optical_sizing, FontOpticalSizing) COMPUTED_STYLE_PROP(font_size, FontSize) COMPUTED_STYLE_PROP(font_size_adjust, FontSizeAdjust)
--- a/layout/style/nsDOMCSSDeclaration.h +++ b/layout/style/nsDOMCSSDeclaration.h @@ -93,27 +93,25 @@ public: void \ Set##method_(const nsAString& aValue, nsIPrincipal* aSubjectPrincipal, \ mozilla::ErrorResult& rv) \ { \ rv = SetPropertyValue(eCSSProperty_##id_, aValue, aSubjectPrincipal); \ } #define CSS_PROP_LIST_EXCLUDE_INTERNAL -#define CSS_PROP_LIST_INCLUDE_LOGICAL #define CSS_PROP_SHORTHAND(name_, id_, method_, ...) CSS_PROP(name_, id_, method_, ) #include "nsCSSPropList.h" #define CSS_PROP_ALIAS(aliasname_, aliasid_, propid_, aliasmethod_, ...) \ CSS_PROP(X, propid_, aliasmethod_, ) #include "nsCSSPropAliasList.h" #undef CSS_PROP_ALIAS #undef CSS_PROP_SHORTHAND -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP_LIST_EXCLUDE_INTERNAL #undef CSS_PROP #undef CSS_PROP_PUBLIC_OR_PRIVATE virtual void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName) override; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2170,18 +2170,22 @@ nsStyleImageRequest::Resolve( mResolved = true; nsIDocument* doc = aPresContext->Document(); nsIURI* docURI = doc->GetDocumentURI(); if (GetImageValue()->HasRef()) { bool isEqualExceptRef = false; RefPtr<nsIURI> imageURI = GetImageURI(); - imageURI->EqualsExceptRef(docURI, &isEqualExceptRef); - if (isEqualExceptRef) { + if (!imageURI) { + return false; + } + + if (NS_SUCCEEDED(imageURI->EqualsExceptRef(docURI, &isEqualExceptRef)) && + isEqualExceptRef) { // Prevent loading an internal resource. return true; } } // TODO(emilio, bug 1440442): This is a hackaround to avoid flickering due the // lack of non-http image caching in imagelib (bug 1406134), which causes // stuff like bug 1439285. Cleanest fix if that doesn't get fixed is bug
--- a/layout/style/test/ListCSSProperties.cpp +++ b/layout/style/test/ListCSSProperties.cpp @@ -16,40 +16,36 @@ struct PropertyInfo { const char *pref; }; const PropertyInfo gLonghandProperties[] = { #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_ #define CSS_PROP(name_, id_, method_, flags_, pref_, ...) \ { #name_, #method_, pref_ }, -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #undef CSS_PROP_PUBLIC_OR_PRIVATE }; /* * These are the properties for which domName in the above list should * be used. They're in the same order as the above list, with some * items skipped. */ const char* gLonghandPropertiesWithDOMProp[] = { #define CSS_PROP_LIST_EXCLUDE_INTERNAL #define CSS_PROP(name_, ...) #name_, -#define CSS_PROP_LIST_INCLUDE_LOGICAL #include "nsCSSPropList.h" -#undef CSS_PROP_LIST_INCLUDE_LOGICAL #undef CSS_PROP #undef CSS_PROP_LIST_EXCLUDE_INTERNAL }; const PropertyInfo gShorthandProperties[] = { #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_
--- a/layout/svg/crashtests/crashtests.list +++ b/layout/svg/crashtests/crashtests.list @@ -202,8 +202,9 @@ load 1322537-2.html load 1322852.html load 1348564.svg load 1402109.html load 1402124.html load 1402486.html load conditional-outer-svg-nondirty-reflow-assert.xhtml load extref-test-1.xhtml load blob-merging-and-retained-display-list.html +load grouping-empty-bounds.html
new file mode 100644 --- /dev/null +++ b/layout/svg/crashtests/grouping-empty-bounds.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html lang="en" class='reftest-wait'> +<meta charset="utf-8"> +<title>This testcase might create a non-empty display list with an empty set of drawing commands / items in the EventRecorder</title> + +<style> + +body { + margin: 0; +} + +.animated-opacity { + animation: opacity-animation 1s linear alternate infinite; +} + +@keyframes opacity-animation { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +</style> + +<svg style="width: 100px; height: 100px;"> + <rect class="animated-opacity" x="0" y="0" width="100" height="100"/> + <rect x="0" y="0" width="10" height="10" id="toremove"/> + <g transform="translate(10 10)"><rect x="120" y="0" width="1" height="1"/></g> +</svg> + +<script> + +window.addEventListener("MozReftestInvalidate", () => { + var elem = document.getElementById("toremove"); + elem.parentNode.removeChild(elem); + document.documentElement.removeAttribute('class'); +}); + +</script>
--- a/mobile/android/app/src/photon/res/values/styles.xml +++ b/mobile/android/app/src/photon/res/values/styles.xml @@ -473,17 +473,17 @@ <item name="android:textAppearance">@style/TextAppearance.UrlBar.Title</item> <item name="android:textColor">@color/url_bar_title</item> <item name="android:textColorHint">@color/url_bar_title_hint</item> <item name="android:textColorHighlight">@color/url_bar_title_highlight</item> <item name="android:textSelectHandle">@drawable/handle_middle</item> <item name="android:textSelectHandleLeft">@drawable/handle_start</item> <item name="android:textSelectHandleRight">@drawable/handle_end</item> <item name="android:textCursorDrawable">@null</item> - <item name="android:singleLine">true</item> + <item name="android:maxLines">1</item> <item name="android:gravity">center_vertical|left|start</item> <item name="android:hint">@string/url_bar_default_text</item> </style> <!-- URL bar - Image Button --> <style name="UrlBar.ImageButtonBase" parent="UrlBar.Button"> <item name="android:scaleType">center</item> <item name="android:layout_gravity">center_vertical</item>
--- a/mobile/android/chrome/content/config.js +++ b/mobile/android/chrome/content/config.js @@ -567,25 +567,16 @@ Pref.prototype = { reset: function AC_reset() { Services.prefs.clearUserPref(this.name); }, test: function AC_test(aValue) { return aValue ? aValue.test(this.name) : true; }, - escapeHTML: function(input) { - return input.replace(/&/g, "&") - .replace(/</g, "<") - .replace(/>/g, ">") - .replace(/"/g, """) - .replace(/'/g, "'") - .replace(/\//g, "/"); - }, - // Get existing or create new LI node for the pref getOrCreateNewLINode: function AC_getOrCreateNewLINode() { if (!this.li) { this.li = document.createElement("li"); this.li.className = "pref-item"; this.li.setAttribute("name", this.name); @@ -600,42 +591,70 @@ Pref.prototype = { this.li.addEventListener("contextmenu", function(aEvent) { AboutConfig.contextMenuLINode = AboutConfig.getLINodeForEvent(aEvent); } ); this.li.setAttribute("contextmenu", "prefs-context-menu"); - // Create list item outline, bind to object actions - this.li.unsafeSetInnerHTML( - "<div class='pref-name' " + - "onclick='AboutConfig.selectOrToggleBoolPref(event);'>" + - this.escapeHTML(this.name) + - "</div>" + - "<div class='pref-item-line'>" + - "<input class='pref-value' value='' " + - "onblur='AboutConfig.setIntOrStringPref(event);' " + - "onclick='AboutConfig.selectOrToggleBoolPref(event);'>" + - "</input>" + - "<div class='pref-button reset' " + - "onclick='AboutConfig.resetDefaultPref(event);'>" + - gStringBundle.GetStringFromName("pref.resetButton") + - "</div>" + - "<div class='pref-button toggle' " + - "onclick='AboutConfig.toggleBoolPref(event);'>" + - gStringBundle.GetStringFromName("pref.toggleButton") + - "</div>" + - "<div class='pref-button up' " + - "onclick='AboutConfig.incrOrDecrIntPref(event, 1);'>" + - "</div>" + - "<div class='pref-button down' " + - "onclick='AboutConfig.incrOrDecrIntPref(event, -1);'>" + - "</div>" + - "</div>"); + let prefName = document.createElement("div"); + prefName.className = "pref-name"; + prefName.addEventListener("click", function(event) { + AboutConfig.selectOrToggleBoolPref(event); + }); + prefName.textContent = this.name; + + this.li.appendChild(prefName); + + let prefItemLine = document.createElement("div"); + prefItemLine.className = "pref-item-line"; + + let prefValue = document.createElement("input"); + prefValue.className = "pref-value"; + prefValue.addEventListener("blur", function(event) { + AboutConfig.setIntOrStringPref(event); + }); + prefValue.addEventListener("click", function(event) { + AboutConfig.selectOrToggleBoolPref(event); + }); + prefValue.value = ""; + prefItemLine.appendChild(prefValue); + + let resetButton = document.createElement("div"); + resetButton.className = "pref-button reset"; + resetButton.addEventListener("click", function(event) { + AboutConfig.resetDefaultPref(event); + }); + resetButton.textContent = gStringBundle.GetStringFromName("pref.resetButton"); + prefItemLine.appendChild(resetButton); + + let toggleButton = document.createElement("div"); + toggleButton.className = "pref-button toggle"; + toggleButton.addEventListener("click", function(event) { + AboutConfig.toggleBoolPref(event); + }); + toggleButton.textContent = gStringBundle.GetStringFromName("pref.toggleButton"); + prefItemLine.appendChild(toggleButton); + + let upButton = document.createElement("div"); + upButton.className = "pref-button up"; + upButton.addEventListener("click", function(event) { + AboutConfig.incrOrDecrIntPref(event, 1); + }); + prefItemLine.appendChild(upButton); + + let downButton = document.createElement("div"); + downButton.className = "pref-button down"; + downButton.addEventListener("click", function(event) { + AboutConfig.incrOrDecrIntPref(event, -1); + }); + prefItemLine.appendChild(downButton); + + this.li.appendChild(prefItemLine); // Delay providing the list item values, until the LI is returned and added to the document setTimeout(this._valueSetup.bind(this), INNERHTML_VALUE_DELAY); } return this.li; },
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2150,16 +2150,17 @@ pref("network.proxy.failover_timeout", pref("network.online", true); //online/offline pref("network.cookie.cookieBehavior", 0); // 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign #ifdef ANDROID pref("network.cookie.cookieBehavior", 0); // Keep the old default of accepting all cookies #endif pref("network.cookie.thirdparty.sessionOnly", false); pref("network.cookie.thirdparty.nonsecureSessionOnly", false); pref("network.cookie.leave-secure-alone", true); +pref("network.cookie.same-site.enabled", true); // Honor the SameSite cookie attribute pref("network.cookie.ipc.sync", false); pref("network.cookie.lifetimePolicy", 0); // 0-accept, 1-dontUse 2-acceptForSession, 3-acceptForNDays pref("network.cookie.prefsMigrated", false); pref("network.cookie.lifetime.days", 90); // Ignored unless network.cookie.lifetimePolicy is 3. // The PAC file to load. Ignored unless network.proxy.type is 2. pref("network.proxy.autoconfig_url", ""); // Strip off paths when sending URLs to PAC scripts @@ -2524,26 +2525,31 @@ pref("extensions.blocklist.detailsURL", pref("extensions.blocklist.itemURL", "https://blocked.cdn.mozilla.net/%blockID%.html"); // Controls what level the blocklist switches from warning about items to forcibly // blocking them. pref("extensions.blocklist.level", 2); // Blocklist via settings server (Kinto) pref("services.blocklist.bucket", "blocklists"); pref("services.blocklist.onecrl.collection", "certificates"); pref("services.blocklist.onecrl.checked", 0); +pref("services.blocklist.onecrl.signer", "onecrl.content-signature.mozilla.org"); pref("services.blocklist.addons.collection", "addons"); pref("services.blocklist.addons.checked", 0); +pref("services.blocklist.addons.signer", "onecrl.content-signature.mozilla.org"); pref("services.blocklist.plugins.collection", "plugins"); pref("services.blocklist.plugins.checked", 0); +pref("services.blocklist.plugins.signer", "onecrl.content-signature.mozilla.org"); pref("services.blocklist.pinning.enabled", true); pref("services.blocklist.pinning.bucket", "pinning"); pref("services.blocklist.pinning.collection", "pins"); pref("services.blocklist.pinning.checked", 0); +pref("services.blocklist.pinning.signer", "pinning-preload.content-signature.mozilla.org"); pref("services.blocklist.gfx.collection", "gfx"); pref("services.blocklist.gfx.checked", 0); +pref("services.blocklist.gfx.signer", "onecrl.content-signature.mozilla.org"); // Enable blocklists via the services settings mechanism pref("services.blocklist.update_enabled", true); // Modifier key prefs: default to Windows settings, // menu access key = alt, accelerator key = control. // Use 17 for Ctrl, 18 for Alt, 224 for Meta, 91 for Win, 0 for none. Mac settings in macprefs.js pref("ui.key.accelKey", 17); pref("ui.key.menuAccessKey", 18);
--- a/netwerk/cookie/CookieServiceChild.cpp +++ b/netwerk/cookie/CookieServiceChild.cpp @@ -309,17 +309,17 @@ CookieServiceChild::GetCookieStringFromC continue; // if the cookie is secure and the host scheme isn't, we can't send it if (cookie->IsSecure() && !isSecure) continue; int32_t sameSiteAttr = 0; cookie->GetSameSite(&sameSiteAttr); - if (aIsSameSiteForeign) { + if (aIsSameSiteForeign && nsCookieService::IsSameSiteEnabled()) { // it if's a cross origin request and the cookie is same site only (strict) // don't send it if (sameSiteAttr == nsICookie2::SAMESITE_STRICT) { continue; } // if it's a cross origin request, the cookie is same site lax, but it's not // a top-level navigation, don't send it if (sameSiteAttr == nsICookie2::SAMESITE_LAX && !aIsSafeTopLevelNav) {
--- a/netwerk/cookie/nsCookieService.cpp +++ b/netwerk/cookie/nsCookieService.cpp @@ -71,16 +71,17 @@ using namespace mozilla::net; nsCookieKey(baseDomain, OriginAttributes()) /****************************************************************************** * nsCookieService impl: * useful types & constants ******************************************************************************/ static StaticRefPtr<nsCookieService> gCookieService; +bool nsCookieService::sSameSiteEnabled = false; // XXX_hack. See bug 178993. // This is a hack to hide HttpOnly cookies from older browsers #define HTTP_ONLY_PREFIX "#HttpOnly_" #define COOKIES_FILE "cookies.sqlite" #define COOKIES_SCHEMA_VERSION 9 @@ -3070,16 +3071,28 @@ nsCookieService::DomainMatches(nsCookie* // first, check for an exact host or domain cookie match, e.g. "google.com" // or ".google.com"; second a subdomain match, e.g. // host = "mail.google.com", cookie domain = ".google.com". return aCookie->RawHost() == aHost || (aCookie->IsDomain() && StringEndsWith(aHost, aCookie->Host())); } bool +nsCookieService::IsSameSiteEnabled() +{ + static bool prefInitialized = false; + if (!prefInitialized) { + Preferences::AddBoolVarCache(&sSameSiteEnabled, + "network.cookie.same-site.enabled", false); + prefInitialized = true; + } + return sSameSiteEnabled; +} + +bool nsCookieService::PathMatches(nsCookie* aCookie, const nsACString& aPath) { // calculate cookie path length, excluding trailing '/' uint32_t cookiePathLen = aCookie->Path().Length(); if (cookiePathLen > 0 && aCookie->Path().Last() == '/') --cookiePathLen; @@ -3199,17 +3212,17 @@ nsCookieService::GetCookiesForURI(nsIURI continue; // if the cookie is secure and the host scheme isn't, we can't send it if (cookie->IsSecure() && !isSecure) continue; int32_t sameSiteAttr = 0; cookie->GetSameSite(&sameSiteAttr); - if (aIsSameSiteForeign) { + if (aIsSameSiteForeign && IsSameSiteEnabled()) { // it if's a cross origin request and the cookie is same site only (strict) // don't send it if (sameSiteAttr == nsICookie2::SAMESITE_STRICT) { continue; } // if it's a cross origin request, the cookie is same site lax, but it's not // a top-level navigation, don't send it if (sameSiteAttr == nsICookie2::SAMESITE_LAX && !aIsSafeTopLevelNav) { @@ -3466,18 +3479,19 @@ nsCookieService::CanSetCookie(nsIURI* "non-https cookie can't set secure flag"); Telemetry::Accumulate(Telemetry::COOKIE_LEAVE_SECURE_ALONE, BLOCKED_SECURE_SET_FROM_HTTP); return newCookie; } // If the new cookie is same-site but in a cross site context, // browser must ignore the cookie. - if (aCookieAttributes.sameSite != nsICookie2::SAMESITE_UNSET && - aThirdPartyUtil) { + if ((aCookieAttributes.sameSite != nsICookie2::SAMESITE_UNSET) && + aThirdPartyUtil && + IsSameSiteEnabled()) { bool isThirdParty = false; aThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isThirdParty); if (isThirdParty) { COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the samesite tests"); return newCookie; } }
--- a/netwerk/cookie/nsCookieService.h +++ b/netwerk/cookie/nsCookieService.h @@ -237,16 +237,18 @@ class nsCookieService final : public nsI , public nsICookieManager , public nsIObserver , public nsSupportsWeakReference , public nsIMemoryReporter { private: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + static bool sSameSiteEnabled; // cached pref + public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER NS_DECL_NSICOOKIESERVICE NS_DECL_NSICOOKIEMANAGER NS_DECL_NSIMEMORYREPORTER nsCookieService(); @@ -259,16 +261,17 @@ class nsCookieService final : public nsI * (thus instantiating it, if necessary) and clear all the cookies for that * app. */ static void AppClearDataObserverInit(); static nsCString GetPathFromURI(nsIURI *aHostURI); static nsresult GetBaseDomain(nsIEffectiveTLDService *aTLDService, nsIURI *aHostURI, nsCString &aBaseDomain, bool &aRequireHostMatch); static nsresult GetBaseDomainFromHost(nsIEffectiveTLDService *aTLDService, const nsACString &aHost, nsCString &aBaseDomain); static bool DomainMatches(nsCookie* aCookie, const nsACString& aHost); + static bool IsSameSiteEnabled(); static bool PathMatches(nsCookie* aCookie, const nsACString& aPath); static bool CanSetCookie(nsIURI *aHostURI, const nsCookieKey& aKey, nsCookieAttributes &aCookieAttributes, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel, bool aLeaveSercureAlone, bool &aSetCookie, mozIThirdPartyUtil* aThirdPartyUtil); static CookieStatus CheckPrefs(nsICookiePermission *aPermissionServices, uint8_t aCookieBehavior, bool aThirdPartySession, bool aThirdPartyNonsecureSession, nsIURI *aHostURI, bool aIsForeign, const char *aCookieHeader, const int aNumOfCookies, const OriginAttributes& aOriginAttrs); static int64_t ParseServerTime(const nsCString &aServerTime); void GetCookiesForURI(nsIURI *aHostURI, bool aIsForeign, bool aIsSafeTopLevelNav, bool aIsTopLevelForeign, bool aHttpBound, const OriginAttributes& aOriginAttrs, nsTArray<nsCookie*>& aCookieList); protected: virtual ~nsCookieService();
--- a/netwerk/dns/TRRService.cpp +++ b/netwerk/dns/TRRService.cpp @@ -568,26 +568,33 @@ TRRService::CompleteLookup(nsHostRecord NS_NewTimerWithCallback(getter_AddRefs(mRetryConfirmTimer), this, mRetryConfirmInterval, nsITimer::TYPE_ONE_SHOT); if (mRetryConfirmInterval < 64000) { // double the interval up to this point mRetryConfirmInterval *= 2; } } else { + if (mMode != MODE_TRRONLY) { + // don't accumulate trronly data here since trronly failures are + // handled above by trying again, so counting the successes here would + // skew the numbers + Telemetry::Accumulate(Telemetry::DNS_TRR_NS_VERFIFIED, + (mConfirmationState == CONFIRM_OK)); + } mRetryConfirmInterval = 1000; } return LOOKUP_OK; } // when called without a host record, this is a domain name check response. if (NS_SUCCEEDED(status)) { LOG(("TRR verified %s to be fine!\n", newRRSet->mHostName)); } else { - LOG(("TRR says %s doesn't resove as NS!\n", newRRSet->mHostName)); + LOG(("TRR says %s doesn't resolve as NS!\n", newRRSet->mHostName)); TRRBlacklist(nsCString(newRRSet->mHostName), pb, false); } return LOOKUP_OK; } #undef LOG } // namespace net
--- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -295,33 +295,31 @@ nsHostRecord::ResolveComplete() Telemetry::LABELS_DNS_TRR_RACE::NativeFasterBy50 : Telemetry::LABELS_DNS_TRR_RACE::NativeFaster); LOG(("nsHostRecord::Complete %s Dns Race: NATIVE\n", host.get())); } } switch(mResolverMode) { case MODE_NATIVEONLY: + case MODE_TRROFF: AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::nativeOnly); break; case MODE_PARALLEL: AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrRace); break; case MODE_TRRFIRST: AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrFirst); break; case MODE_TRRONLY: AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrOnly); break; case MODE_SHADOW: AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrShadow); break; - case MODE_TRROFF: - AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrOff); - break; } if (mTRRUsed && !mTRRSuccess && mNativeSuccess && gTRRService) { gTRRService->TRRBlacklist(nsCString(host), pb, true); } } nsHostRecord::~nsHostRecord()
--- a/security/manager/ssl/nsIX509CertDB.idl +++ b/security/manager/ssl/nsIX509CertDB.idl @@ -73,27 +73,16 @@ interface nsIX509CertDB : nsISupports { * * @param aDBkey Database internal key, as obtained using * attribute dbkey in nsIX509Cert. */ [must_use] nsIX509Cert findCertByDBKey(in ACString aDBkey); /** - * Find a certificate by email address. - * - * @param aEmailAddress The email address to be used as the key - * to find the certificate. - * - * @return The matching certificate if found. - */ - [must_use] - nsIX509Cert findCertByEmailAddress(in ACString aEmailAddress); - - /** * Use this to import a stream sent down as a mime type into * the certificate database on the default token. * The stream may consist of one or more certificates. * * @param data The raw data to be imported * @param length The length of the data to be imported * @param type The type of the certificate, see constants in nsIX509Cert * @param ctx A UI context. @@ -295,64 +284,38 @@ interface nsIX509CertDB : nsISupports { * effectively ignored by gecko, but they still must be specified * (at least by a final trailing comma) because this argument is * passed to CERT_DecodeTrustString. * @return nsIX509Cert the resulting certificate */ [must_use] nsIX509Cert addCert(in ACString certDER, in ACString trust); - // Flags for verifyCertNow (these must match the values in CertVerifier.cpp): - // Prevent network traffic. Doesn't work with classic verification. + // Flags for asyncVerifyCertAtTime (these must match the values in + // CertVerifier.cpp): + // Prevent network traffic. const uint32_t FLAG_LOCAL_ONLY = 1 << 0; // Do not fall back to DV verification after attempting EV validation. - // Actually does prevent network traffic, but can cause a valid EV - // certificate to not be considered valid. const uint32_t FLAG_MUST_BE_EV = 1 << 1; - /** Warning: This interface is inteded to use only for testing only as: - * 1. It can create IO on the main thread. - * 2. It is in constant change, so in/out can change at any release. - * - * Obtain the verification result for a cert given a particular usage. - * On success, the call returns 0, the chain built during verification, - * and whether the cert is good for EV usage. - * On failure, the call returns the PRErrorCode for the verification failure + /* + * Asynchronously verify a certificate given a set of parameters. Calls the + * `verifyCertFinished` function on the provided `nsICertVerificationCallback` + * with the results of the verification operation. + * See the documentation for nsICertVerificationCallback. * - * @param aCert Obtain the stored trust of this certificate - * @param aUsage a integer representing the usage from NSS - * @param aFlags flags as described above - * @param aHostname the (optional) hostname to verify for - * @param aTime the time at which to verify, in seconds since the epoch - * @param aVerifiedChain chain of verification up to the root if success - * @param aHasEVPolicy bool that signified that the cert was an EV cert - * @return 0 if success or the value or the error code for the verification - * failure - */ - [must_use] - int32_t /*PRErrorCode*/ - verifyCertAtTime(in nsIX509Cert aCert, - in int64_t /*SECCertificateUsage*/ aUsage, - in uint32_t aFlags, - in ACString aHostname, - in uint64_t aTime, - out nsIX509CertList aVerifiedChain, - out bool aHasEVPolicy); - [must_use] - int32_t /*PRErrorCode*/ - verifyCertNow(in nsIX509Cert aCert, - in int64_t /*SECCertificateUsage*/ aUsage, - in uint32_t aFlags, - in ACString aHostname, - out nsIX509CertList aVerifiedChain, - out bool aHasEVPolicy); - - /** - * Similar to the above, but asynchronous. As a result, use of this API is not - * limited to tests. + * @param aCert the certificate to verify + * @param aUsage an integer representing the usage to verify for (see + * SECCertificateUsage in certt.h from NSS) + * @param aFlags flags as described above + * @param aHostname the (optional) hostname to verify for + * @param aTime the time at which to verify, in seconds since the epoch + * @param aCallback the nsICertVerificationCallback that will receive the + results of this verification + * @return a succeeding nsresult if the job was dispatched successfully */ [must_use] void asyncVerifyCertAtTime(in nsIX509Cert aCert, in int64_t /*SECCertificateUsage*/ aUsage, in uint32_t aFlags, in ACString aHostname, in uint64_t aTime, in nsICertVerificationCallback aCallback);
--- a/security/manager/ssl/nsNSSCertificateDB.cpp +++ b/security/manager/ssl/nsNSSCertificateDB.cpp @@ -884,72 +884,16 @@ nsNSSCertificateDB::ExportPKCS12File(nsI if (count == 0) { return NS_OK; } nsPKCS12Blob blob; return blob.ExportToFile(aFile, certs, count); } NS_IMETHODIMP -nsNSSCertificateDB::FindCertByEmailAddress(const nsACString& aEmailAddress, - nsIX509Cert** _retval) -{ - nsresult rv = BlockUntilLoadableRootsLoaded(); - if (NS_FAILED(rv)) { - return rv; - } - - RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); - NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); - - const nsCString& flatEmailAddress = PromiseFlatCString(aEmailAddress); - UniqueCERTCertList certlist( - PK11_FindCertsFromEmailAddress(flatEmailAddress.get(), nullptr)); - if (!certlist) - return NS_ERROR_FAILURE; - - // certlist now contains certificates with the right email address, - // but they might not have the correct usage or might even be invalid - - if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) - return NS_ERROR_FAILURE; // no certs found - - CERTCertListNode *node; - // search for a valid certificate - for (node = CERT_LIST_HEAD(certlist); - !CERT_LIST_END(node, certlist); - node = CERT_LIST_NEXT(node)) { - - UniqueCERTCertList unusedCertChain; - mozilla::pkix::Result result = - certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient, - mozilla::pkix::Now(), - nullptr /*XXX pinarg*/, - nullptr /*hostname*/, - unusedCertChain); - if (result == mozilla::pkix::Success) { - break; - } - } - - if (CERT_LIST_END(node, certlist)) { - // no valid cert found - return NS_ERROR_FAILURE; - } - - // node now contains the first valid certificate with correct usage - RefPtr<nsNSSCertificate> nssCert = nsNSSCertificate::Create(node->cert); - if (!nssCert) - return NS_ERROR_OUT_OF_MEMORY; - - nssCert.forget(_retval); - return NS_OK; -} - -NS_IMETHODIMP nsNSSCertificateDB::ConstructX509FromBase64(const nsACString& base64, /*out*/ nsIX509Cert** _retval) { if (!_retval) { return NS_ERROR_INVALID_POINTER; } // Base64Decode() doesn't consider a zero length input as an error, and just @@ -1301,45 +1245,16 @@ VerifyCertAtTime(nsIX509Cert* aCert, if (result == mozilla::pkix::Success && evOidPolicy != SEC_OID_UNKNOWN) { *aHasEVPolicy = true; } nssCertList.forget(aVerifiedChain); return NS_OK; } -NS_IMETHODIMP -nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert, - int64_t /*SECCertificateUsage*/ aUsage, - uint32_t aFlags, - const nsACString& aHostname, - nsIX509CertList** aVerifiedChain, - bool* aHasEVPolicy, - int32_t* /*PRErrorCode*/ _retval) -{ - return ::VerifyCertAtTime(aCert, aUsage, aFlags, aHostname, - mozilla::pkix::Now(), - aVerifiedChain, aHasEVPolicy, _retval); -} - -NS_IMETHODIMP -nsNSSCertificateDB::VerifyCertAtTime(nsIX509Cert* aCert, - int64_t /*SECCertificateUsage*/ aUsage, - uint32_t aFlags, - const nsACString& aHostname, - uint64_t aTime, - nsIX509CertList** aVerifiedChain, - bool* aHasEVPolicy, - int32_t* /*PRErrorCode*/ _retval) -{ - return ::VerifyCertAtTime(aCert, aUsage, aFlags, aHostname, - mozilla::pkix::TimeFromEpochInSeconds(aTime), - aVerifiedChain, aHasEVPolicy, _retval); -} - class VerifyCertAtTimeTask final : public CryptoTask { public: VerifyCertAtTimeTask(nsIX509Cert* aCert, int64_t aUsage, uint32_t aFlags, const nsACString& aHostname, uint64_t aTime, nsICertVerificationCallback* aCallback) : mCert(aCert) , mUsage(aUsage) @@ -1356,19 +1271,20 @@ public: private: virtual nsresult CalculateResult() override { nsCOMPtr<nsIX509CertDB> certDB = do_GetService(NS_X509CERTDB_CONTRACTID); if (!certDB) { return NS_ERROR_FAILURE; } - return certDB->VerifyCertAtTime(mCert, mUsage, mFlags, mHostname, mTime, - getter_AddRefs(mVerifiedCertList), - &mHasEVPolicy, &mPRErrorCode); + return VerifyCertAtTime(mCert, mUsage, mFlags, mHostname, + mozilla::pkix::TimeFromEpochInSeconds(mTime), + getter_AddRefs(mVerifiedCertList), + &mHasEVPolicy, &mPRErrorCode); } virtual void CallCallback(nsresult rv) override { if (NS_FAILED(rv)) { Unused << mCallback->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE, nullptr, false); } else {
--- a/security/manager/ssl/tests/unit/head_psm.js +++ b/security/manager/ssl/tests/unit/head_psm.js @@ -171,49 +171,63 @@ function setCertTrust(cert, trustString) } function getXPCOMStatusFromNSS(statusNSS) { let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"] .getService(Ci.nsINSSErrorsService); return nssErrorsService.getXPCOMFromNSSError(statusNSS); } +// Helper for checkCertErrorGenericAtTime +class CertVerificationExpectedErrorResult { + constructor(certName, expectedError, expectedEVStatus, resolve) { + this.certName = certName; + this.expectedError = expectedError; + this.expectedEVStatus = expectedEVStatus; + this.resolve = resolve; + } + + verifyCertFinished(aPRErrorCode, aVerifiedChain, aHasEVPolicy) { + equal(aPRErrorCode, this.expectedError, + `verifying ${this.certName}: should get error ${this.expectedError}`); + if (this.expectedEVStatus != undefined) { + equal(aHasEVPolicy, this.expectedEVStatus, + `verifying ${this.certName}: ` + + `should ${this.expectedEVStatus ? "be" : "not be"} EV`); + } + this.resolve(); + } +} + // certdb implements nsIX509CertDB. See nsIX509CertDB.idl for documentation. // In particular, hostname is optional. function checkCertErrorGenericAtTime(certdb, cert, expectedError, usage, time, - /* optional */ hasEVPolicy, + /* optional */ isEVExpected, /* optional */ hostname) { - info(`cert cn=${cert.commonName}`); - info(`cert issuer cn=${cert.issuerCommonName}`); - let verifiedChain = {}; - let error = certdb.verifyCertAtTime(cert, usage, NO_FLAGS, hostname, time, - verifiedChain, hasEVPolicy || {}); - Assert.equal(error, expectedError, - "Actual and expected error should match"); + return new Promise((resolve, reject) => { + let result = new CertVerificationExpectedErrorResult( + cert.commonName, expectedError, isEVExpected, resolve); + certdb.asyncVerifyCertAtTime(cert, usage, NO_FLAGS, hostname, time, + result); + }); } // certdb implements nsIX509CertDB. See nsIX509CertDB.idl for documentation. // In particular, hostname is optional. function checkCertErrorGeneric(certdb, cert, expectedError, usage, - /* optional */ hasEVPolicy, - /* optional */ hostname) { - info(`cert cn=${cert.commonName}`); - info(`cert issuer cn=${cert.issuerCommonName}`); - let verifiedChain = {}; - let error = certdb.verifyCertNow(cert, usage, NO_FLAGS, hostname, - verifiedChain, hasEVPolicy || {}); - Assert.equal(error, expectedError, - "Actual and expected error should match"); + /* optional */ isEVExpected, + /* optional */ hostname) { + let now = (new Date()).getTime() / 1000; + return checkCertErrorGenericAtTime(certdb, cert, expectedError, usage, now, + isEVExpected, hostname); } function checkEVStatus(certDB, cert, usage, isEVExpected) { - let hasEVPolicy = {}; - checkCertErrorGeneric(certDB, cert, PRErrorCodeSuccess, usage, hasEVPolicy); - Assert.equal(hasEVPolicy.value, isEVExpected, - "Actual and expected EV status should match"); + return checkCertErrorGeneric(certDB, cert, PRErrorCodeSuccess, usage, + isEVExpected); } function _getLibraryFunctionWithNoArguments(functionName, libraryName, returnType) { // Open the NSS library. copied from services/crypto/modules/WeaveCrypto.js let path = ctypes.libraryName(libraryName); // XXX really want to be able to pass specific dlopen flags here. @@ -668,16 +682,25 @@ function startOCSPResponder(serverPort, Assert.equal(expectedResponseTypes.length, 0, "Should have 0 remaining expected response types"); } httpServer.stop(callback); } }; } +// Given an OCSP responder (see startOCSPResponder), returns a promise that +// resolves when the responder has successfully stopped. +function stopOCSPResponder(responder) { + return new Promise((resolve, reject) => { + responder.stop(resolve); + }); +} + + // A prototype for a fake, error-free sslstatus var FakeSSLStatus = function(certificate) { this.serverCert = certificate; }; FakeSSLStatus.prototype = { serverCert: null, cipherName: null,
--- a/security/manager/ssl/tests/unit/test_add_preexisting_cert.js +++ b/security/manager/ssl/tests/unit/test_add_preexisting_cert.js @@ -20,25 +20,25 @@ function load_cert(cert, trust) { function getDERString(cert) { let derString = ""; for (let rawByte of cert.getRawDER({})) { derString += String.fromCharCode(rawByte); } return derString; } -function run_test() { +add_task(async function() { load_cert("ca", "CTu,CTu,CTu"); let int_cert = load_cert("int-limited-depth", "CTu,CTu,CTu"); let file = "test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem"; let cert_pem = readFile(do_get_file(file)); let ee = certDB.constructX509FromBase64(pemToBase64(cert_pem)); - checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess, - certificateUsageSSLServer); + await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess, + certificateUsageSSLServer); // Change the already existing intermediate certificate's trust using // addCertFromBase64(). notEqual(int_cert, null, "Intermediate cert should be in the cert DB"); let base64_cert = btoa(getDERString(int_cert)); let returnedEE = certDB.addCertFromBase64(base64_cert, "p,p,p"); notEqual(returnedEE, null, "addCertFromBase64 should return a certificate"); - checkCertErrorGeneric(certDB, ee, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageSSLServer); -} + await checkCertErrorGeneric(certDB, ee, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageSSLServer); +});
--- a/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js +++ b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js @@ -26,22 +26,22 @@ function certFromFile(certName) { function loadCertWithTrust(certName, trustString) { addCertFromFile(gCertDB, `test_baseline_requirements/${certName}.pem`, trustString); } function checkCertOn25August2016(cert, expectedResult) { // (new Date("2016-08-25T00:00:00Z")).getTime() / 1000 const VALIDATION_TIME = 1472083200; - checkCertErrorGenericAtTime(gCertDB, cert, expectedResult, - certificateUsageSSLServer, VALIDATION_TIME, {}, - "example.com"); + return checkCertErrorGenericAtTime(gCertDB, cert, expectedResult, + certificateUsageSSLServer, VALIDATION_TIME, + false, "example.com"); } -function run_test() { +add_task(async function() { registerCleanupFunction(() => { Services.prefs.clearUserPref("security.pki.name_matching_mode"); Services.prefs.clearUserPref("security.test.built_in_root_hash"); Services.prefs.clearUserPref("privacy.reduceTimerPrecision"); }); Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); @@ -50,142 +50,142 @@ function run_test() { // When verifying a certificate, if the trust anchor is not a built-in root, // name matching will fall back to using the subject common name if necessary // (i.e. if there is no subject alternative name extension or it does not // contain any dNSName or iPAddress entries). Thus, since imported roots are // not in general treated as built-ins, these should all successfully verify // regardless of the value of the pref. Services.prefs.setIntPref("security.pki.name_matching_mode", 0); info("current mode: always fall back, root not built-in"); - checkCertOn25August2016(certFromFile("no-san-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-older"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), - PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-older"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), + PRErrorCodeSuccess); Services.prefs.setIntPref("security.pki.name_matching_mode", 1); info("current mode: fall back for notBefore < August 23, 2016, root " + "not built-in"); - checkCertOn25August2016(certFromFile("no-san-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-older"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), - PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-older"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), + PRErrorCodeSuccess); Services.prefs.setIntPref("security.pki.name_matching_mode", 2); info("current mode: fall back for notBefore < August 23, 2015, root " + "not built-in"); - checkCertOn25August2016(certFromFile("no-san-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-older"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), - PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-older"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), + PRErrorCodeSuccess); Services.prefs.setIntPref("security.pki.name_matching_mode", 3); info("current mode: never fall back, root not built-in"); - checkCertOn25August2016(certFromFile("no-san-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-older"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), - PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-older"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), + PRErrorCodeSuccess); // In debug builds, we can treat an imported root as a built-in, and thus we // can actually test the different values of the pref. if (isDebugBuild) { let root = certFromFile("ca"); Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint); // Always fall back if necessary. Services.prefs.setIntPref("security.pki.name_matching_mode", 0); info("current mode: always fall back, root built-in"); - checkCertOn25August2016(certFromFile("no-san-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-older"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), - PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-older"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), + PRErrorCodeSuccess); // Only fall back if notBefore < 23 August 2016 Services.prefs.setIntPref("security.pki.name_matching_mode", 1); info("current mode: fall back for notBefore < August 23, 2016, root " + "built-in"); - checkCertOn25August2016(certFromFile("no-san-recent"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("no-san-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("no-san-older"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), - PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-recent"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("no-san-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-older"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), + PRErrorCodeSuccess); // Only fall back if notBefore < 23 August 2015 Services.prefs.setIntPref("security.pki.name_matching_mode", 2); info("current mode: fall back for notBefore < August 23, 2015, root " + "built-in"); - checkCertOn25August2016(certFromFile("no-san-recent"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("no-san-old"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("no-san-older"), - PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), - PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("no-san-recent"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("no-san-old"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("no-san-older"), + PRErrorCodeSuccess); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), + PRErrorCodeSuccess); // Never fall back. Services.prefs.setIntPref("security.pki.name_matching_mode", 3); info("current mode: never fall back, root built-in"); - checkCertOn25August2016(certFromFile("no-san-recent"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("no-san-old"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("no-san-older"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), - SSL_ERROR_BAD_CERT_DOMAIN); - checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), - SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("no-san-recent"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("no-san-old"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("no-san-older"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"), + SSL_ERROR_BAD_CERT_DOMAIN); + await checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"), + SSL_ERROR_BAD_CERT_DOMAIN); } -} +});
--- a/security/manager/ssl/tests/unit/test_certDB_import.js +++ b/security/manager/ssl/tests/unit/test_certDB_import.js @@ -63,27 +63,35 @@ function getCertAsByteArray(certPath) { let byteArray = []; for (let i = 0; i < certBytes.length; i++) { byteArray.push(certBytes.charCodeAt(i)); } return byteArray; } -function findCertByCommonName(commonName) { +function commonFindCertBy(propertyName, value) { let certEnumerator = gCertDB.getCerts().getEnumerator(); while (certEnumerator.hasMoreElements()) { let cert = certEnumerator.getNext().QueryInterface(Ci.nsIX509Cert); - if (cert.commonName == commonName) { + if (cert[propertyName] == value) { return cert; } } return null; } +function findCertByCommonName(commonName) { + return commonFindCertBy("commonName", commonName); +} + +function findCertByEmailAddress(emailAddress) { + return commonFindCertBy("emailAddress", emailAddress); +} + function testImportCACert() { // Sanity check the CA cert is missing. equal(findCertByCommonName(CA_CERT_COMMON_NAME), null, "CA cert should not be in the database before import"); // Import and check for success. let caArray = getCertAsByteArray("test_certDB_import/importedCA.pem"); gCertDB.importCertificates(caArray, caArray.length, Ci.nsIX509Cert.CA_CERT, @@ -102,22 +110,21 @@ function run_test() { let certificateDialogsCID = MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1", gCertificateDialogs); registerCleanupFunction(() => { MockRegistrar.unregister(certificateDialogsCID); }); // Sanity check the e-mail cert is missing. - throws(() => gCertDB.findCertByEmailAddress(TEST_EMAIL_ADDRESS), - /NS_ERROR_FAILURE/, + equal(findCertByEmailAddress(TEST_EMAIL_ADDRESS), null, "E-mail cert should not be in the database before import"); // Import the CA cert so that the e-mail import succeeds. testImportCACert(); // Import the e-mail cert and check for success. let emailArray = getCertAsByteArray("test_certDB_import/emailEE.pem"); gCertDB.importEmailCertificate(emailArray, emailArray.length, gInterfaceRequestor); - notEqual(gCertDB.findCertByEmailAddress(TEST_EMAIL_ADDRESS), null, + notEqual(findCertByEmailAddress(TEST_EMAIL_ADDRESS), null, "E-mail cert should now be found in the database"); }
--- a/security/manager/ssl/tests/unit/test_cert_blocklist.js +++ b/security/manager/ssl/tests/unit/test_cert_blocklist.js @@ -161,28 +161,29 @@ var addonManager = Cc["@mozilla.org/addo addonManager.observe(null, "addons-startup", null); var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] .createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; function verify_cert(file, expectedError) { let ee = constructCertFromFile(file); - checkCertErrorGeneric(certDB, ee, expectedError, certificateUsageSSLServer); + return checkCertErrorGeneric(certDB, ee, expectedError, + certificateUsageSSLServer); } // The certificate blocklist currently only applies to TLS server certificates. -function verify_non_tls_usage_succeeds(file) { +async function verify_non_tls_usage_succeeds(file) { let ee = constructCertFromFile(file); - checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess, - certificateUsageSSLClient); - checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess, - certificateUsageEmailSigner); - checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess, + certificateUsageSSLClient); + await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess, + certificateUsageEmailRecipient); } function load_cert(cert, trust) { let file = "bad_certs/" + cert + ".pem"; addCertFromFile(certDB, file, trust); } function test_is_revoked(certList, issuerString, serialString, subjectString, @@ -304,17 +305,17 @@ function run_test() { { " Rym6o+VN9xgZXT/QLrvN/nv1ZN4=": true}, "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=": { " a0X7/7DlTaedpgrIJg25iBPOkIM=": true}, "YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy": { " YW5vdGhlciBzZXJpYWwu": true, " c2VyaWFsMi4=": true } }; - add_test(function () { + add_task(async function() { // check some existing items in revocations.txt are blocked. Since the // CertBlocklistItems don't know about the data they contain, we can use // arbitrary data (not necessarily DER) to test if items are revoked or not. // This test corresponds to: // issuer: c29tZSBpbWFnaW5hcnkgaXNzdWVy // serial: c2VyaWFsLg== ok(test_is_revoked(certList, "some imaginary issuer", "serial."), "issuer / serial pair should be blocked"); @@ -331,35 +332,33 @@ function run_test() { // (we test this issuer twice to ensure we can read multiple serials) ok(test_is_revoked(certList, "another imaginary issuer", "serial2."), "issuer / serial pair should be blocked"); // Soon we'll load a blocklist which revokes test-int.pem, which issued // test-int-ee.pem. // Check the cert validates before we load the blocklist let file = "test_onecrl/test-int-ee.pem"; - verify_cert(file, PRErrorCodeSuccess); + await verify_cert(file, PRErrorCodeSuccess); // The blocklist also revokes other-test-ca.pem, which issued // other-ca-ee.pem. Check the cert validates before we load the blocklist file = "bad_certs/other-issuer-ee.pem"; - verify_cert(file, PRErrorCodeSuccess); + await verify_cert(file, PRErrorCodeSuccess); // The blocklist will revoke same-issuer-ee.pem via subject / pubKeyHash. // Check the cert validates before we load the blocklist file = "test_onecrl/same-issuer-ee.pem"; - verify_cert(file, PRErrorCodeSuccess); - - run_next_test(); + await verify_cert(file, PRErrorCodeSuccess); }); // blocklist load is async so we must use add_test from here add_task(fetch_blocklist); - add_test(function() { + add_task(async function() { // The blocklist will be loaded now. Let's check the data is sane. // In particular, we should still have the revoked issuer / serial pair // that was in both revocations.txt and the blocklist. ok(test_is_revoked(certList, "another imaginary issuer", "serial2."), "issuer / serial pair should be blocked"); // Check that both serials in the certItem with multiple serials were read // properly @@ -374,48 +373,46 @@ function run_test() { "issuer / serial pair should be blocked"); // Check the blocklist entry has been persisted properly to the backing // file check_revocations_txt_contents(expected); // Check the blocklisted intermediate now causes a failure let file = "test_onecrl/test-int-ee.pem"; - verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE); - verify_non_tls_usage_succeeds(file); + await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE); + await verify_non_tls_usage_succeeds(file); // Check the ee with the blocklisted root also causes a failure file = "bad_certs/other-issuer-ee.pem"; - verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE); - verify_non_tls_usage_succeeds(file); + await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE); + await verify_non_tls_usage_succeeds(file); // Check the ee blocked by subject / pubKey causes a failure file = "test_onecrl/same-issuer-ee.pem"; - verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE); - verify_non_tls_usage_succeeds(file); + await verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE); + await verify_non_tls_usage_succeeds(file); // Check a non-blocklisted chain still validates OK file = "bad_certs/default-ee.pem"; - verify_cert(file, PRErrorCodeSuccess); + await verify_cert(file, PRErrorCodeSuccess); // Check a bad cert is still bad (unknown issuer) file = "bad_certs/unknownissuer.pem"; - verify_cert(file, SEC_ERROR_UNKNOWN_ISSUER); + await verify_cert(file, SEC_ERROR_UNKNOWN_ISSUER); // check that save with no further update is a no-op let lastModified = gRevocations.lastModifiedTime; // add an already existing entry certList.revokeCertByIssuerAndSerial("YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy", "c2VyaWFsMi4="); certList.saveEntries(); let newModified = gRevocations.lastModifiedTime; equal(lastModified, newModified, "saveEntries with no modifications should not update the backing file"); - - run_next_test(); }); add_test(function() { // Check the blocklist entry has not changed check_revocations_txt_contents(expected); run_next_test(); });
--- a/security/manager/ssl/tests/unit/test_cert_eku.js +++ b/security/manager/ssl/tests/unit/test_cert_eku.js @@ -18,120 +18,122 @@ function certFromFile(certName) { return constructCertFromFile(`test_cert_eku/${certName}.pem`); } function loadCertWithTrust(certName, trustString) { addCertFromFile(certdb, `test_cert_eku/${certName}.pem`, trustString); } function checkEndEntity(cert, expectedResult) { - checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLServer); + return checkCertErrorGeneric(certdb, cert, expectedResult, + certificateUsageSSLServer); } function checkCertOn25August2016(cert, expectedResult) { // (new Date("2016-08-25T00:00:00Z")).getTime() / 1000 const VALIDATION_TIME = 1472083200; - checkCertErrorGenericAtTime(certdb, cert, expectedResult, - certificateUsageSSLServer, VALIDATION_TIME); + return checkCertErrorGenericAtTime(certdb, cert, expectedResult, + certificateUsageSSLServer, + VALIDATION_TIME); } -function run_test() { +add_task(async function() { registerCleanupFunction(() => { Services.prefs.clearUserPref("privacy.reduceTimerPrecision"); }); Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); loadCertWithTrust("ca", "CTu,,"); // end-entity has id-kp-serverAuth => success - checkEndEntity(certFromFile("ee-SA"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-SA"), PRErrorCodeSuccess); // end-entity has id-kp-serverAuth => success - checkEndEntity(certFromFile("ee-SA-CA"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-SA-CA"), PRErrorCodeSuccess); // end-entity has extended key usage, but id-kp-serverAuth is not present => // failure - checkEndEntity(certFromFile("ee-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE); + await checkEndEntity(certFromFile("ee-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE); // end-entity has id-kp-serverAuth => success - checkEndEntity(certFromFile("ee-SA-nsSGC"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-SA-nsSGC"), PRErrorCodeSuccess); // end-entity has extended key usage, but id-kp-serverAuth is not present => // failure (in particular, Netscape Server Gated Crypto (also known as // Netscape Step Up) is not an acceptable substitute for end-entity // certificates). // Verify this for all Netscape Step Up policy configurations. // 0 = "always accept nsSGC in place of serverAuth for CA certificates" Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 0); - checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE); + await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE); // 1 = "accept nsSGC before 23 August 2016" Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 1); - checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE); + await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE); // 2 = "accept nsSGC before 23 August 2015" Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 2); - checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE); + await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE); // 3 = "never accept nsSGC" Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 3); - checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE); + await checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE); // end-entity has id-kp-OCSPSigning, which is not acceptable for end-entity // certificates being verified as TLS server certificates => failure - checkEndEntity(certFromFile("ee-SA-OCSP"), SEC_ERROR_INADEQUATE_CERT_TYPE); + await checkEndEntity(certFromFile("ee-SA-OCSP"), SEC_ERROR_INADEQUATE_CERT_TYPE); // intermediate has id-kp-serverAuth => success loadCertWithTrust("int-SA", ",,"); - checkEndEntity(certFromFile("ee-int-SA"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-int-SA"), PRErrorCodeSuccess); // intermediate has id-kp-serverAuth => success loadCertWithTrust("int-SA-CA", ",,"); - checkEndEntity(certFromFile("ee-int-SA-CA"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-int-SA-CA"), PRErrorCodeSuccess); // intermediate has extended key usage, but id-kp-serverAuth is not present // => failure loadCertWithTrust("int-CA", ",,"); - checkEndEntity(certFromFile("ee-int-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE); + await checkEndEntity(certFromFile("ee-int-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE); // intermediate has id-kp-serverAuth => success loadCertWithTrust("int-SA-nsSGC", ",,"); - checkEndEntity(certFromFile("ee-int-SA-nsSGC"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-int-SA-nsSGC"), PRErrorCodeSuccess); // Intermediate has Netscape Server Gated Crypto. Success will depend on the // Netscape Step Up policy configuration and the notBefore property of the // intermediate. loadCertWithTrust("int-nsSGC-recent", ",,"); loadCertWithTrust("int-nsSGC-old", ",,"); loadCertWithTrust("int-nsSGC-older", ",,"); // 0 = "always accept nsSGC in place of serverAuth for CA certificates" Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 0); info("Netscape Step Up policy: always accept"); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"), PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"), PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"), PRErrorCodeSuccess); // 1 = "accept nsSGC before 23 August 2016" info("Netscape Step Up policy: accept before 23 August 2016"); Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 1); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"), SEC_ERROR_INADEQUATE_CERT_TYPE); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"), PRErrorCodeSuccess); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"), PRErrorCodeSuccess); // 2 = "accept nsSGC before 23 August 2015" info("Netscape Step Up policy: accept before 23 August 2015"); Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 2); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"), SEC_ERROR_INADEQUATE_CERT_TYPE); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"), SEC_ERROR_INADEQUATE_CERT_TYPE); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"), PRErrorCodeSuccess); // 3 = "never accept nsSGC" info("Netscape Step Up policy: never accept"); Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 3); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"), SEC_ERROR_INADEQUATE_CERT_TYPE); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"), SEC_ERROR_INADEQUATE_CERT_TYPE); - checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"), + await checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"), SEC_ERROR_INADEQUATE_CERT_TYPE); // intermediate has id-kp-OCSPSigning, which is acceptable for CA // certificates => success loadCertWithTrust("int-SA-OCSP", ",,"); - checkEndEntity(certFromFile("ee-int-SA-OCSP"), PRErrorCodeSuccess); -} + await checkEndEntity(certFromFile("ee-int-SA-OCSP"), PRErrorCodeSuccess); +});
--- a/security/manager/ssl/tests/unit/test_cert_embedded_null.js +++ b/security/manager/ssl/tests/unit/test_cert_embedded_null.js @@ -9,30 +9,32 @@ // Includes a similar test case but for the subject alternative name extension. "use strict"; do_get_profile(); // must be called before getting nsIX509CertDB const certdb = Cc["@mozilla.org/security/x509certdb;1"] .getService(Ci.nsIX509CertDB); -function do_testcase(certname, checkCommonName) { +async function do_testcase(certname, checkCommonName) { let cert = constructCertFromFile(`test_cert_embedded_null/${certname}.pem`); // Where applicable, check that the testcase is meaningful (i.e. that the // certificate's subject common name has an embedded NUL in it). if (checkCommonName) { equal(cert.commonName, "www.bank1.com\\00www.bad-guy.com", "certificate subject common name should have an embedded NUL byte"); } - checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN, - certificateUsageSSLServer, {}, "www.bank1.com"); - checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN, - certificateUsageSSLServer, {}, "www.bad-guy.com"); + await checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN, + certificateUsageSSLServer, undefined, + "www.bank1.com"); + await checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN, + certificateUsageSSLServer, undefined, + "www.bad-guy.com"); } -function run_test() { +add_task(async function() { addCertFromFile(certdb, "test_cert_embedded_null/ca.pem", "CTu,,"); - do_testcase("embeddedNull", true); - do_testcase("embeddedNullSAN", false); - do_testcase("embeddedNullCNAndSAN", true); - do_testcase("embeddedNullSAN2", false); -} + await do_testcase("embeddedNull", true); + await do_testcase("embeddedNullSAN", false); + await do_testcase("embeddedNullCNAndSAN", true); + await do_testcase("embeddedNullSAN2", false); +});
--- a/security/manager/ssl/tests/unit/test_cert_sha1.js +++ b/security/manager/ssl/tests/unit/test_cert_sha1.js @@ -22,21 +22,22 @@ function certFromFile(certName) { return constructCertFromFile("test_cert_sha1/" + certName + ".pem"); } function loadCertWithTrust(certName, trustString) { addCertFromFile(certdb, "test_cert_sha1/" + certName + ".pem", trustString); } function checkEndEntity(cert, expectedResult) { - checkCertErrorGenericAtTime(certdb, cert, expectedResult, - certificateUsageSSLServer, VALIDATION_TIME); + return checkCertErrorGenericAtTime(certdb, cert, expectedResult, + certificateUsageSSLServer, + VALIDATION_TIME); } -function run_test() { +add_task(async function() { loadCertWithTrust("ca", "CTu,,"); loadCertWithTrust("int-pre", ",,"); loadCertWithTrust("int-post", ",,"); // Test cases per pref setting // // root intermed. end entity // =========================== @@ -82,61 +83,61 @@ function run_test() { // verifier does not take into account the currently configured SHA-1 policy. // This is in part due to implementation complexity and because this isn't // actually how TLS web server certificates are verified in the TLS handshake // (which makes a full implementation that supports heeding the SHA-1 policy // unnecessary). // SHA-1 allowed Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 0); - checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess); // SHA-1 forbidden Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 1); - checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); - checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); - checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); // SHA-1 forbidden (test the case where the pref has been set to 2) Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 2); - checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); - checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); - checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); // SHA-1 allowed only when issued by an imported root. First test with the // test root considered a built-in (on debug only - this functionality is // disabled on non-debug builds). Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 3); if (isDebugBuild) { let root = certFromFile("ca"); Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint); - checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); - checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); - checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); Services.prefs.clearUserPref("security.test.built_in_root_hash"); } // SHA-1 still allowed only when issued by an imported root. // Now test with the test root considered a non-built-in. - checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess); // SHA-1 allowed before 2016 or when issued by an imported root. First test // with the test root considered a built-in. Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4); if (isDebugBuild) { let root = certFromFile("ca"); Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint); - checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); - checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); + await checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED); Services.prefs.clearUserPref("security.test.built_in_root_hash"); } // SHA-1 still only allowed before 2016 or when issued by an imported root. // Now test with the test root considered a non-built-in. - checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess); -} + await checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess); +});
--- a/security/manager/ssl/tests/unit/test_cert_signatures.js +++ b/security/manager/ssl/tests/unit/test_cert_signatures.js @@ -39,25 +39,25 @@ function readAndTamperWithNthByte(certif const BYTE_IN_SIGNATURE = -8; function addSignatureTamperedCertificate(certificatePath) { let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE); certdb.addCertFromBase64(base64, ",,"); } function ensureSignatureVerificationFailure(certificatePath) { let cert = constructCertFromFile(certificatePath); - checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE, - certificateUsageSSLServer); + return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE, + certificateUsageSSLServer); } function tamperWithSignatureAndEnsureVerificationFailure(certificatePath) { let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE); let cert = certdb.constructX509FromBase64(base64); - checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE, - certificateUsageSSLServer); + return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE, + certificateUsageSSLServer); } // The beginning of a certificate looks like this (in hex, using DER): // 30 XX XX XX [the XX encode length - there are probably 3 bytes here] // 30 XX XX XX [length again] // A0 03 // 02 01 // 02 @@ -76,46 +76,46 @@ function addSerialNumberTamperedCertific BYTE_IN_SERIAL_NUMBER); certdb.addCertFromBase64(base64, ",,"); } function tamperWithSerialNumberAndEnsureVerificationFailure(certificatePath) { let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SERIAL_NUMBER); let cert = certdb.constructX509FromBase64(base64); - checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE, - certificateUsageSSLServer); + return checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE, + certificateUsageSSLServer); } -function run_test() { +add_task(async function() { addCertFromFile(certdb, "test_cert_signatures/ca-rsa.pem", "CTu,,"); addCertFromFile(certdb, "test_cert_signatures/ca-secp384r1.pem", "CTu,,"); // Tamper with the signatures on intermediate certificates and ensure that // end-entity certificates issued by those intermediates do not validate // successfully. addSignatureTamperedCertificate("test_cert_signatures/int-rsa.pem"); addSignatureTamperedCertificate("test_cert_signatures/int-secp384r1.pem"); - ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem"); - ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem"); + await ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem"); + await ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem"); // Tamper with the signatures on end-entity certificates and ensure that they // do not validate successfully. - tamperWithSignatureAndEnsureVerificationFailure( + await tamperWithSignatureAndEnsureVerificationFailure( "test_cert_signatures/ee-rsa-direct.pem"); - tamperWithSignatureAndEnsureVerificationFailure( + await tamperWithSignatureAndEnsureVerificationFailure( "test_cert_signatures/ee-secp384r1-direct.pem"); // Tamper with the serial numbers of intermediate certificates and ensure // that end-entity certificates issued by those intermediates do not validate // successfully. addSerialNumberTamperedCertificate("test_cert_signatures/int-rsa.pem"); addSerialNumberTamperedCertificate("test_cert_signatures/int-secp384r1.pem"); - ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem"); - ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem"); + await ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem"); + await ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem"); // Tamper with the serial numbers of end-entity certificates and ensure that // they do not validate successfully. - tamperWithSerialNumberAndEnsureVerificationFailure( + await tamperWithSerialNumberAndEnsureVerificationFailure( "test_cert_signatures/ee-rsa-direct.pem"); - tamperWithSerialNumberAndEnsureVerificationFailure( + await tamperWithSerialNumberAndEnsureVerificationFailure( "test_cert_signatures/ee-secp384r1-direct.pem"); -} +});
--- a/security/manager/ssl/tests/unit/test_cert_trust.js +++ b/security/manager/ssl/tests/unit/test_cert_trust.js @@ -18,129 +18,129 @@ function load_cert(cert_name, trust_stri function setup_basic_trusts(ca_cert, int_cert) { certdb.setCertTrust(ca_cert, Ci.nsIX509Cert.CA_CERT, Ci.nsIX509CertDB.TRUSTED_SSL | Ci.nsIX509CertDB.TRUSTED_EMAIL); certdb.setCertTrust(int_cert, Ci.nsIX509Cert.CA_CERT, 0); } -function test_ca_distrust(ee_cert, cert_to_modify_trust, isRootCA) { +async function test_ca_distrust(ee_cert, cert_to_modify_trust, isRootCA) { // On reset most usages are successful - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageSSLServer); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, - certificateUsageSSLCA); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, + certificateUsageSSLCA); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailRecipient); // Test of active distrust. No usage should pass. setCertTrust(cert_to_modify_trust, "p,p,p"); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageSSLServer); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, - certificateUsageSSLCA); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, + certificateUsageSSLCA); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageEmailRecipient); // Trust set to T - trusted CA to issue client certs, where client cert is // usageSSLClient. setCertTrust(cert_to_modify_trust, "T,T,T"); - checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER - : PRErrorCodeSuccess, - certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER + : PRErrorCodeSuccess, + certificateUsageSSLServer); // XXX(Bug 982340) - checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER - : PRErrorCodeSuccess, - certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER + : PRErrorCodeSuccess, + certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, - certificateUsageSSLCA); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, + certificateUsageSSLCA); - checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER - : PRErrorCodeSuccess, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER - : PRErrorCodeSuccess, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER + : PRErrorCodeSuccess, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER + : PRErrorCodeSuccess, + certificateUsageEmailRecipient); // Now tests on the SSL trust bit setCertTrust(cert_to_modify_trust, "p,C,C"); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageSSLServer); // XXX(Bug 982340) - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, - certificateUsageSSLCA); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, + certificateUsageSSLCA); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailRecipient); // Inherited trust SSL setCertTrust(cert_to_modify_trust, ",C,C"); - checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER - : PRErrorCodeSuccess, - certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER + : PRErrorCodeSuccess, + certificateUsageSSLServer); // XXX(Bug 982340) - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, - certificateUsageSSLCA); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, + certificateUsageSSLCA); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailRecipient); // Now tests on the EMAIL trust bit setCertTrust(cert_to_modify_trust, "C,p,C"); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageSSLServer); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, - certificateUsageSSLCA); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, + certificateUsageSSLCA); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER, + certificateUsageEmailRecipient); // inherited EMAIL Trust setCertTrust(cert_to_modify_trust, "C,,C"); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageSSLServer); - checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER - : PRErrorCodeSuccess, - certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, - certificateUsageSSLCA); - checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER - : PRErrorCodeSuccess, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER - : PRErrorCodeSuccess, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER + : PRErrorCodeSuccess, + certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID, + certificateUsageSSLCA); + await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER + : PRErrorCodeSuccess, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER + : PRErrorCodeSuccess, + certificateUsageEmailRecipient); } -function run_test() { +add_task(async function() { let certList = [ "ca", "int", "ee", ]; let loadedCerts = []; for (let certName of certList) { loadedCerts.push(load_cert(certName, ",,")); @@ -149,41 +149,41 @@ function run_test() { let ca_cert = loadedCerts[0]; notEqual(ca_cert, null, "CA cert should have successfully loaded"); let int_cert = loadedCerts[1]; notEqual(int_cert, null, "Intermediate cert should have successfully loaded"); let ee_cert = loadedCerts[2]; notEqual(ee_cert, null, "EE cert should have successfully loaded"); setup_basic_trusts(ca_cert, int_cert); - test_ca_distrust(ee_cert, ca_cert, true); + await test_ca_distrust(ee_cert, ca_cert, true); setup_basic_trusts(ca_cert, int_cert); - test_ca_distrust(ee_cert, int_cert, false); + await test_ca_distrust(ee_cert, int_cert, false); // Reset trust to default ("inherit trust") setCertTrust(ca_cert, ",,"); setCertTrust(int_cert, ",,"); // If an end-entity certificate is manually trusted, it may not be the root of // its own verified chain. In general this will cause "unknown issuer" errors // unless a CA trust anchor can be found. setCertTrust(ee_cert, "CTu,CTu,CTu"); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, - certificateUsageSSLServer); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, - certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, - certificateUsageEmailRecipient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNKNOWN_ISSUER, + certificateUsageEmailRecipient); // Now make a CA trust anchor available. setCertTrust(ca_cert, "CTu,CTu,CTu"); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageSSLServer); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageSSLClient); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageEmailSigner); - checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, - certificateUsageEmailRecipient); -} + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLServer); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageSSLClient); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailSigner); + await checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess, + certificateUsageEmailRecipient); +});
--- a/security/manager/ssl/tests/unit/test_cert_version.js +++ b/security/manager/ssl/tests/unit/test_cert_version.js @@ -37,154 +37,156 @@ function certFromFile(certName) { return constructCertFromFile("test_cert_version/" + certName + ".pem"); } function loadCertWithTrust(certName, trustString) { addCertFromFile(certdb, "test_cert_version/" + certName + ".pem", trustString); } function checkEndEntity(cert, expectedResult) { - checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLServer); + return checkCertErrorGeneric(certdb, cert, expectedResult, + certificateUsageSSLServer); } function checkIntermediate(cert, expectedResult) { - checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLCA); + return checkCertErrorGeneric(certdb, cert, expectedResult, + certificateUsageSSLCA); } // Test that the code that decodes certificates to display them in the // certificate manager correctly handles the version field. function checkCertVersion(cert, expectedVersionString) { let asn1 = cert.ASN1Structure.QueryInterface(Ci.nsIASN1Sequence); let tbsCertificate = asn1.ASN1Objects.queryElementAt(0, Ci.nsIASN1Sequence); let version = tbsCertificate.ASN1Objects.queryElementAt(0, Ci.nsIASN1Object); equal(version.displayValue, expectedVersionString, "Actual and expected version strings should match"); } -function run_test() { +add_task(async function() { loadCertWithTrust("ca", "CTu,,"); // Section for CAs lacking the basicConstraints extension entirely: loadCertWithTrust("int-v1-noBC_ca", ",,"); - checkIntermediate(certFromFile("int-v1-noBC_ca"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA); - checkEndEntity(certFromFile("ee_int-v1-noBC"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA); + await checkIntermediate(certFromFile("int-v1-noBC_ca"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA); + await checkEndEntity(certFromFile("ee_int-v1-noBC"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA); // A v1 certificate with no basicConstraints extension may issue certificates // if it is a trust anchor. loadCertWithTrust("int-v1-noBC_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v1-noBC_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v1-noBC"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v1-noBC_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v1-noBC"), PRErrorCodeSuccess); loadCertWithTrust("int-v2-noBC_ca", ",,"); - checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v2-noBC_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v3-noBC_ca", ",,"); - checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v3-noBC_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v4-noBC_ca", ",,"); - checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v4-noBC_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID); // Section for CAs with basicConstraints not specifying cA: loadCertWithTrust("int-v1-BC-not-cA_ca", ",,"); - checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v1-BC-not-cA_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v2-BC-not-cA_ca", ",,"); - checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v2-BC-not-cA_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v3-BC-not-cA_ca", ",,"); - checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v3-BC-not-cA_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v4-BC-not-cA_ca", ",,"); - checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); loadCertWithTrust("int-v4-BC-not-cA_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); - checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); + await checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID); + await checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID); // Section for CAs with basicConstraints specifying cA: loadCertWithTrust("int-v1-BC-cA_ca", ",,"); - checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess); loadCertWithTrust("int-v1-BC-cA_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess); loadCertWithTrust("int-v2-BC-cA_ca", ",,"); - checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess); loadCertWithTrust("int-v2-BC-cA_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess); loadCertWithTrust("int-v3-BC-cA_ca", ",,"); - checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess); loadCertWithTrust("int-v3-BC-cA_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess); loadCertWithTrust("int-v4-BC-cA_ca", ",,"); - checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess); loadCertWithTrust("int-v4-BC-cA_ca", "CTu,,"); - checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess); + await checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess); // Section for end-entity certificates with various basicConstraints: - checkEndEntity(certFromFile("ee-v1-noBC_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-v2-noBC_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-v3-noBC_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-v4-noBC_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-v1-noBC_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-v2-noBC_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-v3-noBC_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-v4-noBC_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-v1-BC-not-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-v2-BC-not-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-v3-BC-not-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-v4-BC-not-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-v1-BC-not-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-v2-BC-not-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-v3-BC-not-cA_ca"), PRErrorCodeSuccess); + await checkEndEntity(certFromFile("ee-v4-BC-not-cA_ca"), PRErrorCodeSuccess); - checkEndEntity(certFromFile("ee-v1-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY); - checkEndEntity(certFromFile("ee-v2-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY); - checkEndEntity(certFromFile("ee-v3-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY); - checkEndEntity(certFromFile("ee-v4-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY); + await checkEndEntity(certFromFile("ee-v1-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY); + await checkEndEntity(certFromFile("ee-v2-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY); + await checkEndEntity(certFromFile("ee-v3-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY); + await checkEndEntity(certFromFile("ee-v4-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY); // Section for self-signed certificates: - checkEndEntity(certFromFile("ss-v1-noBC"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v2-noBC"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v3-noBC"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v4-noBC"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v1-noBC"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v2-noBC"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v3-noBC"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v4-noBC"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v1-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v2-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v3-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v4-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v1-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v2-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v3-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v4-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v1-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v2-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v3-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER); - checkEndEntity(certFromFile("ss-v4-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v1-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v2-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v3-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER); + await checkEndEntity(certFromFile("ss-v4-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER); checkCertVersion(certFromFile("ss-v1-noBC"), "Version 1"); checkCertVersion(certFromFile("int-v2-BC-cA_ca"), "Version 2"); checkCertVersion(certFromFile("ee-v3-BC-not-cA_ca"), "Version 3"); checkCertVersion(certFromFile("int-v4-BC-not-cA_ca"), "Version 4"); -} +});
--- a/security/manager/ssl/tests/unit/test_keysize.js +++ b/security/manager/ssl/tests/unit/test_keysize.js @@ -19,109 +19,109 @@ const certdb = Cc["@mozilla.org/security * The key type of the root certificate, or the name of an elliptic * curve, as output by the 'openssl ecparam -list_curves' command. * @param {Number} rootKeySize * @param {String} intKeyType * @param {Number} intKeySize * @param {String} eeKeyType * @param {Number} eeKeySize * @param {PRErrorCode} eeExpectedError + * @return {Promise} a promise that will resolve when the verification has + * completed */ function checkChain(rootKeyType, rootKeySize, intKeyType, intKeySize, eeKeyType, eeKeySize, eeExpectedError) { let rootName = "root_" + rootKeyType + "_" + rootKeySize; let intName = "int_" + intKeyType + "_" + intKeySize; let eeName = "ee_" + eeKeyType + "_" + eeKeySize; let intFullName = intName + "-" + rootName; let eeFullName = eeName + "-" + intName + "-" + rootName; addCertFromFile(certdb, `test_keysize/${rootName}.pem`, "CTu,CTu,CTu"); addCertFromFile(certdb, `test_keysize/${intFullName}.pem`, ",,"); let eeCert = constructCertFromFile(`test_keysize/${eeFullName}.pem`); info("cert o=" + eeCert.organization); info("cert issuer o=" + eeCert.issuerOrganization); - checkCertErrorGeneric(certdb, eeCert, eeExpectedError, - certificateUsageSSLServer); + return checkCertErrorGeneric(certdb, eeCert, eeExpectedError, + certificateUsageSSLServer); } /** * Tests various RSA chains. * * @param {Number} inadequateKeySize * @param {Number} adequateKeySize */ -function checkRSAChains(inadequateKeySize, adequateKeySize) { +async function checkRSAChains(inadequateKeySize, adequateKeySize) { // Chain with certs that have adequate sizes for DV - checkChain("rsa", adequateKeySize, - "rsa", adequateKeySize, - "rsa", adequateKeySize, - PRErrorCodeSuccess); + await checkChain("rsa", adequateKeySize, + "rsa", adequateKeySize, + "rsa", adequateKeySize, + PRErrorCodeSuccess); // Chain with a root cert that has an inadequate size for DV - checkChain("rsa", inadequateKeySize, - "rsa", adequateKeySize, - "rsa", adequateKeySize, - MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE); + await checkChain("rsa", inadequateKeySize, + "rsa", adequateKeySize, + "rsa", adequateKeySize, + MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE); // Chain with an intermediate cert that has an inadequate size for DV - checkChain("rsa", adequateKeySize, - "rsa", inadequateKeySize, - "rsa", adequateKeySize, - MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE); + await checkChain("rsa", adequateKeySize, + "rsa", inadequateKeySize, + "rsa", adequateKeySize, + MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE); // Chain with an end entity cert that has an inadequate size for DV - checkChain("rsa", adequateKeySize, - "rsa", adequateKeySize, - "rsa", inadequateKeySize, - MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE); + await checkChain("rsa", adequateKeySize, + "rsa", adequateKeySize, + "rsa", inadequateKeySize, + MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE); } -function checkECCChains() { - checkChain("secp256r1", 256, - "secp384r1", 384, - "secp521r1", 521, - PRErrorCodeSuccess); - checkChain("secp256r1", 256, - "secp224r1", 224, - "secp256r1", 256, - SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - checkChain("secp256r1", 256, - "secp256r1", 256, - "secp224r1", 224, - SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - checkChain("secp224r1", 224, - "secp256r1", 256, - "secp256r1", 256, - SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - checkChain("secp256r1", 256, - "secp256r1", 256, - "secp256k1", 256, - SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - checkChain("secp256k1", 256, - "secp256r1", 256, - "secp256r1", 256, - SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); +async function checkECCChains() { + await checkChain("secp256r1", 256, + "secp384r1", 384, + "secp521r1", 521, + PRErrorCodeSuccess); + await checkChain("secp256r1", 256, + "secp224r1", 224, + "secp256r1", 256, + SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + await checkChain("secp256r1", 256, + "secp256r1", 256, + "secp224r1", 224, + SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + await checkChain("secp224r1", 224, + "secp256r1", 256, + "secp256r1", 256, + SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + await checkChain("secp256r1", 256, + "secp256r1", 256, + "secp256k1", 256, + SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + await checkChain("secp256k1", 256, + "secp256r1", 256, + "secp256r1", 256, + SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); } -function checkCombinationChains() { - checkChain("rsa", 2048, - "secp256r1", 256, - "secp384r1", 384, - PRErrorCodeSuccess); - checkChain("rsa", 2048, - "secp256r1", 256, - "secp224r1", 224, - SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - checkChain("secp256r1", 256, - "rsa", 1016, - "secp256r1", 256, - MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE); +async function checkCombinationChains() { + await checkChain("rsa", 2048, + "secp256r1", 256, + "secp384r1", 384, + PRErrorCodeSuccess); + await checkChain("rsa", 2048, + "secp256r1", 256, + "secp224r1", 224, + SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + await checkChain("secp256r1", 256, + "rsa", 1016, + "secp256r1", 256, + MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE); } -function run_test() { - checkRSAChains(1016, 1024); - checkECCChains(); - checkCombinationChains(); - - run_next_test(); -} +add_task(async function() { + await checkRSAChains(1016, 1024); + await checkECCChains(); + await checkCombinationChains(); +});
--- a/security/manager/ssl/tests/unit/test_keysize_ev.js +++ b/security/manager/ssl/tests/unit/test_keysize_ev.js @@ -20,49 +20,47 @@ function getOCSPResponder(expectedCertNa function loadCert(certName, trustString) { let certFilename = "test_keysize_ev/" + certName + ".pem"; addCertFromFile(certDB, certFilename, trustString); return constructCertFromFile(certFilename); } /** - * Adds a single EV key size test. + * Asynchronously runs a single EV key size test. * * @param {Array} expectedNamesForOCSP * An array of nicknames of the certs to be responded to. * @param {String} rootCertFileName * The file name of the root cert. Can begin with ".." to reference * certs in folders other than "test_keysize_ev/". * @param {Array} intCertFileNames * An array of file names of any intermediate certificates. * @param {String} endEntityCertFileName * The file name of the end entity cert. * @param {Boolean} expectedResult * Whether the chain is expected to validate as EV. */ -function addKeySizeTestForEV(expectedNamesForOCSP, - rootCertFileName, intCertFileNames, - endEntityCertFileName, expectedResult) { - add_test(function() { - clearOCSPCache(); - let ocspResponder = getOCSPResponder(expectedNamesForOCSP); +async function keySizeTestForEV(expectedNamesForOCSP, + rootCertFileName, intCertFileNames, + endEntityCertFileName, expectedResult) { + clearOCSPCache(); + let ocspResponder = getOCSPResponder(expectedNamesForOCSP); - loadCert(rootCertFileName, "CTu,CTu,CTu"); - for (let intCertFileName of intCertFileNames) { - loadCert(intCertFileName, ",,"); - } - checkEVStatus( - certDB, - constructCertFromFile(`test_keysize_ev/${endEntityCertFileName}.pem`), - certificateUsageSSLServer, - expectedResult); + loadCert(rootCertFileName, "CTu,CTu,CTu"); + for (let intCertFileName of intCertFileNames) { + loadCert(intCertFileName, ",,"); + } + await checkEVStatus( + certDB, + constructCertFromFile(`test_keysize_ev/${endEntityCertFileName}.pem`), + certificateUsageSSLServer, + expectedResult); - ocspResponder.stop(run_next_test); - }); + await stopOCSPResponder(ocspResponder); } /** * For debug builds which have the test EV roots compiled in, checks RSA chains * which contain certs with key sizes adequate for EV are validated as such, * while chains that contain any cert with an inadequate key size fail EV and * validate as DV. * For opt builds which don't have the test EV roots compiled in, checks that @@ -71,17 +69,17 @@ function addKeySizeTestForEV(expectedNam * Note: This function assumes that the key size requirements for EV are greater * than the requirements for DV. * * @param {Number} inadequateKeySize * The inadequate key size of the generated certs. * @param {Number} adequateKeySize * The adequate key size of the generated certs. */ -function checkRSAChains(inadequateKeySize, adequateKeySize) { +async function checkRSAChains(inadequateKeySize, adequateKeySize) { // Reuse the existing test RSA EV root let rootOKCertFileName = "../test_ev_certs/evroot"; let rootOKName = "evroot"; let rootNotOKName = "ev_root_rsa_" + inadequateKeySize; let intOKName = "ev_int_rsa_" + adequateKeySize; let intNotOKName = "ev_int_rsa_" + inadequateKeySize; let eeOKName = "ev_ee_rsa_" + adequateKeySize; let eeNotOKName = "ev_ee_rsa_" + inadequateKeySize; @@ -91,55 +89,53 @@ function checkRSAChains(inadequateKeySiz // will for example not be done for the "ev_int_rsa_2048-evroot" intermediate // in such a build. let intFullName = intOKName + "-" + rootOKName; let eeFullName = eeOKName + "-" + intOKName + "-" + rootOKName; let expectedNamesForOCSP = gEVExpected ? [ intFullName, eeFullName ] : [ eeFullName ]; - addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName, - [ intFullName ], eeFullName, gEVExpected); + await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName, + [ intFullName ], eeFullName, gEVExpected); // Chain with a root cert that has an inadequate size for EV, but // adequate size for DV intFullName = intOKName + "-" + rootNotOKName; eeFullName = eeOKName + "-" + intOKName + "-" + rootNotOKName; expectedNamesForOCSP = [ eeFullName ]; - addKeySizeTestForEV(expectedNamesForOCSP, rootNotOKName, - [ intFullName ], eeFullName, false); + await keySizeTestForEV(expectedNamesForOCSP, rootNotOKName, + [ intFullName ], eeFullName, false); // Chain with an intermediate cert that has an inadequate size for EV, but // adequate size for DV intFullName = intNotOKName + "-" + rootOKName; eeFullName = eeOKName + "-" + intNotOKName + "-" + rootOKName; expectedNamesForOCSP = [ eeFullName ]; - addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName, - [ intFullName ], eeFullName, false); + await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName, + [ intFullName ], eeFullName, false); // Chain with an end entity cert that has an inadequate size for EV, but // adequate size for DV intFullName = intOKName + "-" + rootOKName; eeFullName = eeNotOKName + "-" + intOKName + "-" + rootOKName; expectedNamesForOCSP = gEVExpected ? [ intFullName, eeFullName ] : [ eeFullName ]; - addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName, - [ intFullName ], eeFullName, false); + await keySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName, + [ intFullName ], eeFullName, false); } -function run_test() { +add_task(async function() { Services.prefs.setCharPref("network.dns.localDomains", "www.example.com"); Services.prefs.setIntPref("security.OCSP.enabled", 1); let smallKeyEVRoot = constructCertFromFile("test_keysize_ev/ev_root_rsa_2040.pem"); equal(smallKeyEVRoot.sha256Fingerprint, "40:AB:5D:A5:89:15:A9:4B:82:87:B8:A6:9A:84:B1:DB:" + "7A:9D:DB:B8:4E:E1:23:E3:C6:64:E7:50:DC:35:8C:68", "test sanity check: the small-key EV root must have the same " + "fingerprint as the corresponding entry in ExtendedValidation.cpp"); - checkRSAChains(2040, 2048); - - run_next_test(); -} + await checkRSAChains(2040, 2048); +});
--- a/security/manager/ssl/tests/unit/test_name_constraints.js +++ b/security/manager/ssl/tests/unit/test_name_constraints.js @@ -33,31 +33,31 @@ function certFromFile(name) { } function loadCertWithTrust(certName, trustString) { addCertFromFile(certdb, `test_name_constraints/${certName}.pem`, trustString); } function checkCertNotInNameSpace(cert) { - checkCertErrorGeneric(certdb, cert, SEC_ERROR_CERT_NOT_IN_NAME_SPACE, - certificateUsageSSLServer); + return checkCertErrorGeneric(certdb, cert, SEC_ERROR_CERT_NOT_IN_NAME_SPACE, + certificateUsageSSLServer); } function checkCertInNameSpace(cert) { - checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess, - certificateUsageSSLServer); + return checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess, + certificateUsageSSLServer); } -function run_test() { +add_task(async function() { // Test that name constraints from the entire certificate chain are enforced. loadCertWithTrust("ca-example-com-permitted", "CTu,,"); loadCertWithTrust("int-example-org-permitted", ",,"); - checkCertNotInNameSpace(certFromFile("ee-example-com-and-org")); - checkCertNotInNameSpace(certFromFile("ee-example-com")); - checkCertNotInNameSpace(certFromFile("ee-example-org")); - checkCertNotInNameSpace(certFromFile("ee-example-test")); + await checkCertNotInNameSpace(certFromFile("ee-example-com-and-org")); + await checkCertNotInNameSpace(certFromFile("ee-example-com")); + await checkCertNotInNameSpace(certFromFile("ee-example-org")); + await checkCertNotInNameSpace(certFromFile("ee-example-test")); // Test that externally-imposed name constraints are enforced (DCISS tests). loadCertWithTrust("dciss", "CTu,,"); - checkCertInNameSpace(certFromFile("NameConstraints.dcissallowed")); - checkCertNotInNameSpace(certFromFile("NameConstraints.dcissblocked")); -} + await checkCertInNameSpace(certFromFile("NameConstraints.dcissallowed")); + await checkCertNotInNameSpace(certFromFile("NameConstraints.dcissblocked")); +});
--- a/security/manager/ssl/tests/unit/test_ocsp_enabled_pref.js +++ b/security/manager/ssl/tests/unit/test_ocsp_enabled_pref.js @@ -25,117 +25,94 @@ function getFailingOCSPResponder() { } function getOCSPResponder(expectedCertNames) { return startOCSPResponder(SERVER_PORT, "www.example.com", "test_ev_certs", expectedCertNames, []); } // Tests that in ocspOff mode, OCSP fetches are never done. -function testOff() { - add_test(() => { - Services.prefs.setIntPref("security.OCSP.enabled", 0); - info("Setting security.OCSP.enabled to 0"); - run_next_test(); - }); +async function testOff() { + Services.prefs.setIntPref("security.OCSP.enabled", 0); + info("Setting security.OCSP.enabled to 0"); // EV chains should verify successfully but never get EV status. - add_test(() => { - clearOCSPCache(); - let ocspResponder = getFailingOCSPResponder(); - checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), certificateUsageSSLServer, - false); - ocspResponder.stop(run_next_test); - }); + clearOCSPCache(); + let ocspResponder = getFailingOCSPResponder(); + await checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), + certificateUsageSSLServer, false); + await stopOCSPResponder(ocspResponder); // A DV chain should verify successfully. - add_test(() => { - clearOCSPCache(); - let ocspResponder = getFailingOCSPResponder(); - checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"), - PRErrorCodeSuccess, certificateUsageSSLServer); - ocspResponder.stop(run_next_test); - }); + clearOCSPCache(); + ocspResponder = getFailingOCSPResponder(); + await checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"), + PRErrorCodeSuccess, certificateUsageSSLServer); + await stopOCSPResponder(ocspResponder); } // Tests that in ocspOn mode, OCSP fetches are done for both EV and DV certs. -function testOn() { - add_test(() => { - Services.prefs.setIntPref("security.OCSP.enabled", 1); - info("Setting security.OCSP.enabled to 1"); - run_next_test(); - }); +async function testOn() { + Services.prefs.setIntPref("security.OCSP.enabled", 1); + info("Setting security.OCSP.enabled to 1"); // If a successful OCSP response is fetched, then an EV chain should verify // successfully and get EV status as well. - add_test(() => { - clearOCSPCache(); - let ocspResponder = + clearOCSPCache(); + let ocspResponder = getOCSPResponder(gEVExpected ? ["test-oid-path-int", "test-oid-path-ee"] : ["test-oid-path-ee"]); - checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), certificateUsageSSLServer, - gEVExpected); - ocspResponder.stop(run_next_test); - }); + await checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), + certificateUsageSSLServer, gEVExpected); + await stopOCSPResponder(ocspResponder); // If a successful OCSP response is fetched, then a DV chain should verify // successfully. - add_test(() => { - clearOCSPCache(); - let ocspResponder = getOCSPResponder(["non-ev-root-path-ee"]); - checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"), - PRErrorCodeSuccess, certificateUsageSSLServer); - ocspResponder.stop(run_next_test); - }); + clearOCSPCache(); + ocspResponder = getOCSPResponder(["non-ev-root-path-ee"]); + await checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),