diff --git a/accessible/aom/AccessibleNode.cpp b/accessible/aom/AccessibleNode.cpp index 2fbd2d7bd36b..41596c6ca83b 100644 --- a/accessible/aom/AccessibleNode.cpp +++ b/accessible/aom/AccessibleNode.cpp @@ -76,6 +76,33 @@ AccessibleNode::GetStates(nsTArray& aStates) mStates->Add(NS_LITERAL_STRING("defunct")); } +bool +AccessibleNode::Is(const Sequence& aFlavors) +{ + if (!mIntl) { + for (const auto& flavor : aFlavors) { + if (!flavor.EqualsLiteral("unknown") && !flavor.EqualsLiteral("defunct")) { + return false; + } + } + return true; + } + + nsAutoString role; + GetOrCreateAccService()->GetStringRole(mIntl->Role(), role); + + if (!mStates) { + mStates = GetOrCreateAccService()->GetStringStates(mIntl->State()); + } + + for (const auto& flavor : aFlavors) { + if (!flavor.Equals(role) && !mStates->Contains(flavor)) { + return false; + } + } + return true; +} + nsINode* AccessibleNode::GetDOMNode() { diff --git a/accessible/aom/AccessibleNode.h b/accessible/aom/AccessibleNode.h index 0a75e18d55b4..5ccd9a85840b 100644 --- a/accessible/aom/AccessibleNode.h +++ b/accessible/aom/AccessibleNode.h @@ -8,9 +8,7 @@ #define A11Y_AOM_ACCESSIBLENODE_H #include "nsWrapperCache.h" -#include "mozilla/RefPtr.h" -#include "nsTArray.h" -#include "nsString.h" +#include "mozilla/dom/BindingDeclarations.h" class nsINode; @@ -41,6 +39,8 @@ public: void GetStates(nsTArray& aStates); nsINode* GetDOMNode(); + bool Is(const Sequence& aFlavors); + a11y::Accessible* Internal() const { return mIntl; } protected: diff --git a/accessible/aom/moz.build b/accessible/aom/moz.build index c1adb0cc77d6..700081215312 100644 --- a/accessible/aom/moz.build +++ b/accessible/aom/moz.build @@ -5,11 +5,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS.mozilla.dom += [ - 'AccessibleNode.h' + 'AccessibleNode.h', ] UNIFIED_SOURCES += [ - 'AccessibleNode.cpp' + 'AccessibleNode.cpp', ] LOCAL_INCLUDES += [ diff --git a/accessible/tests/mochitest/aom/test_general.html b/accessible/tests/mochitest/aom/test_general.html index e67b51c4e19c..bc1038987f05 100644 --- a/accessible/tests/mochitest/aom/test_general.html +++ b/accessible/tests/mochitest/aom/test_general.html @@ -77,6 +77,9 @@ } } + ok(anode.is('document', 'focusable'), + 'correct role and state on an accessible node'); + finish(); } diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index cdbce306900d..e54bd77e79b0 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -24,7 +24,8 @@ - @@ -1092,9 +1093,9 @@ var oldBrowser = this.mCurrentBrowser; if (!gMultiProcessBrowser) { - oldBrowser.setAttribute("type", "content-targetable"); + oldBrowser.removeAttribute("primary"); oldBrowser.docShellIsActive = false; - newBrowser.setAttribute("type", "content-primary"); + newBrowser.setAttribute("primary", "true"); newBrowser.docShellIsActive = (window.windowState != window.STATE_MINIMIZED); } @@ -1940,7 +1941,7 @@ let b = document.createElementNS(NS_XUL, "browser"); b.permanentKey = aParams.permanentKey || {}; - b.setAttribute("type", "content-targetable"); + b.setAttribute("type", "content"); b.setAttribute("message", "true"); b.setAttribute("messagemanagergroup", "browsers"); b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu")); @@ -2526,13 +2527,6 @@ var browser = this.getBrowserForTab(aTab); - // Start closing the FrameLoaderOwners which are inactive, so that - // they are cleaned up as well. - let frameLoader = browser.frameLoader; - if (frameLoader && frameLoader.groupedSessionHistory) { - frameLoader.groupedSessionHistory.closeInactiveFrameLoaderOwners(); - } - if (!aTab._pendingPermitUnload && !aAdoptedByTab && !aSkipPermitUnload) { // We need to block while calling permitUnload() because it // processes the event queue and may lead to another removeTab() @@ -2622,7 +2616,7 @@ } // We are no longer the primary content area. - browser.setAttribute("type", "content-targetable"); + browser.removeAttribute("primary"); // Remove this tab as the owner of any other tabs, since it's going away. for (let tab of this.tabs) { @@ -3757,7 +3751,7 @@ this.destroy(); let toBrowser = this.requestedTab.linkedBrowser; - toBrowser.setAttribute("type", "content-primary"); + toBrowser.setAttribute("primary", "true"); this.tabbrowser._adjustFocusAfterTabSwitch(this.requestedTab); @@ -3766,7 +3760,7 @@ // before we were able to finalize, in which case, fromBrowser // doesn't exist. if (fromBrowser) { - fromBrowser.setAttribute("type", "content-targetable"); + fromBrowser.removeAttribute("primary"); } let event = new CustomEvent("TabSwitchDone", { diff --git a/browser/themes/shared/autocomplete.inc.css b/browser/themes/shared/autocomplete.inc.css index 79402ff5c86f..5f66b25d2729 100644 --- a/browser/themes/shared/autocomplete.inc.css +++ b/browser/themes/shared/autocomplete.inc.css @@ -40,7 +40,23 @@ /* Insecure field warning */ #PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] { - background-color: #F6F6F6; /* Bug 1319176 */ + background-color: var(--arrowpanel-dimmed); + border-bottom: 1px solid var(--panel-separator-color); + padding-bottom: 4px; + padding-top: 4px; +} + +#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"][selected] { + background-color: var(--arrowpanel-dimmed-further); +} + +#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] > .ac-title { + color: GrayText; + font-size: 1em; +} + +#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"][selected] > .ac-title { + color: inherit; } #PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] > .ac-site-icon { diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 6c0c442aa867..1e8639a9827b 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -1708,13 +1708,15 @@ nsDocShell::FirePageHideNotification(bool aIsUnload) return NS_OK; } -void +bool nsDocShell::MaybeInitTiming() { if (mTiming && !mBlankTiming) { - return; + return false; } + bool canBeReset = false; + if (mScriptGlobal && mBlankTiming) { nsPIDOMWindowInner* innerWin = mScriptGlobal->AsOuter()->GetCurrentInnerWindow(); @@ -1726,11 +1728,22 @@ nsDocShell::MaybeInitTiming() if (!mTiming) { mTiming = new nsDOMNavigationTiming(); + canBeReset = true; } mTiming->NotifyNavigationStart( mIsActive ? nsDOMNavigationTiming::DocShellState::eActive : nsDOMNavigationTiming::DocShellState::eInactive); + + return canBeReset; +} + +void +nsDocShell::MaybeResetInitTiming(bool aReset) +{ + if (aReset) { + mTiming = nullptr; + } } // @@ -7286,7 +7299,7 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest, // We don't update navigation timing for wyciwyg channels if (this == aProgress && !wcwgChannel) { - MaybeInitTiming(); + mozilla::Unused << MaybeInitTiming(); mTiming->NotifyFetchStart(uri, ConvertLoadTypeToNavigationType(mLoadType)); } @@ -7968,7 +7981,7 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal, // Make sure timing is created. But first record whether we had it // already, so we don't clobber the timing for an in-progress load. bool hadTiming = mTiming; - MaybeInitTiming(); + bool toBeReset = MaybeInitTiming(); if (mContentViewer) { // We've got a content viewer already. Make sure the user // permits us to discard the current document and replace it @@ -7984,6 +7997,7 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal, if (NS_SUCCEEDED(rv) && !okToUnload) { // The user chose not to unload the page, interrupt the load. + MaybeResetInitTiming(toBeReset); return NS_ERROR_FAILURE; } @@ -10481,12 +10495,10 @@ nsDocShell::InternalLoad(nsIURI* aURI, // timing then, from OnStateChange. // XXXbz mTiming should know what channel it's for, so we don't - // need this hackery. Note that this is still broken in cases - // when we're loading something that's not javascript: and the - // beforeunload handler denies the load. That will screw up - // timing for the next load! + // need this hackery. + bool toBeReset = false; if (!isJavaScript) { - MaybeInitTiming(); + toBeReset = MaybeInitTiming(); } bool timeBeforeUnload = aFileName.IsVoid(); if (mTiming && timeBeforeUnload) { @@ -10501,6 +10513,7 @@ nsDocShell::InternalLoad(nsIURI* aURI, if (NS_SUCCEEDED(rv) && !okToUnload) { // The user chose not to unload the page, interrupt the // load. + MaybeResetInitTiming(toBeReset); return NS_OK; } } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index a723102c54bd..68d10e528364 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -747,9 +747,15 @@ protected: /** * Initializes mTiming if it isn't yet. - * After calling this, mTiming is non-null. + * After calling this, mTiming is non-null. This method returns true if the + * initialization of the Timing can be reset (basically this is true if a new + * Timing object is created). + * In case the loading is aborted, MaybeResetInitTiming() can be called + * passing the return value of MaybeInitTiming(): if it's possible to reset + * the Timing, this method will do it. */ - void MaybeInitTiming(); + MOZ_MUST_USE bool MaybeInitTiming(); + void MaybeResetInitTiming(bool aReset); bool DisplayLoadError(nsresult aError, nsIURI* aURI, const char16_t* aURL, nsIChannel* aFailedChannel) diff --git a/docshell/base/nsIDocShellTreeOwner.idl b/docshell/base/nsIDocShellTreeOwner.idl index 76c9f130e2f3..d7d5bb10e169 100644 --- a/docshell/base/nsIDocShellTreeOwner.idl +++ b/docshell/base/nsIDocShellTreeOwner.idl @@ -23,11 +23,9 @@ interface nsIDocShellTreeOwner : nsISupports * * @param aContentShell the shell being added. * @param aPrimary whether the shell is primary. - * @param aID the "id" of the shell. What this actually means is - * undefined. Don't rely on this for anything. */ void contentShellAdded(in nsIDocShellTreeItem aContentShell, - in boolean aPrimary, in AString aID); + in boolean aPrimary); /** * Called when a content shell is removed from the docshell tree. This is diff --git a/docshell/shistory/nsIGroupedSHistory.idl b/docshell/shistory/nsIGroupedSHistory.idl index 7c3f6e5dc829..1d090e9241d9 100644 --- a/docshell/shistory/nsIGroupedSHistory.idl +++ b/docshell/shistory/nsIGroupedSHistory.idl @@ -29,10 +29,13 @@ interface nsIGroupedSHistory : nsISupports /** * Notify the grouped session history that the active partial session history - * has been modified. All partial session histories after the active one - * will be removed and destroy. + * has been modified. + * + * @param aPartialHistory The partial history which was updated + * @param aTruncate If this parameter is true, all partial session histories + * after this one will be removed. */ - void onPartialSessionHistoryChange(in nsIPartialSHistory aPartialHistory); + void handleSHistoryUpdate(in nsIPartialSHistory aPartialHistory, in boolean aTruncate); /** * Find the proper partial session history and navigate to the entry diff --git a/docshell/shistory/nsIPartialSHistory.idl b/docshell/shistory/nsIPartialSHistory.idl index 99359794e765..6d992f8a7ba9 100644 --- a/docshell/shistory/nsIPartialSHistory.idl +++ b/docshell/shistory/nsIPartialSHistory.idl @@ -17,6 +17,9 @@ interface nsIPartialSHistory : nsISupports // The number of entries of its corresponding nsISHistory. [infallible] readonly attribute unsigned long count; + // The current global index of the active shentry in this partialSHistory. + [infallible] readonly attribute long globalIndex; + // If it's part of a grouped session history, globalIndexOffset denotes the // number of entries ahead. [infallible] readonly attribute unsigned long globalIndexOffset; @@ -34,15 +37,15 @@ interface nsIPartialSHistory : nsISupports void onAttachGroupedSessionHistory(in unsigned long aOffset); /** - * Notify that one or more entries in its associated nsISHistory object - * have been changed (i.e. add / remove / replace). It's mainly used for - * cross-process case, since in the in-process case we can just register an - * nsISHistoryListener instead. + * This method is used by the TabParent to notify the PartialSHistory + * that the state of its corresponding nsISHistory in the content process + * has been updated. It is unused in the in-process case. * - * @param aCount The number of entries in the associated session history. - * It can be the same as the old value if entries were replaced. + * @param aCount The number of entries in the associated session history. + * @param aLocalIndex The local index of the currently active entry in the + * associated session history */ - void onSessionHistoryChange(in unsigned long aCount); + void handleSHistoryUpdate(in unsigned long aCount, in unsigned long aLocalIndex, in boolean aTruncate); /** * Notify that the partial session history has been swapped in as the active diff --git a/docshell/shistory/nsISHistory.idl b/docshell/shistory/nsISHistory.idl index 7d63b99cff51..2959895d2982 100644 --- a/docshell/shistory/nsISHistory.idl +++ b/docshell/shistory/nsISHistory.idl @@ -32,6 +32,15 @@ interface nsIPartialSHistoryListener; [scriptable, uuid(7b807041-e60a-4384-935f-af3061d8b815)] interface nsISHistory: nsISupports { + /** + * The size of the window of SHEntries which can have alive viewers in the + * bfcache around the currently active SHEntry. + * + * We try to keep viewers for SHEntries between index - VIEWER_WINDOW and + * index + VIEWER_WINDOW alive. + */ + const long VIEWER_WINDOW = 3; + /** * An attribute denoting whether the nsISHistory is associated to a grouped * session history. diff --git a/docshell/shistory/nsISHistoryListener.idl b/docshell/shistory/nsISHistoryListener.idl index 119b39ee497e..061ba32d0460 100644 --- a/docshell/shistory/nsISHistoryListener.idl +++ b/docshell/shistory/nsISHistoryListener.idl @@ -113,5 +113,12 @@ interface nsISHistoryListener : nsISupports * and OnHistoryPurge which happen before the modifications are actually done * and maybe cancellable, this function is called after these modifications. */ - void OnLengthChange(in long aCount); + void OnLengthChanged(in long aCount); + + /** + * Called when nsISHistory::index has been updated. Unlike the other methods + * on this interface, which happen before the modifications are actually done + * and maybe cancellable, this function is called after these modifications. + */ + void OnIndexChanged(in long aIndex); }; diff --git a/docshell/shistory/nsSHistory.cpp b/docshell/shistory/nsSHistory.cpp index cd4aa651f0e1..1c43a95966cb 100644 --- a/docshell/shistory/nsSHistory.cpp +++ b/docshell/shistory/nsSHistory.cpp @@ -48,8 +48,6 @@ static const char* kObservedPrefs[] = { }; static int32_t gHistoryMaxSize = 50; -// Max viewers allowed per SHistory objects -static const int32_t gHistoryMaxViewers = 3; // List of all SHistory objects, used for content viewer cache eviction static PRCList gSHistoryList; // Max viewers allowed total, across all SHistory objects - negative default @@ -430,7 +428,8 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist) // what the length was before, it should always be set back to the current and // lop off the forward. mLength = (++mIndex + 1); - NOTIFY_LISTENERS(OnLengthChange, (mLength)); + NOTIFY_LISTENERS(OnLengthChanged, (mLength)); + NOTIFY_LISTENERS(OnIndexChanged, (mIndex)); // Much like how mLength works above, when changing our entries, all following // partial histories should be purged, so we just reset the number to zero. @@ -561,6 +560,7 @@ nsSHistory::GetEntryAtIndex(int32_t aIndex, bool aModifyIndex, // Set mIndex to the requested index, if asked to do so.. if (aModifyIndex) { mIndex = aIndex; + NOTIFY_LISTENERS(OnIndexChanged, (mIndex)) } } } @@ -784,7 +784,6 @@ nsSHistory::PurgeHistory(int32_t aEntries) } mLength -= cnt; mIndex -= cnt; - NOTIFY_LISTENERS(OnLengthChange, (mLength)); // All following partial histories will be deleted in this case. mEntriesInFollowingPartialHistories = 0; @@ -795,6 +794,9 @@ nsSHistory::PurgeHistory(int32_t aEntries) mIndex = -1; } + NOTIFY_LISTENERS(OnLengthChanged, (mLength)); + NOTIFY_LISTENERS(OnIndexChanged, (mIndex)) + if (mRootDocShell) { mRootDocShell->HistoryPurged(cnt); } @@ -1041,14 +1043,14 @@ nsSHistory::EvictOutOfRangeWindowContentViewers(int32_t aIndex) // We need to release all content viewers that are no longer in the range // - // aIndex - gHistoryMaxViewers to aIndex + gHistoryMaxViewers + // aIndex - VIEWER_WINDOW to aIndex + VIEWER_WINDOW // // to ensure that this SHistory object isn't responsible for more than - // gHistoryMaxViewers content viewers. But our job is complicated by the + // VIEWER_WINDOW content viewers. But our job is complicated by the // fact that two transactions which are related by either hash navigations or // history.pushState will have the same content viewer. // - // To illustrate the issue, suppose gHistoryMaxViewers = 3 and we have four + // To illustrate the issue, suppose VIEWER_WINDOW = 3 and we have four // linked transactions in our history. Suppose we then add a new content // viewer and call into this function. So the history looks like: // @@ -1056,7 +1058,7 @@ nsSHistory::EvictOutOfRangeWindowContentViewers(int32_t aIndex) // + * // // where the letters are content viewers and + and * denote the beginning and - // end of the range aIndex +/- gHistoryMaxViewers. + // end of the range aIndex +/- VIEWER_WINDOW. // // Although one copy of the content viewer A exists outside the range, we // don't want to evict A, because it has other copies in range! @@ -1064,7 +1066,7 @@ nsSHistory::EvictOutOfRangeWindowContentViewers(int32_t aIndex) // We therefore adjust our eviction strategy to read: // // Evict each content viewer outside the range aIndex -/+ - // gHistoryMaxViewers, unless that content viewer also appears within the + // VIEWER_WINDOW, unless that content viewer also appears within the // range. // // (Note that it's entirely legal to have two copies of one content viewer @@ -1078,14 +1080,14 @@ nsSHistory::EvictOutOfRangeWindowContentViewers(int32_t aIndex) NS_ENSURE_TRUE_VOID(aIndex < mLength); // Calculate the range that's safe from eviction. - int32_t startSafeIndex = std::max(0, aIndex - gHistoryMaxViewers); - int32_t endSafeIndex = std::min(mLength, aIndex + gHistoryMaxViewers); + int32_t startSafeIndex = std::max(0, aIndex - nsISHistory::VIEWER_WINDOW); + int32_t endSafeIndex = std::min(mLength, aIndex + nsISHistory::VIEWER_WINDOW); LOG(("EvictOutOfRangeWindowContentViewers(index=%d), " "mLength=%d. Safe range [%d, %d]", aIndex, mLength, startSafeIndex, endSafeIndex)); - // The content viewers in range aIndex -/+ gHistoryMaxViewers will not be + // The content viewers in range aIndex -/+ VIEWER_WINDOW will not be // evicted. Collect a set of them so we don't accidentally evict one of them // if it appears outside this range. nsCOMArray safeViewers; @@ -1182,7 +1184,7 @@ nsSHistory::GloballyEvictContentViewers() nsTArray shTransactions; // Content viewers are likely to exist only within shist->mIndex -/+ - // gHistoryMaxViewers, so only search within that range. + // VIEWER_WINDOW, so only search within that range. // // A content viewer might exist outside that range due to either: // @@ -1194,9 +1196,9 @@ nsSHistory::GloballyEvictContentViewers() // SHistory object in question, we'll do a full search of its history // and evict the out-of-range content viewers, so we don't bother here. // - int32_t startIndex = std::max(0, shist->mIndex - gHistoryMaxViewers); + int32_t startIndex = std::max(0, shist->mIndex - nsISHistory::VIEWER_WINDOW); int32_t endIndex = std::min(shist->mLength - 1, - shist->mIndex + gHistoryMaxViewers); + shist->mIndex + nsISHistory::VIEWER_WINDOW); nsCOMPtr trans; shist->GetTransactionAtIndex(startIndex, getter_AddRefs(trans)); for (int32_t i = startIndex; trans && i <= endIndex; i++) { @@ -1259,8 +1261,8 @@ nsSHistory::GloballyEvictContentViewers() nsresult nsSHistory::EvictExpiredContentViewerForEntry(nsIBFCacheEntry* aEntry) { - int32_t startIndex = std::max(0, mIndex - gHistoryMaxViewers); - int32_t endIndex = std::min(mLength - 1, mIndex + gHistoryMaxViewers); + int32_t startIndex = std::max(0, mIndex - nsISHistory::VIEWER_WINDOW); + int32_t endIndex = std::min(mLength - 1, mIndex + nsISHistory::VIEWER_WINDOW); nsCOMPtr trans; GetTransactionAtIndex(startIndex, getter_AddRefs(trans)); @@ -1458,6 +1460,7 @@ nsSHistory::RemoveDuplicate(int32_t aIndex, bool aKeepNext) // Adjust our indices to reflect the removed transaction if (mIndex > aIndex) { mIndex = mIndex - 1; + NOTIFY_LISTENERS(OnIndexChanged, (mIndex)); } // NB: If the transaction we are removing is the transaction currently @@ -1477,7 +1480,7 @@ nsSHistory::RemoveDuplicate(int32_t aIndex, bool aKeepNext) } --mLength; mEntriesInFollowingPartialHistories = 0; - NOTIFY_LISTENERS(OnLengthChange, (mLength)); + NOTIFY_LISTENERS(OnLengthChanged, (mLength)); return true; } return false; @@ -1547,6 +1550,7 @@ nsSHistory::UpdateIndex() if (mIndex != mRequestedIndex && mRequestedIndex != -1) { RemoveDynEntries(mIndex, mRequestedIndex); mIndex = mRequestedIndex; + NOTIFY_LISTENERS(OnIndexChanged, (mIndex)) } mRequestedIndex = -1; diff --git a/docshell/test/browser/browser.ini b/docshell/test/browser/browser.ini index f362d88c7d94..013f1bd66fc1 100644 --- a/docshell/test/browser/browser.ini +++ b/docshell/test/browser/browser.ini @@ -93,3 +93,7 @@ skip-if = true # Bug 1220415 [browser_ua_emulation.js] [browser_grouped_shistory_dead_navigate.js] skip-if = !e10s +[browser_grouped_shistory_crossproc.js] +skip-if = !e10s +[browser_grouped_shistory_bfcache_cleaning.js] +skip-if = !e10s diff --git a/docshell/test/browser/browser_grouped_shistory_bfcache_cleaning.js b/docshell/test/browser/browser_grouped_shistory_bfcache_cleaning.js new file mode 100644 index 000000000000..f902b5909e7b --- /dev/null +++ b/docshell/test/browser/browser_grouped_shistory_bfcache_cleaning.js @@ -0,0 +1,61 @@ +add_task(function* () { + yield SpecialPowers.pushPrefEnv({ + set: [["browser.groupedhistory.enabled", true]] + }); + + // Wait for a process change and then fulfil the promise. + function awaitProcessChange(browser) { + return new Promise(resolve => { + browser.addEventListener("BrowserChangedProcess", function bcp(e) { + browser.removeEventListener("BrowserChangedProcess", bcp); + ok(true, "The browser changed process!"); + resolve(); + }); + }); + } + + function isAlive(tab) { + return tab.linkedBrowser && + tab.linkedBrowser.frameLoader && + !tab.linkedBrowser.frameLoader.isDead; + } + + yield BrowserTestUtils.withNewTab({ gBrowser, url: "data:text/html,a" }, function* (browser1) { + // Set up the grouped SHEntry setup + let tab2 = gBrowser.loadOneTab("data:text/html,b", { + referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT, + allowThirdPartyFixup: true, + relatedToCurrent: true, + isPrerendered: true, + }); + yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser); + browser1.frameLoader.appendPartialSessionHistoryAndSwap( + tab2.linkedBrowser.frameLoader); + yield awaitProcessChange(browser1); + ok(isAlive(tab2)); + + // Load some URIs and make sure that we lose the old process once we are 3 history entries away. + browser1.loadURI("data:text/html,c", null, null); + yield BrowserTestUtils.browserLoaded(browser1); + ok(isAlive(tab2), "frameloader should still be alive"); + browser1.loadURI("data:text/html,d", null, null); + yield BrowserTestUtils.browserLoaded(browser1); + ok(isAlive(tab2), "frameloader should still be alive"); + browser1.loadURI("data:text/html,e", null, null); + yield BrowserTestUtils.browserLoaded(browser1); + ok(isAlive(tab2), "frameloader should still be alive"); + + // The 4th navigation should kill the frameloader + browser1.loadURI("data:text/html,f", null, null); + yield new Promise(resolve => { + tab2.addEventListener("TabClose", function f() { + tab2.removeEventListener("TabClose", f); + ok(true, "The tab is being closed!\n"); + resolve(); + }); + }); + // We don't check for !isAlive() as TabClose is called during + // _beginRemoveTab, which means that the frameloader may not be dead yet. We + // avoid races by not checking. + }); +}); diff --git a/docshell/test/browser/browser_grouped_shistory_crossproc.js b/docshell/test/browser/browser_grouped_shistory_crossproc.js new file mode 100644 index 000000000000..a036c10002a6 --- /dev/null +++ b/docshell/test/browser/browser_grouped_shistory_crossproc.js @@ -0,0 +1,41 @@ +add_task(function* () { + yield SpecialPowers.pushPrefEnv({ + set: [["browser.groupedhistory.enabled", true]] + }); + + // Wait for a process change and then fulfil the promise. + function awaitProcessChange(browser) { + return new Promise(resolve => { + browser.addEventListener("BrowserChangedProcess", function bcp(e) { + browser.removeEventListener("BrowserChangedProcess", bcp); + ok(true, "The browser changed process!"); + resolve(); + }); + }); + } + + yield BrowserTestUtils.withNewTab({ gBrowser, url: "data:text/html,a" }, function* (browser1) { + // Set up the grouped SHEntry setup + let tab2 = gBrowser.loadOneTab("data:text/html,b", { + referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT, + allowThirdPartyFixup: true, + relatedToCurrent: true, + isPrerendered: true, + }); + yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser); + browser1.frameLoader.appendPartialSessionHistoryAndSwap( + tab2.linkedBrowser.frameLoader); + yield awaitProcessChange(browser1); + + // Load a URI which will involve loading in the parent process + browser1.loadURI("about:config", Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null); + yield BrowserTestUtils.browserLoaded(browser1); + let docshell = browser1.frameLoader.docShell.QueryInterface(Ci.nsIWebNavigation); + ok(docshell, "The browser should be loaded in the chrome process"); + is(docshell.canGoForward, false, "canGoForward is correct"); + is(docshell.canGoBack, true, "canGoBack is correct"); + is(docshell.sessionHistory.count, 3, "Count is correct"); + is(browser1.frameLoader.groupedSessionHistory, null, + "browser1's session history is now complete"); + }); +}); diff --git a/docshell/test/chrome/bug112564_window.xul b/docshell/test/chrome/bug112564_window.xul index e76dafd8643b..0660408a4323 100644 --- a/docshell/test/chrome/bug112564_window.xul +++ b/docshell/test/chrome/bug112564_window.xul @@ -111,5 +111,5 @@ } ]]> - + diff --git a/docshell/test/chrome/bug215405_window.xul b/docshell/test/chrome/bug215405_window.xul index bd8df63cf6fd..9badd5eba5db 100644 --- a/docshell/test/chrome/bug215405_window.xul +++ b/docshell/test/chrome/bug215405_window.xul @@ -156,5 +156,5 @@ } ]]> - + diff --git a/docshell/test/chrome/bug293235_window.xul b/docshell/test/chrome/bug293235_window.xul index 95b783130ab7..002a3cf86730 100644 --- a/docshell/test/chrome/bug293235_window.xul +++ b/docshell/test/chrome/bug293235_window.xul @@ -156,5 +156,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug294258_window.xul b/docshell/test/chrome/bug294258_window.xul index ce9abcf8d065..293c9667df7a 100644 --- a/docshell/test/chrome/bug294258_window.xul +++ b/docshell/test/chrome/bug294258_window.xul @@ -70,5 +70,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug298622_window.xul b/docshell/test/chrome/bug298622_window.xul index 6385a36f985f..2c2e28c0644e 100755 --- a/docshell/test/chrome/bug298622_window.xul +++ b/docshell/test/chrome/bug298622_window.xul @@ -141,6 +141,6 @@ - + diff --git a/docshell/test/chrome/bug301397_window.xul b/docshell/test/chrome/bug301397_window.xul index b6824df19a44..fe1f80ed6172 100644 --- a/docshell/test/chrome/bug301397_window.xul +++ b/docshell/test/chrome/bug301397_window.xul @@ -244,5 +244,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug303267_window.xul b/docshell/test/chrome/bug303267_window.xul index 944afc6cf2cc..4b050d6eb9a5 100755 --- a/docshell/test/chrome/bug303267_window.xul +++ b/docshell/test/chrome/bug303267_window.xul @@ -95,5 +95,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug311007_window.xul b/docshell/test/chrome/bug311007_window.xul index 730580cc2bd3..7ab784540e76 100644 --- a/docshell/test/chrome/bug311007_window.xul +++ b/docshell/test/chrome/bug311007_window.xul @@ -195,5 +195,5 @@ function step4B(aWebProgress, aRequest, aLocation, aFlags) { } ]]> - + diff --git a/docshell/test/chrome/bug321671_window.xul b/docshell/test/chrome/bug321671_window.xul index 08ae2ad3c931..4fc9bec9ae81 100755 --- a/docshell/test/chrome/bug321671_window.xul +++ b/docshell/test/chrome/bug321671_window.xul @@ -127,5 +127,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug360511_window.xul b/docshell/test/chrome/bug360511_window.xul index 273f2b899463..198dfcb8e860 100755 --- a/docshell/test/chrome/bug360511_window.xul +++ b/docshell/test/chrome/bug360511_window.xul @@ -128,5 +128,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug364461_window.xul b/docshell/test/chrome/bug364461_window.xul index 1ae4a66d2b8f..e834285b07b9 100644 --- a/docshell/test/chrome/bug364461_window.xul +++ b/docshell/test/chrome/bug364461_window.xul @@ -266,5 +266,5 @@ } ]]> - + diff --git a/docshell/test/chrome/bug396519_window.xul b/docshell/test/chrome/bug396519_window.xul index 7ee2f5d6d5ee..29537db85a4e 100644 --- a/docshell/test/chrome/bug396519_window.xul +++ b/docshell/test/chrome/bug396519_window.xul @@ -163,5 +163,5 @@ } ]]> - + diff --git a/docshell/test/chrome/bug396649_window.xul b/docshell/test/chrome/bug396649_window.xul index 932f86fbfd09..d8fd88501820 100755 --- a/docshell/test/chrome/bug396649_window.xul +++ b/docshell/test/chrome/bug396649_window.xul @@ -116,5 +116,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug582176_window.xul b/docshell/test/chrome/bug582176_window.xul index f36bc22a6430..bc5669232a88 100644 --- a/docshell/test/chrome/bug582176_window.xul +++ b/docshell/test/chrome/bug582176_window.xul @@ -82,5 +82,5 @@ } ]]> - + diff --git a/docshell/test/chrome/bug662200_window.xul b/docshell/test/chrome/bug662200_window.xul index 8a5522629f11..e53c1ba00227 100644 --- a/docshell/test/chrome/bug662200_window.xul +++ b/docshell/test/chrome/bug662200_window.xul @@ -123,5 +123,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug690056_window.xul b/docshell/test/chrome/bug690056_window.xul index d273de8f8701..2f4cad7e6dd2 100644 --- a/docshell/test/chrome/bug690056_window.xul +++ b/docshell/test/chrome/bug690056_window.xul @@ -170,5 +170,5 @@ } ]]> - + diff --git a/docshell/test/chrome/bug89419_window.xul b/docshell/test/chrome/bug89419_window.xul index 329a4f225c49..99ca84511ec6 100644 --- a/docshell/test/chrome/bug89419_window.xul +++ b/docshell/test/chrome/bug89419_window.xul @@ -76,5 +76,5 @@ ]]> - + diff --git a/docshell/test/chrome/bug92598_window.xul b/docshell/test/chrome/bug92598_window.xul index 54376d537584..5d22b7abe3cd 100644 --- a/docshell/test/chrome/bug92598_window.xul +++ b/docshell/test/chrome/bug92598_window.xul @@ -112,5 +112,5 @@ } ]]> - + diff --git a/docshell/test/chrome/window.template.txt b/docshell/test/chrome/window.template.txt index a7fb0fac7c29..f572806f69ea 100644 --- a/docshell/test/chrome/window.template.txt +++ b/docshell/test/chrome/window.template.txt @@ -40,5 +40,5 @@ ]]> - + diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index 00ee3d42fecb..a4a21e8a12d5 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -103,6 +103,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry) tmp->mCustomDefinitions.Clear(); + tmp->mConstructors.clear(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER @@ -150,6 +151,12 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementRegistry) "mCustomDefinitions prototype", aClosure); } + + for (ConstructorMap::Enum iter(tmp->mConstructors); !iter.empty(); iter.popFront()) { + aCallbacks.Trace(&iter.front().mutableKey(), + "mConstructors key", + aClosure); + } NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_END @@ -184,6 +191,11 @@ CustomElementRegistry::Create(nsPIDOMWindowInner* aWindow) RefPtr customElementRegistry = new CustomElementRegistry(aWindow); + + if (!customElementRegistry->Init()) { + return nullptr; + } + return customElementRegistry.forget(); } @@ -242,6 +254,12 @@ CustomElementRegistry::~CustomElementRegistry() mozilla::DropJSObjects(this); } +bool +CustomElementRegistry::Init() +{ + return mConstructors.init(); +} + CustomElementDefinition* CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName, const nsAString* aIs) const @@ -257,6 +275,23 @@ CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName return nullptr; } +CustomElementDefinition* +CustomElementRegistry::LookupCustomElementDefinition(JSContext* aCx, + JSObject* aConstructor) const +{ + JS::Rooted constructor(aCx, js::CheckedUnwrap(aConstructor)); + + const auto& ptr = mConstructors.lookup(constructor); + if (!ptr) { + return nullptr; + } + + CustomElementDefinition* definition = mCustomDefinitions.Get(ptr->value()); + MOZ_ASSERT(definition, "Definition must be found in mCustomDefinitions"); + + return definition; +} + void CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName) { @@ -610,9 +645,13 @@ CustomElementRegistry::Define(const nsAString& aName, * 4. If this CustomElementRegistry contains an entry with constructor constructor, * then throw a "NotSupportedError" DOMException and abort these steps. */ - // TODO: Step 3 of HTMLConstructor also needs a way to look up definition by - // using constructor. So I plans to figure out a solution to support both of - // them in bug 1274159. + const auto& ptr = mConstructors.lookup(constructorUnwrapped); + if (ptr) { + MOZ_ASSERT(mCustomDefinitions.Get(ptr->value()), + "Definition must be found in mCustomDefinitions"); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return; + } /** * 5. Let localName be name. @@ -768,8 +807,16 @@ CustomElementRegistry::Define(const nsAString& aName, /** * 12. Add definition to this CustomElementRegistry. */ + if (!mConstructors.put(constructorUnwrapped, nameAtom)) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + mCustomDefinitions.Put(nameAtom, definition); + MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(), + "Number of entries should be the same"); + /** * 13. 14. 15. Upgrade candidates */ @@ -854,4 +901,4 @@ CustomElementDefinition::CustomElementDefinition(nsIAtom* aType, } } // namespace dom -} // namespace mozilla \ No newline at end of file +} // namespace mozilla diff --git a/dom/base/CustomElementRegistry.h b/dom/base/CustomElementRegistry.h index ff803a054285..8ef0785af370 100644 --- a/dom/base/CustomElementRegistry.h +++ b/dom/base/CustomElementRegistry.h @@ -7,13 +7,14 @@ #ifndef mozilla_dom_CustomElementRegistry_h #define mozilla_dom_CustomElementRegistry_h +#include "js/GCHashTable.h" #include "js/TypeDecls.h" #include "mozilla/Attributes.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/FunctionBinding.h" #include "nsCycleCollectionParticipant.h" #include "nsWrapperCache.h" -#include "mozilla/dom/FunctionBinding.h" class nsDocument; @@ -127,6 +128,10 @@ struct CustomElementDefinition // The document custom element order. uint32_t mDocOrder; + + bool IsCustomBuiltIn() { + return mType != mLocalName; + } }; class CustomElementRegistry final : public nsISupports, @@ -154,6 +159,9 @@ public: CustomElementDefinition* LookupCustomElementDefinition( const nsAString& aLocalName, const nsAString* aIs = nullptr) const; + CustomElementDefinition* LookupCustomElementDefinition( + JSContext* aCx, JSObject *aConstructor) const; + /** * Enqueue created callback or register upgrade candidate for * newly created custom elements, possibly extending an existing type. @@ -173,6 +181,8 @@ private: explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow); ~CustomElementRegistry(); + bool Init(); + /** * Registers an unresolved custom element that is a candidate for * upgrade when the definition is registered via registerElement. @@ -192,15 +202,25 @@ private: DefinitionMap; typedef nsClassHashtable> CandidateMap; + typedef JS::GCHashMap, + nsCOMPtr, + js::MovableCellHasher>, + js::SystemAllocPolicy> ConstructorMap; // Hashtable for custom element definitions in web components. // Custom prototypes are stored in the compartment where // registerElement was called. DefinitionMap mCustomDefinitions; + // Hashtable for looking up definitions by using constructor as key. + // Custom elements' name are stored here and we need to lookup + // mCustomDefinitions again to get definitions. + ConstructorMap mConstructors; + typedef nsRefPtrHashtable WhenDefinedPromiseMap; WhenDefinedPromiseMap mWhenDefinedPromiseMap; + // The "upgrade candidates map" from the web components spec. Maps from a // namespace id and local name to a list of elements to upgrade if that // element is registered as a custom element. diff --git a/dom/base/GroupedSHistory.cpp b/dom/base/GroupedSHistory.cpp index 92ddef9993f1..eae3db89dfdd 100644 --- a/dom/base/GroupedSHistory.cpp +++ b/dom/base/GroupedSHistory.cpp @@ -70,27 +70,54 @@ GroupedSHistory::AppendPartialSessionHistory(nsIPartialSHistory* aPartialHistory } NS_IMETHODIMP -GroupedSHistory::OnPartialSessionHistoryChange( - nsIPartialSHistory* aPartialSessionHistory) +GroupedSHistory::HandleSHistoryUpdate(nsIPartialSHistory* aPartial, bool aTruncate) { - if (!aPartialSessionHistory) { + if (!aPartial) { return NS_ERROR_INVALID_POINTER; } + nsCOMPtr partialHistory = aPartial; - nsCOMPtr partialHistory(aPartialSessionHistory); - int32_t index = mPartialHistories.IndexOf(partialHistory); - if (NS_WARN_IF(index != mIndexOfActivePartialHistory) || - NS_WARN_IF(index < 0)) { - // Non-active or not attached partialHistory - return NS_ERROR_UNEXPECTED; + int32_t index = partialHistory->GetGlobalIndex(); + // Get the lower and upper bounds for the viewer window + int32_t lower = index - nsISHistory::VIEWER_WINDOW; + int32_t upper = index + nsISHistory::VIEWER_WINDOW; + for (uint32_t i = 0; i < mPartialHistories.Length(); ++i) { + nsIPartialSHistory* pHistory = mPartialHistories[i]; + // Skip the active partial history. + if (pHistory == partialHistory) { + continue; + } + + // Check if the given partialshistory entry is too far away in history, and + // if it is, close it. + int32_t thisCount = pHistory->GetCount(); + int32_t thisOffset = pHistory->GetGlobalIndexOffset(); + if ((thisOffset > upper) || ((thisCount + thisOffset) < lower)) { + nsCOMPtr loader; + pHistory->GetOwnerFrameLoader(getter_AddRefs(loader)); + if (loader && !loader->GetIsDead()) { + loader->RequestFrameLoaderClose(); + } + } } - PurgePartialHistories(index); + // If we should be truncating, make sure to purge any partialSHistories which + // follow the one being updated. + if (aTruncate) { + int32_t index = mPartialHistories.IndexOf(partialHistory); + if (NS_WARN_IF(index != mIndexOfActivePartialHistory) || + NS_WARN_IF(index < 0)) { + // Non-active or not attached partialHistory + return NS_ERROR_UNEXPECTED; + } - // Update global count. - uint32_t count = partialHistory->GetCount(); - uint32_t offset = partialHistory->GetGlobalIndexOffset(); - mCount = count + offset; + PurgePartialHistories(index); + + // Update global count. + uint32_t count = partialHistory->GetCount(); + uint32_t offset = partialHistory->GetGlobalIndexOffset(); + mCount = count + offset; + } return NS_OK; } diff --git a/dom/base/PartialSHistory.cpp b/dom/base/PartialSHistory.cpp index 44a652570f3b..f8288221ebfd 100644 --- a/dom/base/PartialSHistory.cpp +++ b/dom/base/PartialSHistory.cpp @@ -89,6 +89,27 @@ PartialSHistory::GetCount(uint32_t* aResult) return NS_OK; } +NS_IMETHODIMP +PartialSHistory::GetGlobalIndex(int32_t* aResult) +{ + if (!aResult) { + return NS_ERROR_INVALID_POINTER; + } + + nsCOMPtr shistory = GetSessionHistory(); + if (shistory) { + int32_t idx; + nsresult rv = shistory->GetIndex(&idx); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = idx + GetGlobalIndexOffset(); + return NS_OK; + } + + *aResult = mIndex + GetGlobalIndexOffset(); + return NS_OK; +} + NS_IMETHODIMP PartialSHistory::GetGlobalIndexOffset(uint32_t* aResult) { @@ -150,10 +171,32 @@ PartialSHistory::OnAttachGroupedSessionHistory(uint32_t aOffset) } NS_IMETHODIMP -PartialSHistory::OnSessionHistoryChange(uint32_t aCount) +PartialSHistory::HandleSHistoryUpdate(uint32_t aCount, uint32_t aIndex, bool aTruncate) { + // Update our local cache of mCount and mIndex mCount = aCount; - return OnLengthChange(aCount); + mIndex = aIndex; + return SHistoryDidUpdate(aTruncate); +} + +nsresult +PartialSHistory::SHistoryDidUpdate(bool aTruncate /* = false */) +{ + if (!mOwnerFrameLoader) { + // Cycle collected? + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr groupedHistory; + mOwnerFrameLoader->GetGroupedSessionHistory(getter_AddRefs(groupedHistory)); + if (NS_WARN_IF(!groupedHistory)) { + // Maybe we're not the active partial history, but in this case we shouldn't + // receive any update from session history object either. + return NS_ERROR_FAILURE; + } + + groupedHistory->HandleSHistoryUpdate(this, aTruncate); + return NS_OK; } NS_IMETHODIMP @@ -227,27 +270,15 @@ PartialSHistory::OnRequestCrossBrowserNavigation(uint32_t aIndex) ******************************************************************************/ NS_IMETHODIMP -PartialSHistory::OnLengthChange(int32_t aCount) +PartialSHistory::OnLengthChanged(int32_t aCount) { - if (!mOwnerFrameLoader) { - // Cycle collected? - return NS_ERROR_UNEXPECTED; - } + return SHistoryDidUpdate(/* aTruncate = */ true); +} - if (aCount < 0) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr groupedHistory; - mOwnerFrameLoader->GetGroupedSessionHistory(getter_AddRefs(groupedHistory)); - if (!groupedHistory) { - // Maybe we're not the active partial history, but in this case we shouldn't - // receive any update from session history object either. - return NS_ERROR_FAILURE; - } - - groupedHistory->OnPartialSessionHistoryChange(this); - return NS_OK; +NS_IMETHODIMP +PartialSHistory::OnIndexChanged(int32_t aIndex) +{ + return SHistoryDidUpdate(/* aTruncate = */ false); } NS_IMETHODIMP diff --git a/dom/base/PartialSHistory.h b/dom/base/PartialSHistory.h index 5e8a435e67f7..060817c66b24 100644 --- a/dom/base/PartialSHistory.h +++ b/dom/base/PartialSHistory.h @@ -42,11 +42,16 @@ private: already_AddRefed GetSessionHistory(); already_AddRefed GetTabParent(); + nsresult SHistoryDidUpdate(bool aTruncate = false); + // The cache of number of entries in corresponding nsISHistory. It's only // used for remote process case. If nsISHistory is in-process, mCount will not // be used at all. uint32_t mCount; + // The current local index of the active document in this partial SHistory. + uint32_t mIndex; + // The cache of globalIndexOffset in corresponding nsISHistory. It's only // used for remote process case. uint32_t mGlobalIndexOffset; diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 78aee28b78fd..d6b44b8fd5a0 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -967,16 +967,8 @@ nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, NS_PRECONDITION(mOwnerContent, "Must have owning content"); nsAutoString value; - bool isContent = false; - mOwnerContent->GetAttr(kNameSpaceID_None, TypeAttrName(), value); - - // we accept "content" and "content-xxx" values. - // at time of writing, we expect "xxx" to be "primary" or "targetable", but - // someday it might be an integer expressing priority or something else. - - isContent = value.LowerCaseEqualsLiteral("content") || - StringBeginsWith(value, NS_LITERAL_STRING("content-"), - nsCaseInsensitiveStringComparator()); + bool isContent = mOwnerContent->AttrValueIs( + kNameSpaceID_None, TypeAttrName(), nsGkAtoms::content, eIgnoreCase); // Force mozbrowser frames to always be typeContent, even if the // mozbrowser interfaces are disabled. @@ -1009,12 +1001,13 @@ nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) { retval = true; - bool is_primary = value.LowerCaseEqualsLiteral("content-primary"); - + bool is_primary = + mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary, + nsGkAtoms::_true, eIgnoreCase); if (aOwner) { mOwnerContent->AddMutationObserver(this); mObservingOwnerContent = true; - aOwner->ContentShellAdded(aItem, is_primary, value); + aOwner->ContentShellAdded(aItem, is_primary); } } @@ -1995,6 +1988,11 @@ nsFrameLoader::StartDestroy() } } + // Destroy the other frame loader owners now that we are being destroyed. + if (mGroupedSessionHistory) { + mGroupedSessionHistory->CloseInactiveFrameLoaderOwners(); + } + nsCOMPtr destroyRunnable = new nsFrameLoaderDestroyRunnable(this); if (mNeedsAsyncDestroy || !doc || NS_FAILED(doc->FinalizeFrameLoader(this, destroyRunnable))) { @@ -2867,12 +2865,8 @@ nsFrameLoader::TryRemoteBrowser() return false; } - nsAutoString value; - mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value); - - if (!value.LowerCaseEqualsLiteral("content") && - !StringBeginsWith(value, NS_LITERAL_STRING("content-"), - nsCaseInsensitiveStringComparator())) { + if (!mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, + nsGkAtoms::content, eIgnoreCase)) { return false; } @@ -3283,7 +3277,8 @@ nsFrameLoader::AttributeChanged(nsIDocument* aDocument, { MOZ_ASSERT(mObservingOwnerContent); - if (aNameSpaceID != kNameSpaceID_None || aAttribute != TypeAttrName()) { + if (aNameSpaceID != kNameSpaceID_None || + (aAttribute != TypeAttrName() && aAttribute != nsGkAtoms::primary)) { return; } @@ -3318,10 +3313,8 @@ nsFrameLoader::AttributeChanged(nsIDocument* aDocument, return; } - nsAutoString value; - aElement->GetAttr(kNameSpaceID_None, TypeAttrName(), value); - - bool is_primary = value.LowerCaseEqualsLiteral("content-primary"); + bool is_primary = + aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary, nsGkAtoms::_true, eIgnoreCase); #ifdef MOZ_XUL // when a content panel is no longer primary, hide any open popups it may have @@ -3333,11 +3326,8 @@ nsFrameLoader::AttributeChanged(nsIDocument* aDocument, #endif parentTreeOwner->ContentShellRemoved(mDocShell); - if (value.LowerCaseEqualsLiteral("content") || - StringBeginsWith(value, NS_LITERAL_STRING("content-"), - nsCaseInsensitiveStringComparator())) { - - parentTreeOwner->ContentShellAdded(mDocShell, is_primary, value); + if (aElement->AttrValueIs(kNameSpaceID_None, TypeAttrName(), nsGkAtoms::content, eIgnoreCase)) { + parentTreeOwner->ContentShellAdded(mDocShell, is_primary); } } @@ -3546,10 +3536,8 @@ nsFrameLoader::MaybeUpdatePrimaryTabParent(TabParentChange aChange) parentTreeOwner->TabParentRemoved(mRemoteBrowser); if (aChange == eTabParentChanged) { bool isPrimary = - mOwnerContent->AttrValueIs(kNameSpaceID_None, - TypeAttrName(), - NS_LITERAL_STRING("content-primary"), - eIgnoreCase); + mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary, + nsGkAtoms::_true, eIgnoreCase); parentTreeOwner->TabParentAdded(mRemoteBrowser, isPrimary); } } diff --git a/dom/base/test/chrome/file_bug1209621.xul b/dom/base/test/chrome/file_bug1209621.xul index 05d81c3fb1e8..989caa303498 100644 --- a/dom/base/test/chrome/file_bug1209621.xul +++ b/dom/base/test/chrome/file_bug1209621.xul @@ -30,43 +30,43 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1209621 ok(treeOwner, "Active docshell should have a TreeOwner!"); is(treeOwner.primaryContentShell, null, - "There shouldn't be primaryContentShell because no browser has type=content-primary."); + "There shouldn't be primaryContentShell because no browser has primary=true."); is(treeOwner.primaryTabParent, null, - "There shouldn't be primaryTabParent because no remote browser has type=content-primary."); + "There shouldn't be primaryTabParent because no remote browser has primary=true."); var ip = document.getElementById("inprocess"); var remote = document.getElementById("remote"); var remote2 = document.getElementById("remote2"); - ip.setAttribute("type", "content-primary"); + ip.setAttribute("primary", "true"); ok(ip.docShell, "non-remote browser should have a DocShell."); is(treeOwner.primaryContentShell, ip.docShell, - "content-primary browser should be the primaryContentShell."); + "primary browser should be the primaryContentShell."); is(treeOwner.primaryTabParent, null, - "There shouldn't be primaryTabParent because no remote browser has type=content-primary."); + "There shouldn't be primaryTabParent because no remote browser has primary=true."); - ip.setAttribute("type", "content"); - remote.setAttribute("type", "content-primary"); + ip.removeAttribute("primary"); + remote.setAttribute("primary", "true"); is(treeOwner.primaryContentShell, null, - "There shouldn't be primaryContentShell because no browser has type=content-primary."); + "There shouldn't be primaryContentShell because no browser has primary=true."); var tp = remote.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.tabParent; ok(tp, "Remote browsers should have a TabParent."); is(treeOwner.primaryTabParent, tp, - "content-primary remote browser should be the primaryTabParent."); + "primary remote browser should be the primaryTabParent."); - remote.setAttribute("type", "content"); + remote.removeAttribute("primary"); is(treeOwner.primaryContentShell, null, - "There shouldn't be primaryContentShell because no browser has type=content-primary."); + "There shouldn't be primaryContentShell because no browser has primary=true."); is(treeOwner.primaryTabParent, null, - "There shouldn't be primaryTabParent because no remote browser has type=content-primary."); + "There shouldn't be primaryTabParent because no remote browser has primary=true."); - remote2.setAttribute("type", "content-primary"); + remote2.setAttribute("primary", "true"); var tp2 = remote2.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.tabParent; ok(tp2, "Remote browsers should have a TabParent."); is(treeOwner.primaryTabParent, tp2, - "content-primary remote browser should be the primaryTabParent."); + "primary remote browser should be the primaryTabParent."); is(treeOwner.primaryContentShell, null, - "There shouldn't be primaryContentShell because no browser has type=content-primary."); + "There shouldn't be primaryContentShell because no browser has primary=true."); opener.setTimeout("done()", 0); window.close(); diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index e74817327f63..9d693fa7d8c9 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -19,10 +19,12 @@ #include "AccessCheck.h" #include "jsfriendapi.h" +#include "nsContentCreatorFunctions.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" #include "nsIDocShell.h" #include "nsIDOMGlobalPropertyInitializer.h" +#include "nsIParserService.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" #include "nsIXPConnect.h" @@ -37,6 +39,7 @@ #include "nsGlobalWindow.h" #include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/CustomElementRegistry.h" #include "mozilla/dom/DOMError.h" #include "mozilla/dom/DOMErrorBinding.h" #include "mozilla/dom/DOMException.h" @@ -44,6 +47,7 @@ #include "mozilla/dom/HTMLObjectElement.h" #include "mozilla/dom/HTMLObjectElementBinding.h" #include "mozilla/dom/HTMLSharedObjectElement.h" +#include "mozilla/dom/HTMLElementBinding.h" #include "mozilla/dom/HTMLEmbedElementBinding.h" #include "mozilla/dom/HTMLAppletElementBinding.h" #include "mozilla/dom/Promise.h" @@ -62,6 +66,30 @@ namespace dom { using namespace workers; +// Forward declare GetConstructorObject methods. +#define HTML_TAG(_tag, _classname, _interfacename) \ +namespace HTML##_interfacename##ElementBinding { \ + JSObject* GetConstructorObject(JSContext*); \ +} +#define HTML_OTHER(_tag) +#include "nsHTMLTagList.h" +#undef HTML_TAG +#undef HTML_OTHER + +typedef JSObject* (*constructorGetterCallback)(JSContext*); + +// Mapping of html tag and GetConstructorObject methods. +#define HTML_TAG(_tag, _classname, _interfacename) HTML##_interfacename##ElementBinding::GetConstructorObject, +#define HTML_OTHER(_tag) nullptr, +// We use eHTMLTag_foo (where foo is the tag) which is defined in nsHTMLTags.h +// to index into this array. +static const constructorGetterCallback sConstructorGetterCallback[] = { + HTMLUnknownElementBinding::GetConstructorObject, +#include "nsHTMLTagList.h" +#undef HTML_TAG +#undef HTML_OTHER +}; + const JSErrorFormatString ErrorFormatString[] = { #define MSG_DEF(_name, _argc, _exn, _str) \ { #_name, _str, _argc, _exn }, @@ -3328,6 +3356,131 @@ GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs, return true; } +// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor +already_AddRefed +CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs, + ErrorResult& aRv) +{ + // Step 1. + nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); + if (!window) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsIDocument* doc = window->GetExtantDoc(); + if (!doc) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + RefPtr registry(window->CustomElements()); + if (!registry) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + // Step 2 is in the code output by CGClassConstructor. + // Step 3. + JSContext* cx = aGlobal.Context(); + JS::Rooted newTarget(cx, &aCallArgs.newTarget().toObject()); + CustomElementDefinition* definition = + registry->LookupCustomElementDefinition(cx, newTarget); + if (!definition) { + aRv.ThrowTypeError(); + return nullptr; + } + + // The callee might be an Xray. Unwrap it to get actual callee. + JS::Rooted callee(cx, js::CheckedUnwrap(&aCallArgs.callee())); + if (!callee) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + + // And the actual callee might be in different compartment, so enter its + // compartment before getting the standard constructor object to compare to, + // so we get it from the same global as callee itself. + JSAutoCompartment ac(cx, callee); + int32_t tag = eHTMLTag_userdefined; + if (!definition->IsCustomBuiltIn()) { + // Step 4. + // If the definition is for an autonomous custom element, the active + // function should be HTMLElement. + JS::Rooted constructor(cx, HTMLElementBinding::GetConstructorObject(cx)); + if (!constructor) { + aRv.NoteJSContextException(cx); + return nullptr; + } + + if (callee != constructor) { + aRv.ThrowTypeError(); + return nullptr; + } + } else { + // Step 5. + // If the definition is for a customized built-in element, the localName + // should be defined in the specification. + nsIParserService* parserService = nsContentUtils::GetParserService(); + if (!parserService) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + tag = parserService->HTMLCaseSensitiveAtomTagToId(definition->mLocalName); + if (tag == eHTMLTag_userdefined) { + aRv.ThrowTypeError(); + return nullptr; + } + + MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds"); + + // If the definition is for a customized built-in element, the active + // function should be the localname's element interface. + constructorGetterCallback cb = sConstructorGetterCallback[tag]; + if (!cb) { + aRv.ThrowTypeError(); + return nullptr; + } + + JS::Rooted constructor(cx, cb(cx)); + if (!constructor) { + aRv.NoteJSContextException(cx); + return nullptr; + } + + if (callee != constructor) { + aRv.ThrowTypeError(); + return nullptr; + } + } + + RefPtr nodeInfo = + doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName, + nullptr, + kNameSpaceID_XHTML, + nsIDOMNode::ELEMENT_NODE); + if (!nodeInfo) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + // Step 6 and Step 7 are in the code output by CGClassConstructor. + // Step 8. + // Construction stack will be implemented in bug 1287348. So we always run + // "construction stack is empty" case for now. + RefPtr element; + if (tag == eHTMLTag_userdefined) { + // Autonomous custom element. + element = NS_NewHTMLElement(nodeInfo.forget()); + } else { + // Customized built-in element. + element = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER); + } + + return element.forget(); +} + #ifdef DEBUG namespace binding_detail { void diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index f52341fcd0af..b41de68de8c3 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -42,6 +42,7 @@ #include "nsWrapperCacheInlines.h" +class nsGenericHTMLElement; class nsIJSID; namespace mozilla { @@ -3180,6 +3181,13 @@ bool GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs, JS::MutableHandle aDesiredProto); +// This function is expected to be called from the constructor function for an +// HTML element interface; the global/callargs need to be whatever was passed to +// that constructor function. +already_AddRefed +CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs, + ErrorResult& aRv); + void SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject, UseCounter aUseCounter); diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index c1df80d15767..4e8440daebaa 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1638,6 +1638,11 @@ DOMInterfaces = { 'register': False, }, +'TestHTMLConstructorInterface' : { + 'headerFile': 'TestBindingHeader.h', + 'register': False, + }, + } # These are temporary, until they've been converted to use new DOM bindings diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 2f8664e3c496..5a922d918f1f 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1717,6 +1717,71 @@ class CGClassConstructor(CGAbstractStaticMethod): else: ctorName = self.descriptor.interface.identifier.name + # [HTMLConstructor] for custom element + # This needs to live in bindings code because it directly examines + # newtarget and the callee function to do HTMLConstructor specific things. + if self._ctor.isHTMLConstructor(): + htmlConstructorSanityCheck = dedent(""" + // The newTarget might be a cross-compartment wrapper. Get the underlying object + // so we can do the spec's object-identity checks. + JS::Rooted newTarget(cx, js::CheckedUnwrap(&args.newTarget().toObject())); + if (!newTarget) { + return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR); + } + + // Step 2 of https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor. + // Enter the compartment of our underlying newTarget object, so we end + // up comparing to the constructor object for our interface from that global. + { + JSAutoCompartment ac(cx, newTarget); + JS::Handle constructor(GetConstructorObjectHandle(cx)); + if (!constructor) { + return false; + } + if (newTarget == constructor) { + return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR); + } + } + + """) + + # If we are unable to get desired prototype from newTarget, then we + # fall back to the interface prototype object from newTarget's realm. + htmlConstructorFallback = dedent(""" + if (!desiredProto) { + // Step 7 of https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor. + // This fallback behavior is designed to match analogous behavior for the + // JavaScript built-ins. So we enter the compartment of our underlying + // newTarget object and fall back to the prototype object from that global. + // XXX The spec says to use GetFunctionRealm(), which is not actually + // the same thing as what we have here (e.g. in the case of scripted callable proxies + // whose target is not same-compartment with the proxy, or bound functions, etc). + // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658 + { + JSAutoCompartment ac(cx, newTarget); + desiredProto = GetProtoObjectHandle(cx); + if (!desiredProto) { + return false; + } + } + + // desiredProto is in the compartment of the underlying newTarget object. + // Wrap it into the context compartment. + if (!JS_WrapObject(cx, &desiredProto)) { + return false; + } + } + """) + else: + htmlConstructorSanityCheck = "" + htmlConstructorFallback = "" + + + # If we're a constructor, "obj" may not be a function, so calling + # XrayAwareCalleeGlobal() on it is not safe. Of course in the + # constructor case either "obj" is an Xray or we're already in the + # content compartment, not the Xray compartment, so just + # constructing the GlobalObject from "obj" is fine. preamble = fill( """ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); @@ -1727,19 +1792,41 @@ class CGClassConstructor(CGAbstractStaticMethod): // Adding more relocations return ThrowConstructorWithoutNew(cx, "${ctorName}"); } + + GlobalObject global(cx, obj); + if (global.Failed()) { + return false; + } + + $*{htmlConstructorSanityCheck} JS::Rooted desiredProto(cx); if (!GetDesiredProto(cx, args, &desiredProto)) { return false; } + $*{htmlConstructorFallback} """, chromeOnlyCheck=chromeOnlyCheck, - ctorName=ctorName) + ctorName=ctorName, + htmlConstructorSanityCheck=htmlConstructorSanityCheck, + htmlConstructorFallback=htmlConstructorFallback) - name = self._ctor.identifier.name - nativeName = MakeNativeName(self.descriptor.binaryNameFor(name)) - callGenerator = CGMethodCall(nativeName, True, self.descriptor, - self._ctor, isConstructor=True, - constructorName=ctorName) + if self._ctor.isHTMLConstructor(): + signatures = self._ctor.signatures() + assert len(signatures) == 1 + # Given that HTMLConstructor takes no args, we can just codegen a + # call to CreateHTMLElement() in BindingUtils which reuses the + # factory thing in HTMLContentSink. Then we don't have to implement + # Constructor on all the HTML elements. + callGenerator = CGPerSignatureCall(signatures[0][0], signatures[0][1], + "CreateHTMLElement", True, + self.descriptor, self._ctor, + isConstructor=True) + else: + name = self._ctor.identifier.name + nativeName = MakeNativeName(self.descriptor.binaryNameFor(name)) + callGenerator = CGMethodCall(nativeName, True, self.descriptor, + self._ctor, isConstructor=True, + constructorName=ctorName) return preamble + "\n" + callGenerator.define() @@ -7272,26 +7359,23 @@ class CGPerSignatureCall(CGThing): argsPre = [] if idlNode.isStatic(): - # If we're a constructor, "obj" may not be a function, so calling - # XrayAwareCalleeGlobal() on it is not safe. Of course in the - # constructor case either "obj" is an Xray or we're already in the - # content compartment, not the Xray compartment, so just - # constructing the GlobalObject from "obj" is fine. - if isConstructor: - objForGlobalObject = "obj" - else: - objForGlobalObject = "xpc::XrayAwareCalleeGlobal(obj)" - cgThings.append(CGGeneric(fill( - """ - GlobalObject global(cx, ${obj}); - if (global.Failed()) { - return false; - } + # If we're a constructor, the GlobalObject struct will be created in + # CGClassConstructor. + if not isConstructor: + cgThings.append(CGGeneric(dedent( + """ + GlobalObject global(cx, xpc::XrayAwareCalleeGlobal(obj)); + if (global.Failed()) { + return false; + } + + """))) - """, - obj=objForGlobalObject))) argsPre.append("global") + if isConstructor and idlNode.isHTMLConstructor(): + argsPre.append("args") + # For JS-implemented interfaces we do not want to base the # needsCx decision on the types involved, just on our extended # attributes. Also, JSContext is not needed for the static case diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index f668d7d6226d..389cd75d4b70 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -1582,7 +1582,7 @@ class IDLInterface(IDLInterfaceOrNamespace): [self.location]) self._noInterfaceObject = True - elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor": + elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": if identifier == "Constructor" and not self.hasInterfaceObject(): raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", [self.location]) @@ -1595,6 +1595,15 @@ class IDLInterface(IDLInterfaceOrNamespace): raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", [self.location]) + if identifier == "HTMLConstructor": + if not self.hasInterfaceObject(): + raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", + [self.location]) + + if not attr.noArguments(): + raise WebIDLError(str(identifier) + " must take no arguments", + [attr.location]) + args = attr.args() if attr.hasArgs() else [] if self.identifier.name == "Promise": @@ -1603,7 +1612,7 @@ class IDLInterface(IDLInterfaceOrNamespace): promiseType = None retType = IDLWrapperType(self.location, self, promiseType) - if identifier == "Constructor" or identifier == "ChromeConstructor": + if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": name = "constructor" allowForbidden = True else: @@ -1614,7 +1623,8 @@ class IDLInterface(IDLInterfaceOrNamespace): allowForbidden=allowForbidden) method = IDLMethod(self.location, methodIdentifier, retType, - args, static=True) + args, static=True, + htmlConstructor=(identifier == "HTMLConstructor")) # Constructors are always NewObject and are always # assumed to be able to throw (since there's no way to # indicate otherwise) and never have any other @@ -1626,7 +1636,7 @@ class IDLInterface(IDLInterfaceOrNamespace): method.addExtendedAttributes( [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) - if identifier == "Constructor" or identifier == "ChromeConstructor": + if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": method.resolve(self) else: # We need to detect conflicts for NamedConstructors across @@ -4508,7 +4518,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): static=False, getter=False, setter=False, creator=False, deleter=False, specialType=NamedOrIndexed.Neither, legacycaller=False, stringifier=False, jsonifier=False, - maplikeOrSetlikeOrIterable=None): + maplikeOrSetlikeOrIterable=None, htmlConstructor=False): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.Tags.Method) @@ -4538,6 +4548,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._jsonifier = jsonifier assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable + assert isinstance(htmlConstructor, bool) + # The identifier of a HTMLConstructor must be 'constructor'. + assert not htmlConstructor or identifier.name == "constructor" + self._htmlConstructor = htmlConstructor self._specialType = specialType self._unforgeable = False self.dependsOn = "Everything" @@ -4638,6 +4652,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self.isStringifier() or self.isJsonifier()) + def isHTMLConstructor(self): + return self._htmlConstructor + def hasOverloads(self): return self._hasOverloads @@ -4693,6 +4710,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert not method.isStringifier() assert not self.isJsonifier() assert not method.isJsonifier() + assert not self.isHTMLConstructor() + assert not method.isHTMLConstructor() return self diff --git a/dom/bindings/parser/tests/test_constructor.py b/dom/bindings/parser/tests/test_constructor.py index 348204c7dc12..6c68a6c79cf1 100644 --- a/dom/bindings/parser/tests/test_constructor.py +++ b/dom/bindings/parser/tests/test_constructor.py @@ -13,7 +13,7 @@ def WebIDLTest(parser, harness): def checkMethod(method, QName, name, signatures, static=True, getter=False, setter=False, creator=False, deleter=False, legacycaller=False, stringifier=False, - chromeOnly=False): + chromeOnly=False, htmlConstructor=False): harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod") harness.ok(method.isMethod(), "Method is a method") @@ -29,6 +29,7 @@ def WebIDLTest(parser, harness): harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly") + harness.check(method.isHTMLConstructor(), htmlConstructor, "Method has the correct htmlConstructor value") harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures") sigpairs = zip(method.signatures(), signatures) @@ -93,6 +94,21 @@ def WebIDLTest(parser, harness): "constructor", [("TestChromeConstructor (Wrapper)", [])], chromeOnly=True) + parser = parser.reset() + parser.parse(""" + [HTMLConstructor] + interface TestHTMLConstructor { + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestHTMLConstructor::constructor", + "constructor", [("TestHTMLConstructor (Wrapper)", [])], + htmlConstructor=True) + parser = parser.reset() threw = False try: @@ -107,3 +123,151 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Can't have both a Constructor and a ChromeConstructor") + + # Test HTMLConstructor with argument + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor(DOMString a)] + interface TestHTMLConstructorWithArgs { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "HTMLConstructor should take no argument") + + # Test HTMLConstructor on a callback interface + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor] + callback interface TestHTMLConstructorOnCallbackInterface { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "HTMLConstructor can't be used on a callback interface") + + # Test HTMLConstructor and Constructor + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Constructor, + HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a Constructor and a HTMLConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + Constructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + Constructor(DOMString a)] + interface TestHTMLConstructorAndConstructor { + }; + """) + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Constructor(DOMString a), + HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + # Test HTMLConstructor and ChromeConstructor + parser = parser.reset() + threw = False + try: + parser.parse(""" + [ChromeConstructor, + HTMLConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + ChromeConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [ChromeConstructor(DOMString a), + HTMLConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + ChromeConstructor(DOMString a)] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") diff --git a/dom/bindings/parser/tests/test_constructor_no_interface_object.py b/dom/bindings/parser/tests/test_constructor_no_interface_object.py index 2b09ae71e695..40708e7870ed 100644 --- a/dom/bindings/parser/tests/test_constructor_no_interface_object.py +++ b/dom/bindings/parser/tests/test_constructor_no_interface_object.py @@ -34,3 +34,36 @@ def WebIDLTest(parser, harness): interface TestNamedConstructorNoInterfaceObject { }; """) + + # Test HTMLConstructor and NoInterfaceObject + parser = parser.reset() + + threw = False + try: + parser.parse(""" + [NoInterfaceObject, HTMLConstructor] + interface TestHTMLConstructorNoInterfaceObject { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + + threw = False + try: + parser.parse(""" + [HTMLConstructor, NoInterfaceObject] + interface TestHTMLConstructorNoInterfaceObject { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index ca5aafdc57dc..9bd3e407f18f 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -1425,6 +1425,12 @@ public: void SetNeedsCallerTypeAttr(bool, CallerType); }; +class TestHTMLConstructorInterface : public nsGenericHTMLElement +{ +public: + virtual nsISupports* GetParentObject(); +}; + } // namespace dom } // namespace mozilla diff --git a/dom/bindings/test/TestCodeGen.webidl b/dom/bindings/test/TestCodeGen.webidl index 4fb9be2706ad..35777f6aa2d3 100644 --- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -1262,3 +1262,7 @@ interface TestWorkerExposedInterface { [NeedsCallerType] void needsCallerTypeMethod(); [NeedsCallerType] attribute boolean needsCallerTypeAttr; }; + +[HTMLConstructor] +interface TestHTMLConstructorInterface { +}; diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp index 8d0d72bf14f5..59843605da5e 100644 --- a/dom/events/EventDispatcher.cpp +++ b/dom/events/EventDispatcher.cpp @@ -1163,7 +1163,10 @@ EventDispatcher::CreateEvent(EventTarget* aOwner, } if (aEventType.LowerCaseEqualsLiteral("storageevent")) { LOG_EVENT_CREATION(STORAGEEVENT); - return NS_NewDOMStorageEvent(aOwner); + RefPtr event = + StorageEvent::Constructor(aOwner, EmptyString(), StorageEventInit()); + event->MarkUninitialized(); + return event.forget(); } #undef LOG_EVENT_CREATION diff --git a/dom/events/StorageEvent.cpp b/dom/events/StorageEvent.cpp index 64332503e8be..6f0b33311dc1 100644 --- a/dom/events/StorageEvent.cpp +++ b/dom/events/StorageEvent.cpp @@ -99,16 +99,3 @@ StorageEvent::InitStorageEvent(const nsAString& aType, bool aCanBubble, } // namespace dom } // namespace mozilla - -using namespace mozilla; -using namespace mozilla::dom; - -already_AddRefed -NS_NewDOMStorageEvent(EventTarget* aOwner) -{ - RefPtr e = new StorageEvent(aOwner); - - e->SetTrusted(e->Init(aOwner)); - return e.forget(); -} - diff --git a/dom/events/StorageEvent.h b/dom/events/StorageEvent.h index 39a107b93924..d8042fec695f 100644 --- a/dom/events/StorageEvent.h +++ b/dom/events/StorageEvent.h @@ -13,10 +13,6 @@ #include "mozilla/dom/Event.h" #include "mozilla/dom/StorageEventBinding.h" -// Helper for EventDispatcher. -already_AddRefed -NS_NewDOMStorageEvent(mozilla::dom::EventTarget* aOwner); - namespace mozilla { namespace dom { diff --git a/dom/events/test/window_bug617528.xul b/dom/events/test/window_bug617528.xul index fc87f9d78813..ea7c9457f10c 100644 --- a/dom/events/test/window_bug617528.xul +++ b/dom/events/test/window_bug617528.xul @@ -3,7 +3,7 @@ - diff --git a/dom/html/nsHTMLContentSink.cpp b/dom/html/nsHTMLContentSink.cpp index 3e8e019b8344..6e808f87e83a 100644 --- a/dom/html/nsHTMLContentSink.cpp +++ b/dom/html/nsHTMLContentSink.cpp @@ -96,14 +96,12 @@ NS_NewHTMLNOTUSEDElement(already_AddRefed&& aNodeInfo, return nullptr; } -#define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element, -#define HTML_HTMLELEMENT_TAG(_tag) NS_NewHTMLElement, +#define HTML_TAG(_tag, _classname, _interfacename) NS_NewHTML##_classname##Element, #define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement, static const contentCreatorCallback sContentCreatorCallbacks[] = { NS_NewHTMLUnknownElement, #include "nsHTMLTagList.h" #undef HTML_TAG -#undef HTML_HTMLELEMENT_TAG #undef HTML_OTHER NS_NewHTMLUnknownElement }; diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 74b7012e2208..051225f34eec 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -601,12 +601,14 @@ parent: sync EnsureLayersConnected(); /** - * Notify parent that one or more entries have been added / removed from - * the child session history. + * Notify the parent that the session history state has been updated. * - * @param aCount the updated number of entries in child session history + * @param aCount + * The updated number of entries in child session history + * @param aLocalIndex + * The local session history index which is loaded. */ - async NotifySessionHistoryChange(uint32_t aCount); + async SHistoryUpdate(uint32_t aCount, uint32_t aLocalIndex, bool aTruncate); /** * When the session history is across multiple root docshells, this function diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index b8eded62f12a..0d529e2016f3 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -661,8 +661,7 @@ TabChild::Init() if (GroupedSHistory::GroupedHistoryEnabled()) { // Set session history listener. - nsCOMPtr shistory; - mWebNav->GetSessionHistory(getter_AddRefs(shistory)); + nsCOMPtr shistory = GetRelatedSHistory(); if (!shistory) { return NS_ERROR_FAILURE; } @@ -1509,8 +1508,7 @@ TabChild::RecvNotifyAttachGroupedSessionHistory(const uint32_t& aOffset) return IPC_FAIL_NO_REASON(this); } - nsCOMPtr shistory; - mWebNav->GetSessionHistory(getter_AddRefs(shistory)); + nsCOMPtr shistory = GetRelatedSHistory(); NS_ENSURE_TRUE(shistory, IPC_FAIL_NO_REASON(this)); if (NS_FAILED(shistory->OnAttachGroupedSessionHistory(aOffset))) { @@ -1528,8 +1526,7 @@ TabChild::RecvNotifyPartialSessionHistoryActive(const uint32_t& aGlobalLength, return IPC_FAIL_NO_REASON(this); } - nsCOMPtr shistory; - mWebNav->GetSessionHistory(getter_AddRefs(shistory)); + nsCOMPtr shistory = GetRelatedSHistory(); NS_ENSURE_TRUE(shistory, IPC_FAIL_NO_REASON(this)); if (NS_FAILED(shistory->OnPartialSessionHistoryActive(aGlobalLength, @@ -1542,8 +1539,7 @@ TabChild::RecvNotifyPartialSessionHistoryActive(const uint32_t& aGlobalLength, mozilla::ipc::IPCResult TabChild::RecvNotifyPartialSessionHistoryDeactive() { - nsCOMPtr shistory; - mWebNav->GetSessionHistory(getter_AddRefs(shistory)); + nsCOMPtr shistory = GetRelatedSHistory(); NS_ENSURE_TRUE(shistory, IPC_FAIL_NO_REASON(this)); if (NS_FAILED(shistory->OnPartialSessionHistoryDeactive())) { @@ -3093,6 +3089,38 @@ TabChild::ForcePaint(uint64_t aLayerObserverEpoch) RecvSetDocShellIsActive(true, false, aLayerObserverEpoch); } +already_AddRefed +TabChild::GetRelatedSHistory() +{ + nsCOMPtr shistory; + mWebNav->GetSessionHistory(getter_AddRefs(shistory)); + return shistory.forget(); +} + +nsresult +TabChildSHistoryListener::SHistoryDidUpdate(bool aTruncate /* = false */) +{ + RefPtr tabChild(mTabChild); + if (NS_WARN_IF(!tabChild)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr shistory = tabChild->GetRelatedSHistory(); + NS_ENSURE_TRUE(shistory, NS_ERROR_FAILURE); + + int32_t index, count; + nsresult rv = shistory->GetIndex(&index); + NS_ENSURE_SUCCESS(rv, rv); + rv = shistory->GetCount(&count); + NS_ENSURE_SUCCESS(rv, rv); + + // XXX: It would be nice if we could batch these updates like SessionStore + // does, and provide a form of `Flush` command which would allow us to trigger + // an update, and wait for the state to become consistent. + NS_ENSURE_TRUE(tabChild->SendSHistoryUpdate(count, index, aTruncate), NS_ERROR_FAILURE); + return NS_OK; +} + /******************************************************************************* * nsISHistoryListener ******************************************************************************/ @@ -3140,19 +3168,15 @@ TabChildSHistoryListener::OnHistoryReplaceEntry(int32_t aIndex) } NS_IMETHODIMP -TabChildSHistoryListener::OnLengthChange(int32_t aCount) +TabChildSHistoryListener::OnLengthChanged(int32_t aCount) { - RefPtr tabChild(mTabChild); - if (!tabChild) { - return NS_ERROR_FAILURE; - } + return SHistoryDidUpdate(/* aTruncate = */ true); +} - if (aCount < 0) { - return NS_ERROR_FAILURE; - } - - return tabChild->SendNotifySessionHistoryChange(aCount) ? - NS_OK : NS_ERROR_FAILURE; +NS_IMETHODIMP +TabChildSHistoryListener::OnIndexChanged(int32_t aIndex) +{ + return SHistoryDidUpdate(/* aTruncate = */ false); } NS_IMETHODIMP diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 650a699f131a..0c87f7bec14a 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -184,6 +184,8 @@ public: NS_DECL_NSIPARTIALSHISTORYLISTENER private: + nsresult SHistoryDidUpdate(bool aTruncate = false); + ~TabChildSHistoryListener() {} TabChild* mTabChild; }; @@ -661,6 +663,8 @@ public: return wasFreshProcess; } + already_AddRefed GetRelatedSHistory(); + protected: virtual ~TabChild(); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 156e4c4d599d..65b474bbdd9b 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -3224,7 +3224,7 @@ TabParent::RecvLookUpDictionary(const nsString& aText, } mozilla::ipc::IPCResult -TabParent::RecvNotifySessionHistoryChange(const uint32_t& aCount) +TabParent::RecvSHistoryUpdate(const uint32_t& aCount, const uint32_t& aLocalIndex, const bool& aTruncate) { RefPtr frameLoader(GetFrameLoader()); if (!frameLoader) { @@ -3240,7 +3240,7 @@ TabParent::RecvNotifySessionHistoryChange(const uint32_t& aCount) return IPC_OK(); } - partialHistory->OnSessionHistoryChange(aCount); + partialHistory->HandleSHistoryUpdate(aCount, aLocalIndex, aTruncate); return IPC_OK(); } diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 4e4ef54a021a..3f85ac2e8c59 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -629,7 +629,9 @@ protected: virtual mozilla::ipc::IPCResult RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel, const bool& aActive) override; - virtual mozilla::ipc::IPCResult RecvNotifySessionHistoryChange(const uint32_t& aCount) override; + virtual mozilla::ipc::IPCResult RecvSHistoryUpdate(const uint32_t& aCount, + const uint32_t& aLocalIndex, + const bool& aTruncate) override; virtual mozilla::ipc::IPCResult RecvRequestCrossBrowserNavigation(const uint32_t& aGlobalIndex) override; diff --git a/dom/media/webaudio/AnalyserNode.cpp b/dom/media/webaudio/AnalyserNode.cpp index 64c3cf4dae76..dcbc1a645b7d 100644 --- a/dom/media/webaudio/AnalyserNode.cpp +++ b/dom/media/webaudio/AnalyserNode.cpp @@ -101,6 +101,45 @@ public: uint32_t mChunksToProcess = 0; }; +/* static */ already_AddRefed +AnalyserNode::Create(AudioContext& aAudioContext, + const AnalyserOptions& aOptions, + ErrorResult& aRv) +{ + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr analyserNode = new AnalyserNode(&aAudioContext); + + analyserNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + analyserNode->SetFftSize(aOptions.mFftSize, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + analyserNode->SetMinDecibels(aOptions.mMinDecibels, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + analyserNode->SetMaxDecibels(aOptions.mMaxDecibels, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + analyserNode->SetSmoothingTimeConstant(aOptions.mSmoothingTimeConstant, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return analyserNode.forget(); +} + AnalyserNode::AnalyserNode(AudioContext* aContext) : AudioNode(aContext, 1, diff --git a/dom/media/webaudio/AnalyserNode.h b/dom/media/webaudio/AnalyserNode.h index 7fca5df6fe5c..8ca85441b1e0 100644 --- a/dom/media/webaudio/AnalyserNode.h +++ b/dom/media/webaudio/AnalyserNode.h @@ -15,16 +15,26 @@ namespace mozilla { namespace dom { class AudioContext; +struct AnalyserOptions; class AnalyserNode final : public AudioNode { public: - explicit AnalyserNode(AudioContext* aContext); + static already_AddRefed + Create(AudioContext& aAudioContext, const AnalyserOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const AnalyserOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + void GetFloatFrequencyData(const Float32Array& aArray); void GetByteFrequencyData(const Uint8Array& aArray); void GetFloatTimeDomainData(const Float32Array& aArray); @@ -62,10 +72,9 @@ public: virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - ~AnalyserNode() {} - private: + ~AnalyserNode() = default; + friend class AnalyserNodeEngine; void AppendChunk(const AudioChunk& aChunk); bool AllocateBuffer(); @@ -74,6 +83,8 @@ private: void GetTimeDomainData(float* aData, size_t aLength); private: + explicit AnalyserNode(AudioContext* aContext); + FFTBlock mAnalysisBlock; nsTArray mChunks; double mMinDecibels; diff --git a/dom/media/webaudio/AudioBuffer.cpp b/dom/media/webaudio/AudioBuffer.cpp index cb834f6a594e..1726270864d5 100644 --- a/dom/media/webaudio/AudioBuffer.cpp +++ b/dom/media/webaudio/AudioBuffer.cpp @@ -180,6 +180,24 @@ AudioBuffer::~AudioBuffer() mozilla::DropJSObjects(this); } +/* static */ already_AddRefed +AudioBuffer::Constructor(const GlobalObject& aGlobal, + AudioContext& aAudioContext, + const AudioBufferOptions& aOptions, + ErrorResult& aRv) +{ + if (!aOptions.mNumberOfChannels) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return nullptr; + } + + float sampleRate = aOptions.mSampleRate.WasPassed() + ? aOptions.mSampleRate.Value() + : aAudioContext.SampleRate(); + return Create(&aAudioContext, aOptions.mNumberOfChannels, aOptions.mLength, + sampleRate, aRv); +} + void AudioBuffer::ClearJSChannels() { diff --git a/dom/media/webaudio/AudioBuffer.h b/dom/media/webaudio/AudioBuffer.h index 2f2aef5fe85e..c74cfe4549bd 100644 --- a/dom/media/webaudio/AudioBuffer.h +++ b/dom/media/webaudio/AudioBuffer.h @@ -24,6 +24,7 @@ class ThreadSharedFloatArrayBufferList; namespace dom { +struct AudioBufferOptions; class AudioContext; /** @@ -56,6 +57,10 @@ public: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioBuffer) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioBuffer) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const AudioBufferOptions& aOptions, ErrorResult& aRv); + nsPIDOMWindowInner* GetParentObject() const { nsCOMPtr parentObject = do_QueryReferent(mOwnerWindow); @@ -134,4 +139,3 @@ protected: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/AudioBufferSourceNode.cpp b/dom/media/webaudio/AudioBufferSourceNode.cpp index 51b6bab4a22b..2878c8c628ec 100644 --- a/dom/media/webaudio/AudioBufferSourceNode.cpp +++ b/dom/media/webaudio/AudioBufferSourceNode.cpp @@ -608,10 +608,30 @@ AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext) mStream->AddMainThreadListener(this); } -AudioBufferSourceNode::~AudioBufferSourceNode() +/* static */ already_AddRefed +AudioBufferSourceNode::Create(JSContext* aCx, AudioContext& aAudioContext, + const AudioBufferSourceOptions& aOptions, + ErrorResult& aRv) { -} + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + RefPtr audioNode = new AudioBufferSourceNode(&aAudioContext); + + if (aOptions.mBuffer.WasPassed()) { + MOZ_ASSERT(aCx); + audioNode->SetBuffer(aCx, aOptions.mBuffer.Value()); + } + + audioNode->Detune()->SetValue(aOptions.mDetune); + audioNode->SetLoop(aOptions.mLoop); + audioNode->SetLoopEnd(aOptions.mLoopEnd); + audioNode->SetLoopStart(aOptions.mLoopStart); + audioNode->PlaybackRate()->SetValue(aOptions.mPlaybackRate); + + return audioNode.forget(); +} void AudioBufferSourceNode::DestroyMediaStream() { diff --git a/dom/media/webaudio/AudioBufferSourceNode.h b/dom/media/webaudio/AudioBufferSourceNode.h index d982ec5cce81..1011cd219bab 100644 --- a/dom/media/webaudio/AudioBufferSourceNode.h +++ b/dom/media/webaudio/AudioBufferSourceNode.h @@ -13,13 +13,16 @@ namespace mozilla { namespace dom { +struct AudioBufferSourceOptions; class AudioParam; -class AudioBufferSourceNode final : public AudioNode, - public MainThreadMediaStreamListener +class AudioBufferSourceNode final : public AudioNode + , public MainThreadMediaStreamListener { public: - explicit AudioBufferSourceNode(AudioContext* aContext); + static already_AddRefed + Create(JSContext* aCx, AudioContext& aAudioContext, + const AudioBufferSourceOptions& aOptions, ErrorResult& aRv); void DestroyMediaStream() override; @@ -34,6 +37,13 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioBufferSourceNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const AudioBufferSourceOptions& aOptions, ErrorResult& aRv) + { + return Create(aGlobal.Context(), aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; void Start(double aWhen, double aOffset, @@ -99,10 +109,10 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~AudioBufferSourceNode(); - private: + explicit AudioBufferSourceNode(AudioContext* aContext); + ~AudioBufferSourceNode() = default; + friend class AudioBufferSourceNodeEngine; // START is sent during Start(). // STOP is sent during Stop(). @@ -130,7 +140,6 @@ private: void SendBufferParameterToStream(JSContext* aCx); void SendOffsetAndDurationParametersToStream(AudioNodeStream* aStream); -private: double mLoopStart; double mLoopEnd; double mOffset; @@ -146,4 +155,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index e3bdf7616039..b71b4029f395 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -12,10 +12,26 @@ #include "mozilla/OwningNonNull.h" #include "mozilla/dom/AnalyserNode.h" +#include "mozilla/dom/AnalyserNodeBinding.h" +#include "mozilla/dom/AudioBufferSourceNodeBinding.h" #include "mozilla/dom/AudioContextBinding.h" +#include "mozilla/dom/BiquadFilterNodeBinding.h" +#include "mozilla/dom/ChannelMergerNodeBinding.h" +#include "mozilla/dom/ChannelSplitterNodeBinding.h" +#include "mozilla/dom/ConvolverNodeBinding.h" +#include "mozilla/dom/DelayNodeBinding.h" +#include "mozilla/dom/DynamicsCompressorNodeBinding.h" +#include "mozilla/dom/GainNodeBinding.h" +#include "mozilla/dom/IIRFilterNodeBinding.h" #include "mozilla/dom/HTMLMediaElement.h" +#include "mozilla/dom/MediaElementAudioSourceNodeBinding.h" +#include "mozilla/dom/MediaStreamAudioSourceNodeBinding.h" #include "mozilla/dom/OfflineAudioContextBinding.h" +#include "mozilla/dom/OscillatorNodeBinding.h" +#include "mozilla/dom/PannerNodeBinding.h" #include "mozilla/dom/Promise.h" +#include "mozilla/dom/StereoPannerNodeBinding.h" +#include "mozilla/dom/WaveShaperNodeBinding.h" #include "AudioBuffer.h" #include "AudioBufferSourceNode.h" @@ -241,13 +257,9 @@ bool AudioContext::CheckClosed(ErrorResult& aRv) already_AddRefed AudioContext::CreateBufferSource(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr bufferNode = - new AudioBufferSourceNode(this); - return bufferNode.forget(); + return AudioBufferSourceNode::Create(nullptr, *this, + AudioBufferSourceOptions(), + aRv); } already_AddRefed @@ -299,18 +311,8 @@ bool IsValidBufferSize(uint32_t aBufferSize) { already_AddRefed AudioContext::CreateMediaStreamDestination(ErrorResult& aRv) { - if (mIsOffline) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } - - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr node = - new MediaStreamAudioDestinationNode(this); - return node.forget(); + return MediaStreamAudioDestinationNode::Create(*this, AudioNodeOptions(), + aRv); } already_AddRefed @@ -340,186 +342,93 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize, already_AddRefed AudioContext::CreateAnalyser(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr analyserNode = new AnalyserNode(this); - return analyserNode.forget(); + return AnalyserNode::Create(*this, AnalyserOptions(), aRv); } already_AddRefed AudioContext::CreateStereoPanner(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr stereoPannerNode = new StereoPannerNode(this); - return stereoPannerNode.forget(); + return StereoPannerNode::Create(*this, StereoPannerOptions(), aRv); } already_AddRefed AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement, ErrorResult& aRv) { - if (mIsOffline) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } + MediaElementAudioSourceOptions options; + options.mMediaElement = aMediaElement; - if (aMediaElement.ContainsRestrictedContent()) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } - - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr stream = - aMediaElement.CaptureAudio(aRv, mDestination->Stream()->Graph()); - if (aRv.Failed()) { - return nullptr; - } - return MediaElementAudioSourceNode::Create(this, stream, aRv); + return MediaElementAudioSourceNode::Create(*this, options, aRv); } already_AddRefed AudioContext::CreateMediaStreamSource(DOMMediaStream& aMediaStream, ErrorResult& aRv) { - if (mIsOffline) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } + MediaStreamAudioSourceOptions options; + options.mMediaStream = aMediaStream; - if (CheckClosed(aRv)) { - return nullptr; - } - - return MediaStreamAudioSourceNode::Create(this, &aMediaStream, aRv); + return MediaStreamAudioSourceNode::Create(*this, options, aRv); } already_AddRefed AudioContext::CreateGain(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr gainNode = new GainNode(this); - return gainNode.forget(); + return GainNode::Create(*this, GainOptions(), aRv); } already_AddRefed AudioContext::CreateWaveShaper(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr waveShaperNode = new WaveShaperNode(this); - return waveShaperNode.forget(); + return WaveShaperNode::Create(*this, WaveShaperOptions(), aRv); } already_AddRefed AudioContext::CreateDelay(double aMaxDelayTime, ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - if (aMaxDelayTime > 0. && aMaxDelayTime < 180.) { - RefPtr delayNode = new DelayNode(this, aMaxDelayTime); - return delayNode.forget(); - } - - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; + DelayOptions options; + options.mMaxDelayTime = aMaxDelayTime; + return DelayNode::Create(*this, options, aRv); } already_AddRefed AudioContext::CreatePanner(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr pannerNode = new PannerNode(this); - mPannerNodes.PutEntry(pannerNode); - return pannerNode.forget(); + return PannerNode::Create(*this, PannerOptions(), aRv); } already_AddRefed AudioContext::CreateConvolver(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr convolverNode = new ConvolverNode(this); - return convolverNode.forget(); + return ConvolverNode::Create(nullptr, *this, ConvolverOptions(), aRv); } already_AddRefed AudioContext::CreateChannelSplitter(uint32_t aNumberOfOutputs, ErrorResult& aRv) { - if (aNumberOfOutputs == 0 || - aNumberOfOutputs > WebAudioUtils::MaxChannelCount) { - aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); - return nullptr; - } - - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr splitterNode = - new ChannelSplitterNode(this, aNumberOfOutputs); - return splitterNode.forget(); + ChannelSplitterOptions options; + options.mNumberOfOutputs = aNumberOfOutputs; + return ChannelSplitterNode::Create(*this, options, aRv); } already_AddRefed AudioContext::CreateChannelMerger(uint32_t aNumberOfInputs, ErrorResult& aRv) { - if (aNumberOfInputs == 0 || - aNumberOfInputs > WebAudioUtils::MaxChannelCount) { - aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); - return nullptr; - } - - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr mergerNode = - new ChannelMergerNode(this, aNumberOfInputs); - return mergerNode.forget(); + ChannelMergerOptions options; + options.mNumberOfInputs = aNumberOfInputs; + return ChannelMergerNode::Create(*this, options, aRv); } already_AddRefed AudioContext::CreateDynamicsCompressor(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr compressorNode = - new DynamicsCompressorNode(this); - return compressorNode.forget(); + return DynamicsCompressorNode::Create(*this, DynamicsCompressorOptions(), aRv); } already_AddRefed AudioContext::CreateBiquadFilter(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr filterNode = - new BiquadFilterNode(this); - return filterNode.forget(); + return BiquadFilterNode::Create(*this, BiquadFilterOptions(), aRv); } already_AddRefed @@ -527,47 +436,16 @@ AudioContext::CreateIIRFilter(const mozilla::dom::binding_detail::AutoSequence& aFeedback, mozilla::ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - if (aFeedforward.Length() == 0 || aFeedforward.Length() > 20) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } - - if (aFeedback.Length() == 0 || aFeedback.Length() > 20) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } - - bool feedforwardAllZeros = true; - for (size_t i = 0; i < aFeedforward.Length(); ++i) { - if (aFeedforward.Elements()[i] != 0.0) { - feedforwardAllZeros = false; - } - } - - if (feedforwardAllZeros || aFeedback.Elements()[0] == 0.0) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return nullptr; - } - - RefPtr filterNode = - new IIRFilterNode(this, aFeedforward, aFeedback); - return filterNode.forget(); + IIRFilterOptions options; + options.mFeedforward = aFeedforward; + options.mFeedback = aFeedback; + return IIRFilterNode::Create(*this, options, aRv); } already_AddRefed AudioContext::CreateOscillator(ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - - RefPtr oscillatorNode = - new OscillatorNode(this); - return oscillatorNode.forget(); + return OscillatorNode::Create(*this, OscillatorOptions(), aRv); } already_AddRefed diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 069efa9863aa..ac66aeabfab0 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -323,6 +323,8 @@ public: IMPL_EVENT_HANDLER(mozinterruptbegin) IMPL_EVENT_HANDLER(mozinterruptend) + bool CheckClosed(ErrorResult& aRv); + private: void DisconnectFromWindow(); void RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob); @@ -333,8 +335,6 @@ private: friend struct ::mozilla::WebAudioDecodeJob; - bool CheckClosed(ErrorResult& aRv); - nsTArray GetAllStreams() const; private: diff --git a/dom/media/webaudio/AudioNode.cpp b/dom/media/webaudio/AudioNode.cpp index 2b64fcf880dc..5c3530d8b7cc 100644 --- a/dom/media/webaudio/AudioNode.cpp +++ b/dom/media/webaudio/AudioNode.cpp @@ -72,6 +72,28 @@ AudioNode::~AudioNode() } } +void +AudioNode::Initialize(const AudioNodeOptions& aOptions, ErrorResult& aRv) +{ + if (aOptions.mChannelCount.WasPassed()) { + SetChannelCount(aOptions.mChannelCount.Value(), aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + } + + if (aOptions.mChannelCountMode.WasPassed()) { + SetChannelCountModeValue(aOptions.mChannelCountMode.Value(), aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + } + + if (aOptions.mChannelInterpretation.WasPassed()) { + SetChannelInterpretationValue(aOptions.mChannelInterpretation.Value()); + } +} + size_t AudioNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { diff --git a/dom/media/webaudio/AudioNode.h b/dom/media/webaudio/AudioNode.h index ebef129c83ea..c3b6183ad4e2 100644 --- a/dom/media/webaudio/AudioNode.h +++ b/dom/media/webaudio/AudioNode.h @@ -251,6 +251,9 @@ private: bool DisconnectFromOutputIfConnected(uint32_t aOutputIndex, uint32_t aInputIndex); protected: + // Helper for the Constructors for nodes. + void Initialize(const AudioNodeOptions& aOptions, ErrorResult& aRv); + // Helpers for sending different value types to streams void SendDoubleParameterToStream(uint32_t aIndex, double aValue); void SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue); diff --git a/dom/media/webaudio/BiquadFilterNode.cpp b/dom/media/webaudio/BiquadFilterNode.cpp index 0c8c05586b3d..a853d8d4739b 100644 --- a/dom/media/webaudio/BiquadFilterNode.cpp +++ b/dom/media/webaudio/BiquadFilterNode.cpp @@ -263,8 +263,29 @@ BiquadFilterNode::BiquadFilterNode(AudioContext* aContext) aContext->Graph()); } -BiquadFilterNode::~BiquadFilterNode() +/* static */ already_AddRefed +BiquadFilterNode::Create(AudioContext& aAudioContext, + const BiquadFilterOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr audioNode = new BiquadFilterNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + audioNode->SetType(aOptions.mType); + audioNode->Q()->SetValue(aOptions.mQ); + audioNode->Detune()->SetValue(aOptions.mDetune); + audioNode->Frequency()->SetValue(aOptions.mFrequency); + audioNode->Gain()->SetValue(aOptions.mGain); + + return audioNode.forget(); } size_t diff --git a/dom/media/webaudio/BiquadFilterNode.h b/dom/media/webaudio/BiquadFilterNode.h index f81c623f0b1e..cb56c27ded0a 100644 --- a/dom/media/webaudio/BiquadFilterNode.h +++ b/dom/media/webaudio/BiquadFilterNode.h @@ -15,15 +15,25 @@ namespace mozilla { namespace dom { class AudioContext; +struct BiquadFilterOptions; class BiquadFilterNode final : public AudioNode { public: - explicit BiquadFilterNode(AudioContext* aContext); + static already_AddRefed + Create(AudioContext& aAudioContext, const BiquadFilterOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BiquadFilterNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const BiquadFilterOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; BiquadFilterType Type() const @@ -64,10 +74,10 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~BiquadFilterNode(); - private: + explicit BiquadFilterNode(AudioContext* aContext); + ~BiquadFilterNode() = default; + BiquadFilterType mType; RefPtr mFrequency; RefPtr mDetune; @@ -79,4 +89,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/ChannelMergerNode.cpp b/dom/media/webaudio/ChannelMergerNode.cpp index 7b63a98a602c..5c14e6915124 100644 --- a/dom/media/webaudio/ChannelMergerNode.cpp +++ b/dom/media/webaudio/ChannelMergerNode.cpp @@ -75,8 +75,30 @@ ChannelMergerNode::ChannelMergerNode(AudioContext* aContext, aContext->Graph()); } -ChannelMergerNode::~ChannelMergerNode() +/* static */ already_AddRefed +ChannelMergerNode::Create(AudioContext& aAudioContext, + const ChannelMergerOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + if (aOptions.mNumberOfInputs == 0 || + aOptions.mNumberOfInputs > WebAudioUtils::MaxChannelCount) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return nullptr; + } + + RefPtr audioNode = + new ChannelMergerNode(&aAudioContext, aOptions.mNumberOfInputs); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return audioNode.forget(); } JSObject* @@ -87,4 +109,3 @@ ChannelMergerNode::WrapObject(JSContext* aCx, JS::Handle aGivenProto) } // namespace dom } // namespace mozilla - diff --git a/dom/media/webaudio/ChannelMergerNode.h b/dom/media/webaudio/ChannelMergerNode.h index d064c8e236be..5acf831919ec 100644 --- a/dom/media/webaudio/ChannelMergerNode.h +++ b/dom/media/webaudio/ChannelMergerNode.h @@ -13,15 +13,24 @@ namespace mozilla { namespace dom { class AudioContext; +struct ChannelMergerOptions; class ChannelMergerNode final : public AudioNode { public: - ChannelMergerNode(AudioContext* aContext, - uint16_t aInputCount); + static already_AddRefed + Create(AudioContext& aAudioContext, const ChannelMergerOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const ChannelMergerOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; uint16_t NumberOfInputs() const override { return mInputCount; } @@ -36,10 +45,11 @@ public: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } -protected: - virtual ~ChannelMergerNode(); - private: + ChannelMergerNode(AudioContext* aContext, + uint16_t aInputCount); + ~ChannelMergerNode() = default; + const uint16_t mInputCount; }; @@ -47,4 +57,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/ChannelSplitterNode.cpp b/dom/media/webaudio/ChannelSplitterNode.cpp index 34a414d1648c..988a9eccd91f 100644 --- a/dom/media/webaudio/ChannelSplitterNode.cpp +++ b/dom/media/webaudio/ChannelSplitterNode.cpp @@ -66,8 +66,30 @@ ChannelSplitterNode::ChannelSplitterNode(AudioContext* aContext, aContext->Graph()); } -ChannelSplitterNode::~ChannelSplitterNode() +/* static */ already_AddRefed +ChannelSplitterNode::Create(AudioContext& aAudioContext, + const ChannelSplitterOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + if (aOptions.mNumberOfOutputs == 0 || + aOptions.mNumberOfOutputs > WebAudioUtils::MaxChannelCount) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return nullptr; + } + + RefPtr audioNode = + new ChannelSplitterNode(&aAudioContext, aOptions.mNumberOfOutputs); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return audioNode.forget(); } JSObject* @@ -78,4 +100,3 @@ ChannelSplitterNode::WrapObject(JSContext* aCx, JS::Handle aGivenProt } // namespace dom } // namespace mozilla - diff --git a/dom/media/webaudio/ChannelSplitterNode.h b/dom/media/webaudio/ChannelSplitterNode.h index 3b267eccc50a..da2be388ca24 100644 --- a/dom/media/webaudio/ChannelSplitterNode.h +++ b/dom/media/webaudio/ChannelSplitterNode.h @@ -13,15 +13,24 @@ namespace mozilla { namespace dom { class AudioContext; +struct ChannelSplitterOptions; class ChannelSplitterNode final : public AudioNode { public: - ChannelSplitterNode(AudioContext* aContext, - uint16_t aOutputCount); + static already_AddRefed + Create(AudioContext& aAudioContext, const ChannelSplitterOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const ChannelSplitterOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; uint16_t NumberOfOutputs() const override { return mOutputCount; } @@ -36,10 +45,11 @@ public: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } -protected: - virtual ~ChannelSplitterNode(); - private: + ChannelSplitterNode(AudioContext* aContext, + uint16_t aOutputCount); + ~ChannelSplitterNode() = default; + const uint16_t mOutputCount; }; @@ -47,4 +57,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/ConvolverNode.cpp b/dom/media/webaudio/ConvolverNode.cpp index 314cdf7cf63a..2b99f2ca3ae1 100644 --- a/dom/media/webaudio/ConvolverNode.cpp +++ b/dom/media/webaudio/ConvolverNode.cpp @@ -204,8 +204,34 @@ ConvolverNode::ConvolverNode(AudioContext* aContext) aContext->Graph()); } -ConvolverNode::~ConvolverNode() +/* static */ already_AddRefed +ConvolverNode::Create(JSContext* aCx, AudioContext& aAudioContext, + const ConvolverOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr audioNode = new ConvolverNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + // This must be done before setting the buffer. + audioNode->SetNormalize(!aOptions.mDisableNormalization); + + if (aOptions.mBuffer.WasPassed()) { + MOZ_ASSERT(aCx); + audioNode->SetBuffer(aCx, aOptions.mBuffer.Value(), aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + } + + return audioNode.forget(); } size_t @@ -292,4 +318,3 @@ ConvolverNode::SetNormalize(bool aNormalize) } // namespace dom } // namespace mozilla - diff --git a/dom/media/webaudio/ConvolverNode.h b/dom/media/webaudio/ConvolverNode.h index 53cff9d273c5..4539272510ad 100644 --- a/dom/media/webaudio/ConvolverNode.h +++ b/dom/media/webaudio/ConvolverNode.h @@ -13,14 +13,26 @@ namespace mozilla { namespace dom { +class AudioContext; +struct ConvolverOptions; + class ConvolverNode final : public AudioNode { public: - explicit ConvolverNode(AudioContext* aContext); + static already_AddRefed + Create(JSContext* aCx, AudioContext& aAudioContext, + const ConvolverOptions& aOptions, ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ConvolverNode, AudioNode); + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const ConvolverOptions& aOptions, ErrorResult& aRv) + { + return Create(aGlobal.Context(), aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; AudioBuffer* GetBuffer(JSContext* aCx) const @@ -28,7 +40,7 @@ public: return mBuffer; } - void SetBuffer(JSContext* aCx, AudioBuffer* aBufferi, ErrorResult& aRv); + void SetBuffer(JSContext* aCx, AudioBuffer* aBuffer, ErrorResult& aRv); bool Normalize() const { @@ -62,10 +74,10 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~ConvolverNode(); - private: + explicit ConvolverNode(AudioContext* aContext); + ~ConvolverNode() = default; + RefPtr mBuffer; bool mNormalize; }; @@ -75,4 +87,3 @@ private: } //end namespace mozilla #endif - diff --git a/dom/media/webaudio/DelayNode.cpp b/dom/media/webaudio/DelayNode.cpp index 17dc7251446f..a67a91364ec4 100644 --- a/dom/media/webaudio/DelayNode.cpp +++ b/dom/media/webaudio/DelayNode.cpp @@ -206,8 +206,30 @@ DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay) aContext->Graph()); } -DelayNode::~DelayNode() +/* static */ already_AddRefed +DelayNode::Create(AudioContext& aAudioContext, + const DelayOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + if (aOptions.mMaxDelayTime <= 0. || aOptions.mMaxDelayTime >= 180.) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + + RefPtr audioNode = new DelayNode(&aAudioContext, + aOptions.mMaxDelayTime); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + audioNode->DelayTime()->SetValue(aOptions.mDelayTime); + return audioNode.forget(); } size_t diff --git a/dom/media/webaudio/DelayNode.h b/dom/media/webaudio/DelayNode.h index dfee970bc34f..1eaf6f787a02 100644 --- a/dom/media/webaudio/DelayNode.h +++ b/dom/media/webaudio/DelayNode.h @@ -14,15 +14,25 @@ namespace mozilla { namespace dom { class AudioContext; +struct DelayOptions; class DelayNode final : public AudioNode { public: - DelayNode(AudioContext* aContext, double aMaxDelay); + static already_AddRefed + Create(AudioContext& aAudioContext, const DelayOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DelayNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const DelayOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; AudioParam* DelayTime() const @@ -38,13 +48,12 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~DelayNode(); - private: + DelayNode(AudioContext* aContext, double aMaxDelay); + ~DelayNode() = default; + friend class DelayNodeEngine; -private: RefPtr mDelay; }; @@ -52,4 +61,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/DynamicsCompressorNode.cpp b/dom/media/webaudio/DynamicsCompressorNode.cpp index 3a3dc98491eb..1f02121ee899 100644 --- a/dom/media/webaudio/DynamicsCompressorNode.cpp +++ b/dom/media/webaudio/DynamicsCompressorNode.cpp @@ -205,8 +205,30 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext) aContext->Graph()); } -DynamicsCompressorNode::~DynamicsCompressorNode() +/* static */ already_AddRefed +DynamicsCompressorNode::Create(AudioContext& aAudioContext, + const DynamicsCompressorOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr audioNode = + new DynamicsCompressorNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + audioNode->Attack()->SetValue(aOptions.mAttack); + audioNode->Knee()->SetValue(aOptions.mKnee); + audioNode->Ratio()->SetValue(aOptions.mRatio); + audioNode->GetRelease()->SetValue(aOptions.mRelease); + audioNode->Threshold()->SetValue(aOptions.mThreshold); + + return audioNode.forget(); } size_t diff --git a/dom/media/webaudio/DynamicsCompressorNode.h b/dom/media/webaudio/DynamicsCompressorNode.h index 5bdd5f2d04fe..5018fea14ea4 100644 --- a/dom/media/webaudio/DynamicsCompressorNode.h +++ b/dom/media/webaudio/DynamicsCompressorNode.h @@ -14,15 +14,25 @@ namespace mozilla { namespace dom { class AudioContext; +struct DynamicsCompressorOptions; class DynamicsCompressorNode final : public AudioNode { public: - explicit DynamicsCompressorNode(AudioContext* aContext); + static already_AddRefed + Create(AudioContext& aAudioContext, const DynamicsCompressorOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DynamicsCompressorNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const DynamicsCompressorOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; AudioParam* Threshold() const @@ -70,10 +80,10 @@ public: mReduction = aReduction; } -protected: - virtual ~DynamicsCompressorNode(); - private: + explicit DynamicsCompressorNode(AudioContext* aContext); + ~DynamicsCompressorNode() = default; + RefPtr mThreshold; RefPtr mKnee; RefPtr mRatio; @@ -86,4 +96,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/GainNode.cpp b/dom/media/webaudio/GainNode.cpp index 46ac997638cc..775169f286f9 100644 --- a/dom/media/webaudio/GainNode.cpp +++ b/dom/media/webaudio/GainNode.cpp @@ -128,8 +128,24 @@ GainNode::GainNode(AudioContext* aContext) aContext->Graph()); } -GainNode::~GainNode() +/* static */ already_AddRefed +GainNode::Create(AudioContext& aAudioContext, + const GainOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr audioNode = new GainNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + audioNode->Gain()->SetValue(aOptions.mGain); + return audioNode.forget(); } size_t diff --git a/dom/media/webaudio/GainNode.h b/dom/media/webaudio/GainNode.h index aab22ad65eb7..349e81713383 100644 --- a/dom/media/webaudio/GainNode.h +++ b/dom/media/webaudio/GainNode.h @@ -14,15 +14,25 @@ namespace mozilla { namespace dom { class AudioContext; +struct GainOptions; class GainNode final : public AudioNode { public: - explicit GainNode(AudioContext* aContext); + static already_AddRefed + Create(AudioContext& aAudioContext, const GainOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GainNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const GainOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; AudioParam* Gain() const @@ -38,10 +48,10 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~GainNode(); - private: + explicit GainNode(AudioContext* aContext); + ~GainNode() = default; + RefPtr mGain; }; @@ -49,4 +59,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/IIRFilterNode.cpp b/dom/media/webaudio/IIRFilterNode.cpp index 3a69a94c8c70..e5c4c1b28702 100644 --- a/dom/media/webaudio/IIRFilterNode.cpp +++ b/dom/media/webaudio/IIRFilterNode.cpp @@ -133,8 +133,8 @@ private: }; IIRFilterNode::IIRFilterNode(AudioContext* aContext, - const mozilla::dom::binding_detail::AutoSequence& aFeedforward, - const mozilla::dom::binding_detail::AutoSequence& aFeedback) + const Sequence& aFeedforward, + const Sequence& aFeedback) : AudioNode(aContext, 2, ChannelCountMode::Max, @@ -168,8 +168,46 @@ IIRFilterNode::IIRFilterNode(AudioContext* aContext, aContext->Graph()); } -IIRFilterNode::~IIRFilterNode() +/* static */ already_AddRefed +IIRFilterNode::Create(AudioContext& aAudioContext, + const IIRFilterOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + if (aOptions.mFeedforward.Length() == 0 || aOptions.mFeedforward.Length() > 20) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + + if (aOptions.mFeedback.Length() == 0 || aOptions.mFeedback.Length() > 20) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + + bool feedforwardAllZeros = true; + for (size_t i = 0; i < aOptions.mFeedforward.Length(); ++i) { + if (aOptions.mFeedforward.Elements()[i] != 0.0) { + feedforwardAllZeros = false; + } + } + + if (feedforwardAllZeros || aOptions.mFeedback.Elements()[0] == 0.0) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + RefPtr audioNode = + new IIRFilterNode(&aAudioContext, aOptions.mFeedforward, aOptions.mFeedback); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return audioNode.forget(); } size_t diff --git a/dom/media/webaudio/IIRFilterNode.h b/dom/media/webaudio/IIRFilterNode.h index 78546c3e5473..a0d08d9854ed 100644 --- a/dom/media/webaudio/IIRFilterNode.h +++ b/dom/media/webaudio/IIRFilterNode.h @@ -15,18 +15,25 @@ namespace mozilla { namespace dom { class AudioContext; +struct IIRFilterOptions; class IIRFilterNode final : public AudioNode { public: - explicit IIRFilterNode(AudioContext* aContext, - const mozilla::dom::binding_detail::AutoSequence& aFeedforward, - const mozilla::dom::binding_detail::AutoSequence& aFeedback); + static already_AddRefed + Create(AudioContext& aAudioContext, const IIRFilterOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED - JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const IIRFilterOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; void GetFrequencyResponse(const Float32Array& aFrequencyHz, const Float32Array& aMagResponse, @@ -40,16 +47,17 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~IIRFilterNode(); - private: - nsTArray mFeedback; - nsTArray mFeedforward; + IIRFilterNode(AudioContext* aContext, + const Sequence& aFeedforward, + const Sequence& aFeedback); + ~IIRFilterNode() = default; + + nsTArray mFeedback; + nsTArray mFeedforward; }; } // namespace dom } // namespace mozilla #endif - diff --git a/dom/media/webaudio/MediaElementAudioSourceNode.cpp b/dom/media/webaudio/MediaElementAudioSourceNode.cpp index ebf7dc44f516..4ba3cb0e6495 100644 --- a/dom/media/webaudio/MediaElementAudioSourceNode.cpp +++ b/dom/media/webaudio/MediaElementAudioSourceNode.cpp @@ -16,13 +16,34 @@ MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext* aContext) } /* static */ already_AddRefed -MediaElementAudioSourceNode::Create(AudioContext* aContext, - DOMMediaStream* aStream, ErrorResult& aRv) +MediaElementAudioSourceNode::Create(AudioContext& aAudioContext, + const MediaElementAudioSourceOptions& aOptions, + ErrorResult& aRv) { - RefPtr node = - new MediaElementAudioSourceNode(aContext); + if (aAudioContext.IsOffline()) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } - node->Init(aStream, aRv); + if (aOptions.mMediaElement->ContainsRestrictedContent()) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr node = + new MediaElementAudioSourceNode(&aAudioContext); + + RefPtr stream = + aOptions.mMediaElement->CaptureAudio(aRv, aAudioContext.Destination()->Stream()->Graph()); + if (aRv.Failed()) { + return nullptr; + } + + node->Init(stream, aRv); if (aRv.Failed()) { return nullptr; } diff --git a/dom/media/webaudio/MediaElementAudioSourceNode.h b/dom/media/webaudio/MediaElementAudioSourceNode.h index f6791f355afb..7d8e19d69376 100644 --- a/dom/media/webaudio/MediaElementAudioSourceNode.h +++ b/dom/media/webaudio/MediaElementAudioSourceNode.h @@ -12,11 +12,23 @@ namespace mozilla { namespace dom { +class AudioContext; +struct MediaElementAudioSourceOptions; + class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode { public: static already_AddRefed - Create(AudioContext* aContext, DOMMediaStream* aStream, ErrorResult& aRv); + Create(AudioContext& aAudioContext, + const MediaElementAudioSourceOptions& aOptions, + ErrorResult& aRv); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const MediaElementAudioSourceOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; diff --git a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp index d8c732e472d0..d7f32176ee56 100644 --- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp +++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp @@ -16,7 +16,7 @@ namespace mozilla { namespace dom { -class AudioDestinationTrackSource : +class AudioDestinationTrackSource final : public MediaStreamTrackSource { public: @@ -50,7 +50,7 @@ public: } private: - virtual ~AudioDestinationTrackSource() {} + ~AudioDestinationTrackSource() = default; RefPtr mNode; }; @@ -102,8 +102,29 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* a mPort = outputStream->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK); } -MediaStreamAudioDestinationNode::~MediaStreamAudioDestinationNode() +/* static */ already_AddRefed +MediaStreamAudioDestinationNode::Create(AudioContext& aAudioContext, + const AudioNodeOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.IsOffline()) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr audioNode = + new MediaStreamAudioDestinationNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return audioNode.forget(); } size_t diff --git a/dom/media/webaudio/MediaStreamAudioDestinationNode.h b/dom/media/webaudio/MediaStreamAudioDestinationNode.h index 6c033b46608d..cfc14225cbe5 100644 --- a/dom/media/webaudio/MediaStreamAudioDestinationNode.h +++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.h @@ -12,14 +12,26 @@ namespace mozilla { namespace dom { +class AudioContext; +struct AudioNodeOptions; + class MediaStreamAudioDestinationNode final : public AudioNode { public: - explicit MediaStreamAudioDestinationNode(AudioContext* aContext); + static already_AddRefed + Create(AudioContext& aAudioContext, const AudioNodeOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamAudioDestinationNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const AudioNodeOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; uint16_t NumberOfOutputs() const final override @@ -42,10 +54,10 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~MediaStreamAudioDestinationNode(); - private: + explicit MediaStreamAudioDestinationNode(AudioContext* aContext); + ~MediaStreamAudioDestinationNode() = default; + RefPtr mDOMStream; RefPtr mPort; }; diff --git a/dom/media/webaudio/MediaStreamAudioSourceNode.cpp b/dom/media/webaudio/MediaStreamAudioSourceNode.cpp index beedd5300476..a64b7f9ef1a9 100644 --- a/dom/media/webaudio/MediaStreamAudioSourceNode.cpp +++ b/dom/media/webaudio/MediaStreamAudioSourceNode.cpp @@ -43,13 +43,23 @@ MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AudioContext* aContext) } /* static */ already_AddRefed -MediaStreamAudioSourceNode::Create(AudioContext* aContext, - DOMMediaStream* aStream, ErrorResult& aRv) +MediaStreamAudioSourceNode::Create(AudioContext& aAudioContext, + const MediaStreamAudioSourceOptions& aOptions, + ErrorResult& aRv) { - RefPtr node = - new MediaStreamAudioSourceNode(aContext); + if (aAudioContext.IsOffline()) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } - node->Init(aStream, aRv); + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr node = + new MediaStreamAudioSourceNode(&aAudioContext); + + node->Init(aOptions.mMediaStream, aRv); if (aRv.Failed()) { return nullptr; } diff --git a/dom/media/webaudio/MediaStreamAudioSourceNode.h b/dom/media/webaudio/MediaStreamAudioSourceNode.h index 5383eb2c6a77..8f3f7a5781bf 100644 --- a/dom/media/webaudio/MediaStreamAudioSourceNode.h +++ b/dom/media/webaudio/MediaStreamAudioSourceNode.h @@ -15,6 +15,9 @@ namespace mozilla { namespace dom { +class AudioContext; +struct MediaStreamAudioSourceOptions; + class MediaStreamAudioSourceNodeEngine final : public AudioNodeEngine { public: @@ -46,11 +49,19 @@ class MediaStreamAudioSourceNode : public AudioNode, { public: static already_AddRefed - Create(AudioContext* aContext, DOMMediaStream* aStream, ErrorResult& aRv); + Create(AudioContext& aContext, const MediaStreamAudioSourceOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamAudioSourceNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const MediaStreamAudioSourceOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; void DestroyMediaStream() override; diff --git a/dom/media/webaudio/OscillatorNode.cpp b/dom/media/webaudio/OscillatorNode.cpp index 8e7c103a9456..63a27d3345b0 100644 --- a/dom/media/webaudio/OscillatorNode.cpp +++ b/dom/media/webaudio/OscillatorNode.cpp @@ -426,8 +426,35 @@ OscillatorNode::OscillatorNode(AudioContext* aContext) mStream->AddMainThreadListener(this); } -OscillatorNode::~OscillatorNode() +/* static */ already_AddRefed +OscillatorNode::Create(AudioContext& aAudioContext, + const OscillatorOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr audioNode = new OscillatorNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + audioNode->SetType(aOptions.mType, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + audioNode->Frequency()->SetValue(aOptions.mFrequency); + audioNode->Detune()->SetValue(aOptions.mDetune); + + if (aOptions.mPeriodicWave.WasPassed()) { + audioNode->SetPeriodicWave(aOptions.mPeriodicWave.Value()); + } + + return audioNode.forget(); } size_t diff --git a/dom/media/webaudio/OscillatorNode.h b/dom/media/webaudio/OscillatorNode.h index 1e17e319e830..580a22ca0529 100644 --- a/dom/media/webaudio/OscillatorNode.h +++ b/dom/media/webaudio/OscillatorNode.h @@ -16,16 +16,26 @@ namespace mozilla { namespace dom { class AudioContext; +struct OscillatorOptions; class OscillatorNode final : public AudioNode, public MainThreadMediaStreamListener { public: - explicit OscillatorNode(AudioContext* aContext); + static already_AddRefed + Create(AudioContext& aAudioContext, const OscillatorOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OscillatorNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const OscillatorOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; void DestroyMediaStream() override; @@ -82,14 +92,13 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~OscillatorNode(); - private: + explicit OscillatorNode(AudioContext* aContext); + ~OscillatorNode() = default; + void SendTypeToStream(); void SendPeriodicWaveToStream(); -private: OscillatorType mType; RefPtr mPeriodicWave; RefPtr mFrequency; @@ -101,4 +110,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/PannerNode.cpp b/dom/media/webaudio/PannerNode.cpp index 7696e984ef4e..a7c2a609911f 100644 --- a/dom/media/webaudio/PannerNode.cpp +++ b/dom/media/webaudio/PannerNode.cpp @@ -330,6 +330,38 @@ PannerNode::~PannerNode() } } +/* static */ already_AddRefed +PannerNode::Create(AudioContext& aAudioContext, + const PannerOptions& aOptions, + ErrorResult& aRv) +{ + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr audioNode = new PannerNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + audioNode->SetPanningModel(aOptions.mPanningModel); + audioNode->SetDistanceModel(aOptions.mDistanceModel); + audioNode->SetPosition(aOptions.mPositionX, aOptions.mPositionY, + aOptions.mPositionZ); + audioNode->SetOrientation(aOptions.mOrientationX, aOptions.mOrientationY, + aOptions.mOrientationZ); + audioNode->SetRefDistance(aOptions.mRefDistance); + audioNode->SetMaxDistance(aOptions.mMaxDistance); + audioNode->SetRolloffFactor(aOptions.mRolloffFactor); + audioNode->SetConeInnerAngle(aOptions.mConeInnerAngle); + audioNode->SetConeOuterAngle(aOptions.mConeOuterAngle); + audioNode->SetConeOuterGain(aOptions.mConeOuterGain); + + return audioNode.forget(); +} + void PannerNode::SetPanningModel(PanningModelType aPanningModel) { mPanningModel = aPanningModel; @@ -783,4 +815,3 @@ PannerNode::SendDopplerToSourcesIfNeeded() } // namespace dom } // namespace mozilla - diff --git a/dom/media/webaudio/PannerNode.h b/dom/media/webaudio/PannerNode.h index 184db4603691..8ab6bb103306 100644 --- a/dom/media/webaudio/PannerNode.h +++ b/dom/media/webaudio/PannerNode.h @@ -20,13 +20,24 @@ namespace dom { class AudioContext; class AudioBufferSourceNode; +struct PannerOptions; class PannerNode final : public AudioNode, public SupportsWeakPtr { public: + static already_AddRefed + Create(AudioContext& aAudioContext, const PannerOptions& aOptions, + ErrorResult& aRv); + MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PannerNode) - explicit PannerNode(AudioContext* aContext); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const PannerOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -230,10 +241,10 @@ public: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~PannerNode(); - private: + explicit PannerNode(AudioContext* aContext); + ~PannerNode(); + friend class AudioListener; friend class PannerNodeEngine; enum EngineParameters { @@ -293,4 +304,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/PeriodicWave.cpp b/dom/media/webaudio/PeriodicWave.cpp index 396a93e138ca..0e1cf71d3322 100644 --- a/dom/media/webaudio/PeriodicWave.cpp +++ b/dom/media/webaudio/PeriodicWave.cpp @@ -44,6 +44,32 @@ PeriodicWave::PeriodicWave(AudioContext* aContext, mCoefficients->SetData(1, nullptr, free, buffer+aLength); } +/* static */ already_AddRefed +PeriodicWave::Constructor(const GlobalObject& aGlobal, + AudioContext& aAudioContext, + const PeriodicWaveOptions& aOptions, + ErrorResult& aRv) +{ + if (!aOptions.mReal.WasPassed() || !aOptions.mImag.WasPassed() || + aOptions.mReal.Value().Length() != aOptions.mImag.Value().Length() || + aOptions.mReal.Value().Length() == 0) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + + RefPtr wave = + new PeriodicWave(&aAudioContext, aOptions.mReal.Value().Elements(), + aOptions.mImag.Value().Elements(), + aOptions.mReal.Value().Length(), + aOptions.mDisableNormalization, + aRv); + if (aRv.Failed()) { + return nullptr; + } + + return wave.forget(); +} + size_t PeriodicWave::SizeOfExcludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const { @@ -71,4 +97,3 @@ PeriodicWave::WrapObject(JSContext* aCx, JS::Handle aGivenProto) } // namespace dom } // namespace mozilla - diff --git a/dom/media/webaudio/PeriodicWave.h b/dom/media/webaudio/PeriodicWave.h index b67d597e4d50..ef500d18eb1c 100644 --- a/dom/media/webaudio/PeriodicWave.h +++ b/dom/media/webaudio/PeriodicWave.h @@ -17,6 +17,9 @@ namespace mozilla { namespace dom { +class AudioContext; +struct PeriodicWaveOptions; + class PeriodicWave final : public nsWrapperCache { public: @@ -30,6 +33,10 @@ public: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PeriodicWave) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(PeriodicWave) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const PeriodicWaveOptions& aOptions, ErrorResult& aRv); + AudioContext* GetParentObject() const { return mContext; @@ -56,7 +63,7 @@ public: size_t SizeOfIncludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const; private: - ~PeriodicWave() {} + ~PeriodicWave() = default; RefPtr mContext; RefPtr mCoefficients; diff --git a/dom/media/webaudio/StereoPannerNode.cpp b/dom/media/webaudio/StereoPannerNode.cpp index fc804e7b4765..04f7b7591a08 100644 --- a/dom/media/webaudio/StereoPannerNode.cpp +++ b/dom/media/webaudio/StereoPannerNode.cpp @@ -183,8 +183,24 @@ StereoPannerNode::StereoPannerNode(AudioContext* aContext) aContext->Graph()); } -StereoPannerNode::~StereoPannerNode() +/* static */ already_AddRefed +StereoPannerNode::Create(AudioContext& aAudioContext, + const StereoPannerOptions& aOptions, + ErrorResult& aRv) { + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } + + RefPtr audioNode = new StereoPannerNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + audioNode->Pan()->SetValue(aOptions.mPan); + return audioNode.forget(); } size_t diff --git a/dom/media/webaudio/StereoPannerNode.h b/dom/media/webaudio/StereoPannerNode.h index 68204f757159..4e4df434b039 100644 --- a/dom/media/webaudio/StereoPannerNode.h +++ b/dom/media/webaudio/StereoPannerNode.h @@ -14,12 +14,23 @@ namespace mozilla { namespace dom { class AudioContext; +struct StereoPannerOptions; class StereoPannerNode final : public AudioNode { public: + static already_AddRefed + Create(AudioContext& aAudioContext, const StereoPannerOptions& aOptions, + ErrorResult& aRv); + MOZ_DECLARE_REFCOUNTED_TYPENAME(StereoPannerNode) - explicit StereoPannerNode(AudioContext* aContext); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const StereoPannerOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -56,10 +67,10 @@ public: virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; -protected: - virtual ~StereoPannerNode(); - private: + explicit StereoPannerNode(AudioContext* aContext); + ~StereoPannerNode() = default; + RefPtr mPan; }; @@ -67,4 +78,3 @@ private: } // namespace mozilla #endif - diff --git a/dom/media/webaudio/WaveShaperNode.cpp b/dom/media/webaudio/WaveShaperNode.cpp index d5c617dcd4df..648108c23ad7 100644 --- a/dom/media/webaudio/WaveShaperNode.cpp +++ b/dom/media/webaudio/WaveShaperNode.cpp @@ -19,7 +19,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(WaveShaperNode) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WaveShaperNode, AudioNode) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER - tmp->ClearCurve(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WaveShaperNode, AudioNode) @@ -28,7 +27,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WaveShaperNode) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCurve) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WaveShaperNode) @@ -315,27 +313,39 @@ WaveShaperNode::WaveShaperNode(AudioContext* aContext) 2, ChannelCountMode::Max, ChannelInterpretation::Speakers) - , mCurve(nullptr) , mType(OverSampleType::None) { - mozilla::HoldJSObjects(this); - WaveShaperNodeEngine* engine = new WaveShaperNodeEngine(this); mStream = AudioNodeStream::Create(aContext, engine, AudioNodeStream::NO_STREAM_FLAGS, aContext->Graph()); } -WaveShaperNode::~WaveShaperNode() +/* static */ already_AddRefed +WaveShaperNode::Create(AudioContext& aAudioContext, + const WaveShaperOptions& aOptions, + ErrorResult& aRv) { - ClearCurve(); -} + if (aAudioContext.CheckClosed(aRv)) { + return nullptr; + } -void -WaveShaperNode::ClearCurve() -{ - mCurve = nullptr; - mozilla::DropJSObjects(this); + RefPtr audioNode = new WaveShaperNode(&aAudioContext); + + audioNode->Initialize(aOptions, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + if (aOptions.mCurve.WasPassed()) { + audioNode->SetCurveInternal(aOptions.mCurve.Value(), aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + } + + audioNode->SetOversample(aOptions.mOversample); + return audioNode.forget(); } JSObject* @@ -347,45 +357,85 @@ WaveShaperNode::WrapObject(JSContext *aCx, JS::Handle aGivenProto) void WaveShaperNode::SetCurve(const Nullable& aCurve, ErrorResult& aRv) { - nsTArray curve; - if (!aCurve.IsNull()) { - const Float32Array& floats = aCurve.Value(); + // Let's purge the cached value for the curve attribute. + WaveShaperNodeBinding::ClearCachedCurveValue(this); - floats.ComputeLengthAndData(); - if (floats.IsShared()) { - // Throw if the object is mapping shared memory (must opt in). - aRv.ThrowTypeError(NS_LITERAL_STRING("Argument of WaveShaperNode.setCurve")); - return; - } - - uint32_t argLength = floats.Length(); - if (argLength < 2) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return; - } - - if (!curve.SetLength(argLength, fallible)) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - PodCopy(curve.Elements(), floats.Data(), floats.Length()); - - mCurve = floats.Obj(); - } else { - mCurve = nullptr; + if (aCurve.IsNull()) { + CleanCurveInternal(); + return; } + const Float32Array& floats = aCurve.Value(); + + floats.ComputeLengthAndData(); + if (floats.IsShared()) { + // Throw if the object is mapping shared memory (must opt in). + aRv.ThrowTypeError(NS_LITERAL_STRING("Argument of WaveShaperNode.setCurve")); + return; + } + + nsTArray curve; + uint32_t argLength = floats.Length(); + if (!curve.SetLength(argLength, fallible)) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + + PodCopy(curve.Elements(), floats.Data(), argLength); + SetCurveInternal(curve, aRv); +} + +void +WaveShaperNode::SetCurveInternal(const nsTArray& aCurve, + ErrorResult& aRv) +{ + if (aCurve.Length() < 2) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + + mCurve = aCurve; + SendCurveToStream(); +} + +void +WaveShaperNode::CleanCurveInternal() +{ + mCurve.Clear(); + SendCurveToStream(); +} + +void +WaveShaperNode::SendCurveToStream() +{ AudioNodeStream* ns = mStream; MOZ_ASSERT(ns, "Why don't we have a stream here?"); - ns->SetRawArrayData(curve); + + nsTArray copyCurve(mCurve); + ns->SetRawArrayData(copyCurve); +} + +void +WaveShaperNode::GetCurve(JSContext* aCx, + JS::MutableHandle aRetval) +{ + // Let's return a null value if the list is empty. + if (mCurve.IsEmpty()) { + aRetval.set(nullptr); + return; + } + + MOZ_ASSERT(mCurve.Length() >= 2); + aRetval.set(Float32Array::Create(aCx, this, mCurve.Length(), + mCurve.Elements())); } void WaveShaperNode::SetOversample(OverSampleType aType) { mType = aType; - SendInt32ParameterToStream(WaveShaperNodeEngine::TYPE, static_cast(aType)); + SendInt32ParameterToStream(WaveShaperNodeEngine::TYPE, + static_cast(aType)); } } // namespace dom diff --git a/dom/media/webaudio/WaveShaperNode.h b/dom/media/webaudio/WaveShaperNode.h index b58841ee6943..b2e86c687abd 100644 --- a/dom/media/webaudio/WaveShaperNode.h +++ b/dom/media/webaudio/WaveShaperNode.h @@ -15,21 +15,28 @@ namespace mozilla { namespace dom { class AudioContext; +struct WaveShaperOptions; class WaveShaperNode final : public AudioNode { public: - explicit WaveShaperNode(AudioContext *aContext); + static already_AddRefed + Create(AudioContext& aAudioContext, const WaveShaperOptions& aOptions, + ErrorResult& aRv); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WaveShaperNode, AudioNode) + static already_AddRefed + Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext, + const WaveShaperOptions& aOptions, ErrorResult& aRv) + { + return Create(aAudioContext, aOptions, aRv); + } + JSObject* WrapObject(JSContext *aCx, JS::Handle aGivenProto) override; - void GetCurve(JSContext* aCx, JS::MutableHandle aRetval) const - { - aRetval.set(mCurve); - } + void GetCurve(JSContext* aCx, JS::MutableHandle aRetval); void SetCurve(const Nullable& aData, ErrorResult& aRv); OverSampleType Oversample() const @@ -55,14 +62,17 @@ public: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } -protected: - virtual ~WaveShaperNode(); - private: - void ClearCurve(); + explicit WaveShaperNode(AudioContext *aContext); + ~WaveShaperNode() = default; -private: - JS::Heap mCurve; + void SetCurveInternal(const nsTArray& aCurve, + ErrorResult& aRv); + void CleanCurveInternal(); + + void SendCurveToStream(); + + nsTArray mCurve; OverSampleType mType; }; diff --git a/dom/media/webaudio/test/test_analyserNode.html b/dom/media/webaudio/test/test_analyserNode.html index 7af67a5a5634..5d0e44eba391 100644 --- a/dom/media/webaudio/test/test_analyserNode.html +++ b/dom/media/webaudio/test/test_analyserNode.html @@ -10,9 +10,7 @@
 
+  
+
+
+Bug 1274159
+
+
+
+
+
+
+
+
diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor_chrome.html b/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor_chrome.html
new file mode 100644
index 000000000000..8c7ec0ac6b59
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor_chrome.html
@@ -0,0 +1,41 @@
+
+
+
+
+  Test HTMLConstructor for custom elements.
+  
+  
+
+
+Bug 1274159
+
+
+
+
+
+
+
+
diff --git a/dom/tests/moz.build b/dom/tests/moz.build
index f7c3e2437c16..7fc81abbde05 100644
--- a/dom/tests/moz.build
+++ b/dom/tests/moz.build
@@ -37,6 +37,7 @@ MOCHITEST_CHROME_MANIFESTS += [
     'mochitest/geolocation/chrome.ini',
     'mochitest/localstorage/chrome.ini',
     'mochitest/sessionstorage/chrome.ini',
+    'mochitest/webcomponents/chrome.ini',
     'mochitest/whatwg/chrome.ini',
 ]
 
diff --git a/dom/webidl/AccessibleNode.webidl b/dom/webidl/AccessibleNode.webidl
index 544fe06304aa..442f1a18ba43 100644
--- a/dom/webidl/AccessibleNode.webidl
+++ b/dom/webidl/AccessibleNode.webidl
@@ -10,4 +10,6 @@ interface AccessibleNode {
   [Frozen, Cached, Pure]
   readonly attribute sequence states;
   readonly attribute Node? DOMNode;
+
+  boolean is(DOMString... states);
 };
diff --git a/dom/webidl/AnalyserNode.webidl b/dom/webidl/AnalyserNode.webidl
index 5b4be8822810..eabf4836ddd6 100644
--- a/dom/webidl/AnalyserNode.webidl
+++ b/dom/webidl/AnalyserNode.webidl
@@ -10,7 +10,15 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary AnalyserOptions : AudioNodeOptions {
+             unsigned long fftSize = 2048;
+             float         maxDecibels = -30;
+             float         minDecibels = -100;
+             float         smoothingTimeConstant = 0.8;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional AnalyserOptions options)]
 interface AnalyserNode : AudioNode {
 
     // Real-time frequency-domain data
@@ -38,4 +46,3 @@ interface AnalyserNode : AudioNode {
 
 // Mozilla extension
 AnalyserNode implements AudioNodePassThrough;
-
diff --git a/dom/webidl/AudioBuffer.webidl b/dom/webidl/AudioBuffer.webidl
index ab45268f3921..19f91b12f347 100644
--- a/dom/webidl/AudioBuffer.webidl
+++ b/dom/webidl/AudioBuffer.webidl
@@ -10,7 +10,14 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary AudioBufferOptions {
+             unsigned long numberOfChannels = 1;
+    required unsigned long length;
+             float         sampleRate;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, AudioBufferOptions options)]
 interface AudioBuffer {
 
     readonly attribute float sampleRate;
@@ -29,4 +36,3 @@ interface AudioBuffer {
     [Throws]
     void copyToChannel(Float32Array source, long channelNumber, optional unsigned long startInChannel = 0);
 };
-
diff --git a/dom/webidl/AudioBufferSourceNode.webidl b/dom/webidl/AudioBufferSourceNode.webidl
index f74a968ec212..98ecae076b97 100644
--- a/dom/webidl/AudioBufferSourceNode.webidl
+++ b/dom/webidl/AudioBufferSourceNode.webidl
@@ -10,7 +10,17 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary AudioBufferSourceOptions {
+             AudioBuffer? buffer;
+             float        detune = 0;
+             boolean      loop = false;
+             double       loopEnd = 0;
+             double       loopStart = 0;
+             float        playbackRate = 1;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional AudioBufferSourceOptions options)]
 interface AudioBufferSourceNode : AudioNode {
 
     attribute AudioBuffer? buffer;
diff --git a/dom/webidl/AudioNode.webidl b/dom/webidl/AudioNode.webidl
index d6aa577c0120..f851b9ea3511 100644
--- a/dom/webidl/AudioNode.webidl
+++ b/dom/webidl/AudioNode.webidl
@@ -21,6 +21,12 @@ enum ChannelInterpretation {
     "discrete"
 };
 
+dictionary AudioNodeOptions {
+             unsigned long         channelCount;
+             ChannelCountMode      channelCountMode;
+             ChannelInterpretation channelInterpretation;
+};
+
 [Pref="dom.webaudio.enabled"]
 interface AudioNode : EventTarget {
 
diff --git a/dom/webidl/BiquadFilterNode.webidl b/dom/webidl/BiquadFilterNode.webidl
index 7a9efb77de80..714fd2a0abe6 100644
--- a/dom/webidl/BiquadFilterNode.webidl
+++ b/dom/webidl/BiquadFilterNode.webidl
@@ -21,7 +21,16 @@ enum BiquadFilterType {
   "allpass"
 };
 
-[Pref="dom.webaudio.enabled"]
+dictionary BiquadFilterOptions : AudioNodeOptions {
+             BiquadFilterType type = "lowpass";
+             float            Q = 1;
+             float            detune = 0;
+             float            frequency = 350;
+             float            gain = 0;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional BiquadFilterOptions options)]
 interface BiquadFilterNode : AudioNode {
 
     attribute BiquadFilterType type;
diff --git a/dom/webidl/ChannelMergerNode.webidl b/dom/webidl/ChannelMergerNode.webidl
index a1a7148f2c0f..9fa5ca9cec95 100644
--- a/dom/webidl/ChannelMergerNode.webidl
+++ b/dom/webidl/ChannelMergerNode.webidl
@@ -10,8 +10,11 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
-interface ChannelMergerNode : AudioNode {
-
+dictionary ChannelMergerOptions : AudioNodeOptions {
+             unsigned long numberOfInputs = 6;
 };
 
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional ChannelMergerOptions options)]
+interface ChannelMergerNode : AudioNode {
+};
diff --git a/dom/webidl/ChannelSplitterNode.webidl b/dom/webidl/ChannelSplitterNode.webidl
index c7c0be4983a2..0b025569300f 100644
--- a/dom/webidl/ChannelSplitterNode.webidl
+++ b/dom/webidl/ChannelSplitterNode.webidl
@@ -10,7 +10,12 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary ChannelSplitterOptions : AudioNodeOptions {
+             unsigned long numberOfOutputs = 6;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional ChannelSplitterOptions options)]
 interface ChannelSplitterNode : AudioNode {
 
 };
diff --git a/dom/webidl/ConvolverNode.webidl b/dom/webidl/ConvolverNode.webidl
index b49af04002c1..ea8378ed926c 100644
--- a/dom/webidl/ConvolverNode.webidl
+++ b/dom/webidl/ConvolverNode.webidl
@@ -10,7 +10,13 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary ConvolverOptions : AudioNodeOptions {
+             AudioBuffer? buffer;
+             boolean      disableNormalization = false;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional ConvolverOptions options)]
 interface ConvolverNode : AudioNode {
 
       [SetterThrows]
diff --git a/dom/webidl/DelayNode.webidl b/dom/webidl/DelayNode.webidl
index 6a8fb5c3ae71..203a50c79f82 100644
--- a/dom/webidl/DelayNode.webidl
+++ b/dom/webidl/DelayNode.webidl
@@ -10,7 +10,13 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary DelayOptions : AudioNodeOptions {
+             double maxDelayTime = 1;
+             double delayTime = 0;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional DelayOptions options)]
 interface DelayNode : AudioNode {
 
     readonly attribute AudioParam delayTime;
diff --git a/dom/webidl/DynamicsCompressorNode.webidl b/dom/webidl/DynamicsCompressorNode.webidl
index dc0e46f63a94..0b1874396324 100644
--- a/dom/webidl/DynamicsCompressorNode.webidl
+++ b/dom/webidl/DynamicsCompressorNode.webidl
@@ -10,7 +10,16 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary DynamicsCompressorOptions : AudioNodeOptions {
+             float attack = 0.003;
+             float knee = 30;
+             float ratio = 12;
+             float release = 0.25;
+             float threshold = -24;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional DynamicsCompressorOptions options)]
 interface DynamicsCompressorNode : AudioNode {
 
     readonly attribute AudioParam threshold; // in Decibels
diff --git a/dom/webidl/GainNode.webidl b/dom/webidl/GainNode.webidl
index 143325c70fdb..efc531ae0e91 100644
--- a/dom/webidl/GainNode.webidl
+++ b/dom/webidl/GainNode.webidl
@@ -10,7 +10,12 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary GainOptions : AudioNodeOptions {
+             float gain = 1.0;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional GainOptions options)]
 interface GainNode : AudioNode {
 
     readonly attribute AudioParam gain;
diff --git a/dom/webidl/HTMLAnchorElement.webidl b/dom/webidl/HTMLAnchorElement.webidl
index 0b8ded6d7347..aa8e7d082122 100644
--- a/dom/webidl/HTMLAnchorElement.webidl
+++ b/dom/webidl/HTMLAnchorElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-a-element
+[HTMLConstructor]
 interface HTMLAnchorElement : HTMLElement {
            [SetterThrows]
            attribute DOMString target;
diff --git a/dom/webidl/HTMLAreaElement.webidl b/dom/webidl/HTMLAreaElement.webidl
index be3f3788522a..113f1822ec0f 100644
--- a/dom/webidl/HTMLAreaElement.webidl
+++ b/dom/webidl/HTMLAreaElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-area-element
+[HTMLConstructor]
 interface HTMLAreaElement : HTMLElement {
            [SetterThrows]
            attribute DOMString alt;
diff --git a/dom/webidl/HTMLAudioElement.webidl b/dom/webidl/HTMLAudioElement.webidl
index 8537453c0c48..72566983945a 100644
--- a/dom/webidl/HTMLAudioElement.webidl
+++ b/dom/webidl/HTMLAudioElement.webidl
@@ -11,6 +11,6 @@
  * and create derivative works of this document.
  */
 
-[NamedConstructor=Audio(optional DOMString src)]
+[HTMLConstructor, NamedConstructor=Audio(optional DOMString src)]
 interface HTMLAudioElement : HTMLMediaElement {};
 
diff --git a/dom/webidl/HTMLBRElement.webidl b/dom/webidl/HTMLBRElement.webidl
index cf5cb8a6757b..07b8d9f0d9be 100644
--- a/dom/webidl/HTMLBRElement.webidl
+++ b/dom/webidl/HTMLBRElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-br-element
+[HTMLConstructor]
 interface HTMLBRElement : HTMLElement {};
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
diff --git a/dom/webidl/HTMLBaseElement.webidl b/dom/webidl/HTMLBaseElement.webidl
index d982f46547aa..bc43e0570d31 100644
--- a/dom/webidl/HTMLBaseElement.webidl
+++ b/dom/webidl/HTMLBaseElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-base-element
+[HTMLConstructor]
 interface HTMLBaseElement : HTMLElement {
            [SetterThrows, Pure]
            attribute DOMString href;
diff --git a/dom/webidl/HTMLBodyElement.webidl b/dom/webidl/HTMLBodyElement.webidl
index 95df2d43a7b1..e177584913c3 100644
--- a/dom/webidl/HTMLBodyElement.webidl
+++ b/dom/webidl/HTMLBodyElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLBodyElement : HTMLElement {
 };
 
diff --git a/dom/webidl/HTMLButtonElement.webidl b/dom/webidl/HTMLButtonElement.webidl
index c50e09ae070d..de0b154563dc 100644
--- a/dom/webidl/HTMLButtonElement.webidl
+++ b/dom/webidl/HTMLButtonElement.webidl
@@ -11,6 +11,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-button-element
+[HTMLConstructor]
 interface HTMLButtonElement : HTMLElement {
   [SetterThrows, Pure]
            attribute boolean autofocus;
diff --git a/dom/webidl/HTMLCanvasElement.webidl b/dom/webidl/HTMLCanvasElement.webidl
index 55737b8f8242..858eb09f7497 100644
--- a/dom/webidl/HTMLCanvasElement.webidl
+++ b/dom/webidl/HTMLCanvasElement.webidl
@@ -13,6 +13,7 @@
 interface nsISupports;
 interface Variant;
 
+[HTMLConstructor]
 interface HTMLCanvasElement : HTMLElement {
   [Pure, SetterThrows]
            attribute unsigned long width;
diff --git a/dom/webidl/HTMLDListElement.webidl b/dom/webidl/HTMLDListElement.webidl
index 08020a497009..4e3fa88d8185 100644
--- a/dom/webidl/HTMLDListElement.webidl
+++ b/dom/webidl/HTMLDListElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-dl-element
+[HTMLConstructor]
 interface HTMLDListElement : HTMLElement {
 };
 
diff --git a/dom/webidl/HTMLDataElement.webidl b/dom/webidl/HTMLDataElement.webidl
index 821b8b483e6e..6b9a7f19ad93 100644
--- a/dom/webidl/HTMLDataElement.webidl
+++ b/dom/webidl/HTMLDataElement.webidl
@@ -7,6 +7,7 @@
  * http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-data-element
  */
 
+[HTMLConstructor]
 interface HTMLDataElement : HTMLElement {
            [SetterThrows]
            attribute DOMString value;
diff --git a/dom/webidl/HTMLDataListElement.webidl b/dom/webidl/HTMLDataListElement.webidl
index 83b20cd2bc31..4c38fddf375f 100644
--- a/dom/webidl/HTMLDataListElement.webidl
+++ b/dom/webidl/HTMLDataListElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLDataListElement : HTMLElement {
   readonly attribute HTMLCollection options;
 };
diff --git a/dom/webidl/HTMLDetailsElement.webidl b/dom/webidl/HTMLDetailsElement.webidl
index 104606eb1303..f57f5c93c70b 100644
--- a/dom/webidl/HTMLDetailsElement.webidl
+++ b/dom/webidl/HTMLDetailsElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLDetailsElement : HTMLElement {
   [SetterThrows]
   attribute boolean open;
diff --git a/dom/webidl/HTMLDirectoryElement.webidl b/dom/webidl/HTMLDirectoryElement.webidl
index 9d5160af1bc4..d50b4d330b5f 100644
--- a/dom/webidl/HTMLDirectoryElement.webidl
+++ b/dom/webidl/HTMLDirectoryElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
+[HTMLConstructor]
 interface HTMLDirectoryElement : HTMLElement {
            [SetterThrows, Pure]
            attribute boolean compact;
diff --git a/dom/webidl/HTMLDivElement.webidl b/dom/webidl/HTMLDivElement.webidl
index f50e2aad003f..584c01e0e3ce 100644
--- a/dom/webidl/HTMLDivElement.webidl
+++ b/dom/webidl/HTMLDivElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLDivElement : HTMLElement {};
 
 partial interface HTMLDivElement {
diff --git a/dom/webidl/HTMLElement.webidl b/dom/webidl/HTMLElement.webidl
index 5bd72dca2258..5b1ad746cf0d 100644
--- a/dom/webidl/HTMLElement.webidl
+++ b/dom/webidl/HTMLElement.webidl
@@ -12,6 +12,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLElement : Element {
   // metadata attributes
            attribute DOMString title;
diff --git a/dom/webidl/HTMLEmbedElement.webidl b/dom/webidl/HTMLEmbedElement.webidl
index e4aebfed8318..8cf1db9d5915 100644
--- a/dom/webidl/HTMLEmbedElement.webidl
+++ b/dom/webidl/HTMLEmbedElement.webidl
@@ -13,7 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-embed-element
-[NeedResolve]
+[HTMLConstructor, NeedResolve]
 interface HTMLEmbedElement : HTMLElement {
   [Pure, SetterThrows]
            attribute DOMString src;
diff --git a/dom/webidl/HTMLFieldSetElement.webidl b/dom/webidl/HTMLFieldSetElement.webidl
index 6c9eee52b8e9..f61cdbf5b2cc 100644
--- a/dom/webidl/HTMLFieldSetElement.webidl
+++ b/dom/webidl/HTMLFieldSetElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLFieldSetElement : HTMLElement {
   [SetterThrows]
            attribute boolean disabled;
diff --git a/dom/webidl/HTMLFontElement.webidl b/dom/webidl/HTMLFontElement.webidl
index 781dabb889fd..09c0eae9bfc0 100644
--- a/dom/webidl/HTMLFontElement.webidl
+++ b/dom/webidl/HTMLFontElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLFontElement : HTMLElement {
   [TreatNullAs=EmptyString, SetterThrows] attribute DOMString color;
   [SetterThrows]                          attribute DOMString face;
diff --git a/dom/webidl/HTMLFormElement.webidl b/dom/webidl/HTMLFormElement.webidl
index 8d248e1a53d4..dcc909483478 100644
--- a/dom/webidl/HTMLFormElement.webidl
+++ b/dom/webidl/HTMLFormElement.webidl
@@ -11,7 +11,7 @@
  * and create derivative works of this document.
  */
 
-[OverrideBuiltins, LegacyUnenumerableNamedProperties]
+[OverrideBuiltins, LegacyUnenumerableNamedProperties, HTMLConstructor]
 interface HTMLFormElement : HTMLElement {
            [Pure, SetterThrows]
            attribute DOMString acceptCharset;
diff --git a/dom/webidl/HTMLFrameElement.webidl b/dom/webidl/HTMLFrameElement.webidl
index 9c5aca7c405b..e7d70214353b 100644
--- a/dom/webidl/HTMLFrameElement.webidl
+++ b/dom/webidl/HTMLFrameElement.webidl
@@ -11,6 +11,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#htmlframeelement
+[HTMLConstructor]
 interface HTMLFrameElement : HTMLElement {
            [SetterThrows]
            attribute DOMString name;
diff --git a/dom/webidl/HTMLFrameSetElement.webidl b/dom/webidl/HTMLFrameSetElement.webidl
index ce00d487fa63..cf4e34bcf1dc 100644
--- a/dom/webidl/HTMLFrameSetElement.webidl
+++ b/dom/webidl/HTMLFrameSetElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLFrameSetElement : HTMLElement {
   [SetterThrows]
   attribute DOMString cols;
diff --git a/dom/webidl/HTMLHRElement.webidl b/dom/webidl/HTMLHRElement.webidl
index 0495e43b3144..9359d74b998d 100644
--- a/dom/webidl/HTMLHRElement.webidl
+++ b/dom/webidl/HTMLHRElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-hr-element
+[HTMLConstructor]
 interface HTMLHRElement : HTMLElement {
 };
 
diff --git a/dom/webidl/HTMLHeadElement.webidl b/dom/webidl/HTMLHeadElement.webidl
index 0ad45e3848e5..b649712a6b1c 100644
--- a/dom/webidl/HTMLHeadElement.webidl
+++ b/dom/webidl/HTMLHeadElement.webidl
@@ -12,5 +12,6 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-head-element
+[HTMLConstructor]
 interface HTMLHeadElement : HTMLElement {};
 
diff --git a/dom/webidl/HTMLHeadingElement.webidl b/dom/webidl/HTMLHeadingElement.webidl
index c07e5cb99ca1..97e471025fd7 100644
--- a/dom/webidl/HTMLHeadingElement.webidl
+++ b/dom/webidl/HTMLHeadingElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements
+[HTMLConstructor]
 interface HTMLHeadingElement : HTMLElement {
 };
 
diff --git a/dom/webidl/HTMLHtmlElement.webidl b/dom/webidl/HTMLHtmlElement.webidl
index b06de7761925..f9174a185248 100644
--- a/dom/webidl/HTMLHtmlElement.webidl
+++ b/dom/webidl/HTMLHtmlElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-html-element
+[HTMLConstructor]
 interface HTMLHtmlElement : HTMLElement {};
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
diff --git a/dom/webidl/HTMLIFrameElement.webidl b/dom/webidl/HTMLIFrameElement.webidl
index 6f87c797388e..ea271dedbd51 100644
--- a/dom/webidl/HTMLIFrameElement.webidl
+++ b/dom/webidl/HTMLIFrameElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLIFrameElement : HTMLElement {
   [SetterThrows, Pure]
            attribute DOMString src;
diff --git a/dom/webidl/HTMLImageElement.webidl b/dom/webidl/HTMLImageElement.webidl
index 243c655099d2..c6bc3e4c8113 100644
--- a/dom/webidl/HTMLImageElement.webidl
+++ b/dom/webidl/HTMLImageElement.webidl
@@ -16,7 +16,8 @@ interface imgIRequest;
 interface URI;
 interface nsIStreamListener;
 
-[NamedConstructor=Image(optional unsigned long width, optional unsigned long height)]
+[HTMLConstructor,
+ NamedConstructor=Image(optional unsigned long width, optional unsigned long height)]
 interface HTMLImageElement : HTMLElement {
            [SetterThrows]
            attribute DOMString alt;
diff --git a/dom/webidl/HTMLInputElement.webidl b/dom/webidl/HTMLInputElement.webidl
index 2677c1fe9628..f09f00f949c6 100644
--- a/dom/webidl/HTMLInputElement.webidl
+++ b/dom/webidl/HTMLInputElement.webidl
@@ -21,6 +21,7 @@ enum SelectionMode {
 
 interface nsIControllers;
 
+[HTMLConstructor]
 interface HTMLInputElement : HTMLElement {
   [Pure, SetterThrows]
            attribute DOMString accept;
diff --git a/dom/webidl/HTMLLIElement.webidl b/dom/webidl/HTMLLIElement.webidl
index c20e00846b31..d36b96a0f7b8 100644
--- a/dom/webidl/HTMLLIElement.webidl
+++ b/dom/webidl/HTMLLIElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-li-element
+[HTMLConstructor]
 interface HTMLLIElement : HTMLElement {
            [SetterThrows, Pure]
            attribute long value;
diff --git a/dom/webidl/HTMLLabelElement.webidl b/dom/webidl/HTMLLabelElement.webidl
index f44a56219193..8a5c67fbcfa8 100644
--- a/dom/webidl/HTMLLabelElement.webidl
+++ b/dom/webidl/HTMLLabelElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLLabelElement : HTMLElement {
   readonly attribute HTMLFormElement? form;
            attribute DOMString htmlFor;
diff --git a/dom/webidl/HTMLLegendElement.webidl b/dom/webidl/HTMLLegendElement.webidl
index 0ce4ae88b9a9..8feb70dcbdb7 100644
--- a/dom/webidl/HTMLLegendElement.webidl
+++ b/dom/webidl/HTMLLegendElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-legend-element
+[HTMLConstructor]
 interface HTMLLegendElement : HTMLElement {
   readonly attribute HTMLFormElement? form;
 };
diff --git a/dom/webidl/HTMLLinkElement.webidl b/dom/webidl/HTMLLinkElement.webidl
index ec094e55ece4..c5d8eec4f327 100644
--- a/dom/webidl/HTMLLinkElement.webidl
+++ b/dom/webidl/HTMLLinkElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-link-element
+[HTMLConstructor]
 interface HTMLLinkElement : HTMLElement {
   [Pure]
            attribute boolean disabled;
diff --git a/dom/webidl/HTMLMapElement.webidl b/dom/webidl/HTMLMapElement.webidl
index 88fe4e54c959..cf4d4042602f 100644
--- a/dom/webidl/HTMLMapElement.webidl
+++ b/dom/webidl/HTMLMapElement.webidl
@@ -11,6 +11,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-map-element
+[HTMLConstructor]
 interface HTMLMapElement : HTMLElement {
   [SetterThrows, Pure]
            attribute DOMString name;
diff --git a/dom/webidl/HTMLMenuElement.webidl b/dom/webidl/HTMLMenuElement.webidl
index ff81a7c80d23..7658d8380021 100644
--- a/dom/webidl/HTMLMenuElement.webidl
+++ b/dom/webidl/HTMLMenuElement.webidl
@@ -15,6 +15,7 @@
 interface MenuBuilder;
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-menu-element
+[HTMLConstructor]
 interface HTMLMenuElement : HTMLElement {
            [SetterThrows]
            attribute DOMString type;
diff --git a/dom/webidl/HTMLMenuItemElement.webidl b/dom/webidl/HTMLMenuItemElement.webidl
index 7064885a1ce6..1a7750483787 100644
--- a/dom/webidl/HTMLMenuItemElement.webidl
+++ b/dom/webidl/HTMLMenuItemElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-menuitem-element
+[HTMLConstructor]
 interface HTMLMenuItemElement : HTMLElement {
            [SetterThrows]
            attribute DOMString type;
diff --git a/dom/webidl/HTMLMetaElement.webidl b/dom/webidl/HTMLMetaElement.webidl
index 5b7b0f92c24c..171f673054a9 100644
--- a/dom/webidl/HTMLMetaElement.webidl
+++ b/dom/webidl/HTMLMetaElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-meta-element
+[HTMLConstructor]
 interface HTMLMetaElement : HTMLElement {
   [SetterThrows, Pure]
            attribute DOMString name;
diff --git a/dom/webidl/HTMLMeterElement.webidl b/dom/webidl/HTMLMeterElement.webidl
index 1f80764e942b..d3e7f7f87bc2 100644
--- a/dom/webidl/HTMLMeterElement.webidl
+++ b/dom/webidl/HTMLMeterElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-meter-element
+[HTMLConstructor]
 interface HTMLMeterElement : HTMLElement {
            [SetterThrows]
            attribute double value;
diff --git a/dom/webidl/HTMLModElement.webidl b/dom/webidl/HTMLModElement.webidl
index 45086ccebbf5..654aca2726d7 100644
--- a/dom/webidl/HTMLModElement.webidl
+++ b/dom/webidl/HTMLModElement.webidl
@@ -11,6 +11,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#attributes-common-to-ins-and-del-elements
+[HTMLConstructor]
 interface HTMLModElement : HTMLElement {
   [SetterThrows, Pure]
            attribute DOMString cite;
diff --git a/dom/webidl/HTMLOListElement.webidl b/dom/webidl/HTMLOListElement.webidl
index f41abf3eaa38..5b10d480785e 100644
--- a/dom/webidl/HTMLOListElement.webidl
+++ b/dom/webidl/HTMLOListElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-ol-element
+[HTMLConstructor]
 interface HTMLOListElement : HTMLElement {
            [SetterThrows]
            attribute boolean reversed;
diff --git a/dom/webidl/HTMLObjectElement.webidl b/dom/webidl/HTMLObjectElement.webidl
index 58fd6c1f2f70..a0f4c362612e 100644
--- a/dom/webidl/HTMLObjectElement.webidl
+++ b/dom/webidl/HTMLObjectElement.webidl
@@ -13,7 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-object-element
-[NeedResolve, UnsafeInPrerendering]
+[HTMLConstructor, NeedResolve, UnsafeInPrerendering]
 interface HTMLObjectElement : HTMLElement {
   [Pure, SetterThrows]
            attribute DOMString data;
diff --git a/dom/webidl/HTMLOptGroupElement.webidl b/dom/webidl/HTMLOptGroupElement.webidl
index a23aee30d1de..18d2e5dfab9f 100644
--- a/dom/webidl/HTMLOptGroupElement.webidl
+++ b/dom/webidl/HTMLOptGroupElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLOptGroupElement : HTMLElement {
            [SetterThrows]
            attribute boolean disabled;
diff --git a/dom/webidl/HTMLOptionElement.webidl b/dom/webidl/HTMLOptionElement.webidl
index c80bedeef041..34e6e6c23e7d 100644
--- a/dom/webidl/HTMLOptionElement.webidl
+++ b/dom/webidl/HTMLOptionElement.webidl
@@ -11,7 +11,7 @@
  * and create derivative works of this document.
  */
 
-[NamedConstructor=Option(optional DOMString text, optional DOMString value, optional boolean defaultSelected, optional boolean selected)]
+[HTMLConstructor, NamedConstructor=Option(optional DOMString text, optional DOMString value, optional boolean defaultSelected, optional boolean selected)]
 interface HTMLOptionElement : HTMLElement {
            [SetterThrows]
            attribute boolean disabled;
diff --git a/dom/webidl/HTMLOutputElement.webidl b/dom/webidl/HTMLOutputElement.webidl
index 05dcf1800f35..29e4b34d1ff6 100644
--- a/dom/webidl/HTMLOutputElement.webidl
+++ b/dom/webidl/HTMLOutputElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-output-element
+[HTMLConstructor]
 interface HTMLOutputElement : HTMLElement {
   [PutForwards=value, Constant]
   readonly attribute DOMTokenList htmlFor;
diff --git a/dom/webidl/HTMLParagraphElement.webidl b/dom/webidl/HTMLParagraphElement.webidl
index 2a626d25750b..b72f627d1342 100644
--- a/dom/webidl/HTMLParagraphElement.webidl
+++ b/dom/webidl/HTMLParagraphElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-p-element
+[HTMLConstructor]
 interface HTMLParagraphElement : HTMLElement {
 };
 
diff --git a/dom/webidl/HTMLParamElement.webidl b/dom/webidl/HTMLParamElement.webidl
index e2c7e8d7fab1..b9f17d6f5379 100644
--- a/dom/webidl/HTMLParamElement.webidl
+++ b/dom/webidl/HTMLParamElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-param-element
+[HTMLConstructor]
 interface HTMLParamElement : HTMLElement {
            [SetterThrows, Pure]
            attribute DOMString name;
diff --git a/dom/webidl/HTMLPictureElement.webidl b/dom/webidl/HTMLPictureElement.webidl
index eff30f750109..387eee78ddcd 100644
--- a/dom/webidl/HTMLPictureElement.webidl
+++ b/dom/webidl/HTMLPictureElement.webidl
@@ -4,5 +4,6 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+[HTMLConstructor]
 interface HTMLPictureElement : HTMLElement {
 };
diff --git a/dom/webidl/HTMLPreElement.webidl b/dom/webidl/HTMLPreElement.webidl
index db220b74c080..b128e824d30b 100644
--- a/dom/webidl/HTMLPreElement.webidl
+++ b/dom/webidl/HTMLPreElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-pre-element
+[HTMLConstructor]
 interface HTMLPreElement : HTMLElement {
 };
 
diff --git a/dom/webidl/HTMLProgressElement.webidl b/dom/webidl/HTMLProgressElement.webidl
index 3d1000d22f5b..6cfed38d0af1 100644
--- a/dom/webidl/HTMLProgressElement.webidl
+++ b/dom/webidl/HTMLProgressElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLProgressElement : HTMLElement {
            [SetterThrows]
            attribute double value;
diff --git a/dom/webidl/HTMLQuoteElement.webidl b/dom/webidl/HTMLQuoteElement.webidl
index a266dd353a12..5cf9c4c29eed 100644
--- a/dom/webidl/HTMLQuoteElement.webidl
+++ b/dom/webidl/HTMLQuoteElement.webidl
@@ -12,6 +12,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-blockquote-element
+[HTMLConstructor]
 interface HTMLQuoteElement : HTMLElement {
            [SetterThrows, Pure]
            attribute DOMString cite;
diff --git a/dom/webidl/HTMLScriptElement.webidl b/dom/webidl/HTMLScriptElement.webidl
index 377056366da2..7f5115f1f623 100644
--- a/dom/webidl/HTMLScriptElement.webidl
+++ b/dom/webidl/HTMLScriptElement.webidl
@@ -8,6 +8,7 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
  */
 
+[HTMLConstructor]
 interface HTMLScriptElement : HTMLElement {
   [SetterThrows]
   attribute DOMString src;
diff --git a/dom/webidl/HTMLSelectElement.webidl b/dom/webidl/HTMLSelectElement.webidl
index 74fc7b2cfbd3..afbf5411c533 100644
--- a/dom/webidl/HTMLSelectElement.webidl
+++ b/dom/webidl/HTMLSelectElement.webidl
@@ -7,6 +7,7 @@
  * http://www.whatwg.org/html/#the-select-element
  */
 
+[HTMLConstructor]
 interface HTMLSelectElement : HTMLElement {
   [SetterThrows, Pure]
            attribute boolean autofocus;
diff --git a/dom/webidl/HTMLSourceElement.webidl b/dom/webidl/HTMLSourceElement.webidl
index 10b8e6fd5194..402b4491a9ab 100644
--- a/dom/webidl/HTMLSourceElement.webidl
+++ b/dom/webidl/HTMLSourceElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLSourceElement : HTMLElement {
            [SetterThrows]
            attribute DOMString src;
diff --git a/dom/webidl/HTMLSpanElement.webidl b/dom/webidl/HTMLSpanElement.webidl
index 43a2d97f2003..6f65cdfb383d 100644
--- a/dom/webidl/HTMLSpanElement.webidl
+++ b/dom/webidl/HTMLSpanElement.webidl
@@ -12,4 +12,5 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-span-element
+[HTMLConstructor]
 interface HTMLSpanElement : HTMLElement {};
diff --git a/dom/webidl/HTMLStyleElement.webidl b/dom/webidl/HTMLStyleElement.webidl
index 7ed01a8f186e..b547d6976603 100644
--- a/dom/webidl/HTMLStyleElement.webidl
+++ b/dom/webidl/HTMLStyleElement.webidl
@@ -8,6 +8,7 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
  */
 
+[HTMLConstructor]
 interface HTMLStyleElement : HTMLElement {
            [Pure]
            attribute boolean disabled;
diff --git a/dom/webidl/HTMLTableCaptionElement.webidl b/dom/webidl/HTMLTableCaptionElement.webidl
index 688b9f925448..e9d01527e74a 100644
--- a/dom/webidl/HTMLTableCaptionElement.webidl
+++ b/dom/webidl/HTMLTableCaptionElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLTableCaptionElement : HTMLElement {};
 
 partial interface HTMLTableCaptionElement {
diff --git a/dom/webidl/HTMLTableCellElement.webidl b/dom/webidl/HTMLTableCellElement.webidl
index e970a50401dc..f0a251d273d6 100644
--- a/dom/webidl/HTMLTableCellElement.webidl
+++ b/dom/webidl/HTMLTableCellElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLTableCellElement : HTMLElement {
            [SetterThrows]
            attribute unsigned long colSpan;
diff --git a/dom/webidl/HTMLTableColElement.webidl b/dom/webidl/HTMLTableColElement.webidl
index c927541a3dc4..cf217548ae3a 100644
--- a/dom/webidl/HTMLTableColElement.webidl
+++ b/dom/webidl/HTMLTableColElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLTableColElement : HTMLElement {
            [SetterThrows]
            attribute unsigned long span;
diff --git a/dom/webidl/HTMLTableElement.webidl b/dom/webidl/HTMLTableElement.webidl
index a06f590e0ff4..2653524d64db 100644
--- a/dom/webidl/HTMLTableElement.webidl
+++ b/dom/webidl/HTMLTableElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLTableElement : HTMLElement {
            [SetterThrows]
            attribute HTMLTableCaptionElement? caption;
diff --git a/dom/webidl/HTMLTableRowElement.webidl b/dom/webidl/HTMLTableRowElement.webidl
index 2a356a20e0dd..7d63bcc04920 100644
--- a/dom/webidl/HTMLTableRowElement.webidl
+++ b/dom/webidl/HTMLTableRowElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLTableRowElement : HTMLElement {
   readonly attribute long rowIndex;
   readonly attribute long sectionRowIndex;
diff --git a/dom/webidl/HTMLTableSectionElement.webidl b/dom/webidl/HTMLTableSectionElement.webidl
index 310d0ece6c08..881972ac21c8 100644
--- a/dom/webidl/HTMLTableSectionElement.webidl
+++ b/dom/webidl/HTMLTableSectionElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLTableSectionElement : HTMLElement {
   readonly attribute HTMLCollection rows;
   [Throws]
diff --git a/dom/webidl/HTMLTemplateElement.webidl b/dom/webidl/HTMLTemplateElement.webidl
index c518995f6694..f77eeaa42906 100644
--- a/dom/webidl/HTMLTemplateElement.webidl
+++ b/dom/webidl/HTMLTemplateElement.webidl
@@ -9,6 +9,7 @@
  * liability, trademark and document use rules apply.
  */
 
+[HTMLConstructor]
 interface HTMLTemplateElement : HTMLElement {
     readonly attribute DocumentFragment content;
 };
diff --git a/dom/webidl/HTMLTextAreaElement.webidl b/dom/webidl/HTMLTextAreaElement.webidl
index b1005ed42243..9573579ed3f0 100644
--- a/dom/webidl/HTMLTextAreaElement.webidl
+++ b/dom/webidl/HTMLTextAreaElement.webidl
@@ -14,6 +14,7 @@
 interface nsIEditor;
 interface MozControllers;
 
+[HTMLConstructor]
 interface HTMLTextAreaElement : HTMLElement {
            // attribute DOMString autocomplete;
   [SetterThrows, Pure]
diff --git a/dom/webidl/HTMLTimeElement.webidl b/dom/webidl/HTMLTimeElement.webidl
index 517ca9981eeb..ea37405bfc31 100644
--- a/dom/webidl/HTMLTimeElement.webidl
+++ b/dom/webidl/HTMLTimeElement.webidl
@@ -7,6 +7,7 @@
  * http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-time-element
  */
 
+[HTMLConstructor]
 interface HTMLTimeElement : HTMLElement {
            [SetterThrows]
            attribute DOMString dateTime;
diff --git a/dom/webidl/HTMLTitleElement.webidl b/dom/webidl/HTMLTitleElement.webidl
index e6c8f2c61ff8..c8fe3e46a5ba 100644
--- a/dom/webidl/HTMLTitleElement.webidl
+++ b/dom/webidl/HTMLTitleElement.webidl
@@ -7,6 +7,7 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#the-title-element
  */
 
+[HTMLConstructor]
 interface HTMLTitleElement : HTMLElement {
            [Throws]
            attribute DOMString text;
diff --git a/dom/webidl/HTMLTrackElement.webidl b/dom/webidl/HTMLTrackElement.webidl
index dd88e9beb9ed..e6d366f10d37 100644
--- a/dom/webidl/HTMLTrackElement.webidl
+++ b/dom/webidl/HTMLTrackElement.webidl
@@ -7,6 +7,7 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#the-track-element
  */
 
+[HTMLConstructor]
 interface HTMLTrackElement : HTMLElement {
   [SetterThrows, Pure]
   attribute DOMString kind;
diff --git a/dom/webidl/HTMLUListElement.webidl b/dom/webidl/HTMLUListElement.webidl
index 0528198c9eb9..01ca7afce4cd 100644
--- a/dom/webidl/HTMLUListElement.webidl
+++ b/dom/webidl/HTMLUListElement.webidl
@@ -13,6 +13,7 @@
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-ul-element
+[HTMLConstructor]
 interface HTMLUListElement : HTMLElement {
 };
 
diff --git a/dom/webidl/HTMLVideoElement.webidl b/dom/webidl/HTMLVideoElement.webidl
index af28d5418afd..fd552f7e0d57 100644
--- a/dom/webidl/HTMLVideoElement.webidl
+++ b/dom/webidl/HTMLVideoElement.webidl
@@ -11,6 +11,7 @@
  * and create derivative works of this document.
  */
 
+[HTMLConstructor]
 interface HTMLVideoElement : HTMLMediaElement {
   [SetterThrows]
            attribute unsigned long width;
diff --git a/dom/webidl/IIRFilterNode.webidl b/dom/webidl/IIRFilterNode.webidl
index a1164b6ae121..119406ddb55a 100644
--- a/dom/webidl/IIRFilterNode.webidl
+++ b/dom/webidl/IIRFilterNode.webidl
@@ -9,7 +9,13 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary IIRFilterOptions : AudioNodeOptions {
+    required sequence feedforward;
+    required sequence feedback;
+};
+
+[Pref="dom.webaudio.enabled",
+Constructor(AudioContext context, IIRFilterOptions options)]
 interface IIRFilterNode : AudioNode {
     void getFrequencyResponse(Float32Array frequencyHz, Float32Array magResponse, Float32Array phaseResponse);
 };
diff --git a/dom/webidl/MediaElementAudioSourceNode.webidl b/dom/webidl/MediaElementAudioSourceNode.webidl
index f1ac17473548..37de32536d24 100644
--- a/dom/webidl/MediaElementAudioSourceNode.webidl
+++ b/dom/webidl/MediaElementAudioSourceNode.webidl
@@ -10,7 +10,12 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary MediaElementAudioSourceOptions {
+    required HTMLMediaElement mediaElement;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, MediaElementAudioSourceOptions options)]
 interface MediaElementAudioSourceNode : AudioNode {
 
 };
diff --git a/dom/webidl/MediaStreamAudioDestinationNode.webidl b/dom/webidl/MediaStreamAudioDestinationNode.webidl
index aafff964eea4..9776ab994f64 100644
--- a/dom/webidl/MediaStreamAudioDestinationNode.webidl
+++ b/dom/webidl/MediaStreamAudioDestinationNode.webidl
@@ -10,9 +10,8 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional AudioNodeOptions options)]
 interface MediaStreamAudioDestinationNode : AudioNode {
-
     readonly attribute MediaStream stream;
-
 };
diff --git a/dom/webidl/MediaStreamAudioSourceNode.webidl b/dom/webidl/MediaStreamAudioSourceNode.webidl
index e717ef2543f1..06727a5dadd2 100644
--- a/dom/webidl/MediaStreamAudioSourceNode.webidl
+++ b/dom/webidl/MediaStreamAudioSourceNode.webidl
@@ -10,7 +10,12 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary MediaStreamAudioSourceOptions {
+    required MediaStream mediaStream;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, MediaStreamAudioSourceOptions options)]
 interface MediaStreamAudioSourceNode : AudioNode {
 
 };
diff --git a/dom/webidl/OscillatorNode.webidl b/dom/webidl/OscillatorNode.webidl
index 268897080960..3a1c005bc67d 100644
--- a/dom/webidl/OscillatorNode.webidl
+++ b/dom/webidl/OscillatorNode.webidl
@@ -18,7 +18,15 @@ enum OscillatorType {
   "custom"
 };
 
-[Pref="dom.webaudio.enabled"]
+dictionary OscillatorOptions : AudioNodeOptions {
+             OscillatorType type = "sine";
+             float          frequency = 440;
+             float          detune = 0;
+             PeriodicWave   periodicWave;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional OscillatorOptions options)]
 interface OscillatorNode : AudioNode {
 
     [SetterThrows]
@@ -39,4 +47,3 @@ interface OscillatorNode : AudioNode {
 
 // Mozilla extensions
 OscillatorNode implements AudioNodePassThrough;
-
diff --git a/dom/webidl/PannerNode.webidl b/dom/webidl/PannerNode.webidl
index 86b8928524b9..7e8f708fa7a8 100644
--- a/dom/webidl/PannerNode.webidl
+++ b/dom/webidl/PannerNode.webidl
@@ -21,7 +21,25 @@ enum DistanceModelType {
   "exponential"
 };
 
-[Pref="dom.webaudio.enabled"]
+dictionary PannerOptions : AudioNodeOptions {
+             PanningModelType  panningModel = "equalpower";
+             DistanceModelType distanceModel = "inverse";
+             float             positionX = 0;
+             float             positionY = 0;
+             float             positionZ = 0;
+             float             orientationX = 1;
+             float             orientationY = 0;
+             float             orientationZ = 0;
+             double            refDistance = 1;
+             double            maxDistance = 10000;
+             double            rolloffFactor = 1;
+             double            coneInnerAngle = 360;
+             double            coneOuterAngle = 360;
+             double            coneOuterGain = 0;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional PannerOptions options)]
 interface PannerNode : AudioNode {
 
     // Default for stereo is equalpower
diff --git a/dom/webidl/PeriodicWave.webidl b/dom/webidl/PeriodicWave.webidl
index c118274a240b..9b58045aba01 100644
--- a/dom/webidl/PeriodicWave.webidl
+++ b/dom/webidl/PeriodicWave.webidl
@@ -10,8 +10,12 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
-interface PeriodicWave {
-
+dictionary PeriodicWaveOptions : PeriodicWaveConstraints {
+             sequence real;
+             sequence imag;
 };
 
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, PeriodicWaveOptions options)]
+interface PeriodicWave {
+};
diff --git a/dom/webidl/StereoPannerNode.webidl b/dom/webidl/StereoPannerNode.webidl
index f84c8310b7b2..4e1784c11434 100644
--- a/dom/webidl/StereoPannerNode.webidl
+++ b/dom/webidl/StereoPannerNode.webidl
@@ -10,7 +10,12 @@
  * liability, trademark and document use rules apply.
  */
 
-[Pref="dom.webaudio.enabled"]
+dictionary StereoPannerOptions : AudioNodeOptions {
+             float pan = 0;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional StereoPannerOptions options)]
 interface StereoPannerNode : AudioNode {
   readonly attribute AudioParam pan;
 };
diff --git a/dom/webidl/WaveShaperNode.webidl b/dom/webidl/WaveShaperNode.webidl
index ac30c94dcc94..43403b4a6d00 100644
--- a/dom/webidl/WaveShaperNode.webidl
+++ b/dom/webidl/WaveShaperNode.webidl
@@ -16,10 +16,16 @@ enum OverSampleType {
   "4x"
 };
 
-[Pref="dom.webaudio.enabled"]
+dictionary WaveShaperOptions : AudioNodeOptions {
+             sequence curve;
+             OverSampleType  oversample = "none";
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, optional WaveShaperOptions options)]
 interface WaveShaperNode : AudioNode {
 
-      [SetterThrows]
+      [Cached, Pure, SetterThrows]
       attribute Float32Array? curve;
       attribute OverSampleType oversample;
 
diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp
index b8b57978067a..11363a5e2842 100644
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1609,10 +1609,10 @@ nsXULElement::LoadSrc()
         nsXULSlots* slots = static_cast(Slots());
         nsCOMPtr opener = do_QueryInterface(slots->mFrameLoaderOrOpener);
         if (!opener) {
-            // If we are a content-primary xul-browser, we want to take the opener property!
+            // If we are a primary xul-browser, we want to take the opener property!
             nsCOMPtr chromeWindow = do_QueryInterface(OwnerDoc()->GetWindow());
-            if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
-                            NS_LITERAL_STRING("content-primary"), eIgnoreCase) &&
+            if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
+                            nsGkAtoms::_true, eIgnoreCase) &&
                 chromeWindow) {
                 nsCOMPtr wp;
                 chromeWindow->TakeOpenerForInitialContentBrowser(getter_AddRefs(wp));
diff --git a/editor/composer/test/test_bug434998.xul b/editor/composer/test/test_bug434998.xul
index 4a384ac1c37f..0a117128c9f6 100644
--- a/editor/composer/test/test_bug434998.xul
+++ b/editor/composer/test/test_bug434998.xul
@@ -19,7 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=434998
   

diff --git a/editor/libeditor/HTMLEditorDataTransfer.cpp b/editor/libeditor/HTMLEditorDataTransfer.cpp index b2c32642b15b..93a134adb3ee 100644 --- a/editor/libeditor/HTMLEditorDataTransfer.cpp +++ b/editor/libeditor/HTMLEditorDataTransfer.cpp @@ -1842,7 +1842,12 @@ HTMLEditor::InsertAsPlaintextQuotation(const nsAString& aQuotedText, return NS_OK; // rules canceled the operation } - // Wrap the inserted quote in a so we can distinguish it. + // Wrap the inserted quote in a so we can distinguish it. If we're + // inserting into the , we use a which is displayed as a block + // and sized to the screen using 98 viewport width units. + // We could use 100vw, but 98vw avoids a horizontal scroll bar where possible. + // All this is done to wrap overlong lines to the screen and not to the + // container element, the width-restricted body. nsCOMPtr newNode = DeleteSelectionAndCreateElement(*nsGkAtoms::span); @@ -1855,8 +1860,15 @@ HTMLEditor::InsertAsPlaintextQuotation(const nsAString& aQuotedText, newNode->SetAttr(kNameSpaceID_None, nsGkAtoms::mozquote, NS_LITERAL_STRING("true"), true); // Allow wrapping on spans so long lines get wrapped to the screen. - newNode->SetAttr(kNameSpaceID_None, nsGkAtoms::style, - NS_LITERAL_STRING("white-space: pre-wrap;"), true); + nsCOMPtr parent = newNode->GetParentNode(); + if (parent && parent->IsHTMLElement(nsGkAtoms::body)) { + newNode->SetAttr(kNameSpaceID_None, nsGkAtoms::style, + NS_LITERAL_STRING("white-space: pre-wrap; display: block; width: 98vw;"), + true); + } else { + newNode->SetAttr(kNameSpaceID_None, nsGkAtoms::style, + NS_LITERAL_STRING("white-space: pre-wrap;"), true); + } // and set the selection inside it: selection->Collapse(newNode, 0); diff --git a/editor/libeditor/tests/test_bug607584.xul b/editor/libeditor/tests/test_bug607584.xul index fb16cee83800..c51be9d6132e 100644 --- a/editor/libeditor/tests/test_bug607584.xul +++ b/editor/libeditor/tests/test_bug607584.xul @@ -19,7 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=607584

diff --git a/editor/libeditor/tests/test_bug780908.xul b/editor/libeditor/tests/test_bug780908.xul index 312f0278759f..238bdf9c8bc7 100644 --- a/editor/libeditor/tests/test_bug780908.xul +++ b/editor/libeditor/tests/test_bug780908.xul @@ -21,7 +21,8 @@ adapted from test_bug607584.xul by Kent James

diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index fd9890db2906..ba804629ac7a 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -274,10 +274,10 @@ nsDocShellTreeOwner::EnsureContentTreeOwner() NS_IMETHODIMP nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell, - bool aPrimary, const nsAString& aID) + bool aPrimary) { if (mTreeOwner) - return mTreeOwner->ContentShellAdded(aContentShell, aPrimary, aID); + return mTreeOwner->ContentShellAdded(aContentShell, aPrimary); EnsureContentTreeOwner(); aContentShell->SetTreeOwner(mContentTreeOwner); diff --git a/gfx/2d/Logging.h b/gfx/2d/Logging.h index 02ee70823f6a..0d9886cff5cf 100644 --- a/gfx/2d/Logging.h +++ b/gfx/2d/Logging.h @@ -130,6 +130,7 @@ enum class LogReason : int { UnbalancedClipStack, ProcessingError, InvalidDrawTarget, + NativeFontResourceNotFound, // End MustBeLessThanThis = 101, }; diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp index 40222eda04e7..d929669b838c 100644 --- a/gfx/2d/RecordedEvent.cpp +++ b/gfx/2d/RecordedEvent.cpp @@ -1644,6 +1644,12 @@ bool RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const { NativeFontResource *fontResource = aTranslator->LookupNativeFontResource(mFontDataKey); + if (!fontResource) { + gfxDevCrash(LogReason::NativeFontResourceNotFound) << + "NativeFontResource lookup failed for key |" << hexa(mFontDataKey) << "|."; + return false; + } + RefPtr scaledFont = fontResource->CreateScaledFont(mIndex, mGlyphSize); aTranslator->AddScaledFont(mRefPtr, scaledFont); return true; diff --git a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp index 99edf945209d..2500b0ffffd6 100644 --- a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp +++ b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp @@ -219,7 +219,13 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, fIsColorFont = fFactory2.get() && fontFace2.get() && fontFace2->IsColorFont(); #endif - // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC + IDWriteFactory* factory = sk_get_dwrite_factory(); + if (factory != nullptr) { + HRVM(factory->CreateRenderingParams(&fDefaultRenderingParams), + "Could not create default rendering params"); + } + + // In general, all glyphs should DWriteFontFace::GetRecommendedRenderingMode // except when bi-level rendering is requested or there are embedded // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). // @@ -315,13 +321,26 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, fTextSizeMeasure = realTextSize; fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; - // The normal case is to use natural symmetric rendering and linear metrics. + // The normal case is to use the recommended rendering mode } else { fTextSizeRender = realTextSize; - fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; fTextSizeMeasure = realTextSize; fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; + + if (!SUCCEEDED(fTypeface->fDWriteFontFace->GetRecommendedRenderingMode( + fTextSizeRender, + 1.0f, + fMeasuringMode, + fDefaultRenderingParams.get(), + &fRenderingMode))) { + fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; + } + + // We don't support outline mode right now. + if (fRenderingMode == DWRITE_RENDERING_MODE_OUTLINE) { + fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; + } } if (this->isSubpixel()) { diff --git a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h index 98c4910b27f0..f2a7e255bab0 100644 --- a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h +++ b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h @@ -75,6 +75,7 @@ private: DWRITE_RENDERING_MODE fRenderingMode; DWRITE_TEXTURE_TYPE fTextureType; DWRITE_MEASURING_MODE fMeasuringMode; + SkTScopedComPtr fDefaultRenderingParams; #if SK_HAS_DWRITE_2_H SkTScopedComPtr fFactory2; bool fIsColorFont; diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 982390d1867b..75026df396dd 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -133,11 +133,6 @@ public: } bool AccelerateLayersByDefault() override { -#ifdef NIGHTLY_BUILD - // Only enable the GL compositor on Nightly for now until we have - // sufficient data for blocklisting. - return true; -#endif return false; } diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp index 0f7d465dbbfa..cb28c564128b 100644 --- a/js/ipc/JavaScriptShared.cpp +++ b/js/ipc/JavaScriptShared.cpp @@ -101,7 +101,7 @@ IdToObjectMap::has(const ObjectId& id, const JSObject* obj) const auto p = table_.lookup(id); if (!p) return false; - return p->value().unbarrieredGet() == obj; + return p->value() == obj; } #endif diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index e0ae158e8926..d6ad1bf86c59 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -144,10 +144,6 @@ template struct PersistentRootedMarker; } /* namespace gc */ -#define DECLARE_POINTER_COMPARISON_OPS(T) \ - bool operator==(const T& other) const { return get() == other; } \ - bool operator!=(const T& other) const { return get() != other; } - // Important: Return a reference so passing a Rooted, etc. to // something that takes a |const T&| is not a GC hazard. #define DECLARE_POINTER_CONSTREF_OPS(T) \ @@ -233,6 +229,8 @@ class Heap : public js::HeapBase static_assert(js::IsHeapConstructibleType::value, "Type T must be a public GC pointer type"); public: + using ElementType = T; + Heap() { static_assert(sizeof(T) == sizeof(Heap), "Heap must be binary compatible with T."); @@ -372,6 +370,8 @@ template class TenuredHeap : public js::HeapBase { public: + using ElementType = T; + TenuredHeap() : bits(0) { static_assert(sizeof(T) == sizeof(TenuredHeap), "TenuredHeap must be binary compatible with T."); @@ -379,9 +379,6 @@ class TenuredHeap : public js::HeapBase explicit TenuredHeap(T p) : bits(0) { setPtr(p); } explicit TenuredHeap(const TenuredHeap& p) : bits(0) { setPtr(p.getPtr()); } - bool operator==(const TenuredHeap& other) { return bits == other.bits; } - bool operator!=(const TenuredHeap& other) { return bits != other.bits; } - void setPtr(T newPtr) { MOZ_ASSERT((reinterpret_cast(newPtr) & flagsMask) == 0); if (newPtr) @@ -458,6 +455,8 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase friend class JS::MutableHandle; public: + using ElementType = T; + /* Creates a handle from a handle of a type convertible to T. */ template MOZ_IMPLICIT Handle(Handle handle, @@ -518,7 +517,6 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase MOZ_IMPLICIT Handle(MutableHandle& root, typename mozilla::EnableIf::value, int>::Type dummy = 0); - DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); @@ -545,6 +543,8 @@ template class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase { public: + using ElementType = T; + inline MOZ_IMPLICIT MutableHandle(Rooted* root); inline MOZ_IMPLICIT MutableHandle(PersistentRooted* root); @@ -774,6 +774,8 @@ class MOZ_RAII Rooted : public js::RootedBase } public: + using ElementType = T; + template explicit Rooted(const RootingContext& cx) : ptr(GCPolicy::initial()) @@ -803,7 +805,6 @@ class MOZ_RAII Rooted : public js::RootedBase ptr = value; } - DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(Rooted, T); DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); @@ -880,13 +881,14 @@ template class MOZ_RAII FakeRooted : public RootedBase { public: + using ElementType = T; + template explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy::initial()) {} template FakeRooted(CX* cx, T initial) : ptr(initial) {} - DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T); DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); @@ -907,6 +909,8 @@ template class FakeMutableHandle : public js::MutableHandleBase { public: + using ElementType = T; + MOZ_IMPLICIT FakeMutableHandle(T* t) { ptr = t; } @@ -1097,6 +1101,8 @@ class PersistentRooted : public js::PersistentRootedBase, js::RootLists& rootLists(js::ContextFriendFields* cx) = delete; public: + using ElementType = T; + PersistentRooted() : ptr(GCPolicy::initial()) {} template @@ -1150,7 +1156,6 @@ class PersistentRooted : public js::PersistentRootedBase, } } - DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); @@ -1187,6 +1192,8 @@ class JS_PUBLIC_API(ObjectPtr) Heap value; public: + using ElementType = JSObject*; + ObjectPtr() : value(nullptr) {} explicit ObjectPtr(JSObject* obj) : value(obj) {} @@ -1308,6 +1315,177 @@ Swap(JS::TenuredHeap& aX, JS::TenuredHeap& aY) } /* namespace mozilla */ +namespace js { +namespace detail { + +// DefineComparisonOps is a trait which selects which wrapper classes to define +// operator== and operator!= for. It supplies a getter function to extract the +// value to compare. This is used to avoid triggering the automatic read +// barriers where appropriate. +// +// If DefineComparisonOps is not specialized for a particular wrapper you may +// get errors such as 'invalid operands to binary expression' or 'no match for +// operator==' when trying to compare against instances of the wrapper. + +template +struct DefineComparisonOps : mozilla::FalseType {}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Heap& v) { return v.unbarrieredGet(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T get(const JS::TenuredHeap& v) { return v.unbarrieredGetPtr(); } +}; + +template <> +struct DefineComparisonOps : mozilla::TrueType { + static const JSObject* get(const JS::ObjectPtr& v) { return v.unbarrieredGet(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Rooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Handle& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::MutableHandle& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::PersistentRooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const js::FakeRooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const js::FakeMutableHandle& v) { return v.get(); } +}; + +} /* namespace detail */ +} /* namespace js */ + +// Overload operator== and operator!= for all types with the DefineComparisonOps +// trait using the supplied getter. +// +// There are four cases: + +// Case 1: comparison between two wrapper objects. + +template +typename mozilla::EnableIf::value && + js::detail::DefineComparisonOps::value, bool>::Type +operator==(const T& a, const U& b) { + return js::detail::DefineComparisonOps::get(a) == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf::value && + js::detail::DefineComparisonOps::value, bool>::Type +operator!=(const T& a, const U& b) { + return !(a == b); +} + +// Case 2: comparison between a wrapper object and its unwrapped element type. + +template +typename mozilla::EnableIf::value, bool>::Type +operator==(const T& a, const typename T::ElementType& b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf::value, bool>::Type +operator!=(const T& a, const typename T::ElementType& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf::value, bool>::Type +operator==(const typename T::ElementType& a, const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf::value, bool>::Type +operator!=(const typename T::ElementType& a, const T& b) { + return !(a == b); +} + +// Case 3: For pointer wrappers, comparison between the wrapper and a const +// element pointer. + +template +typename mozilla::EnableIf::value && + mozilla::IsPointer::value, bool>::Type +operator==(const typename mozilla::RemovePointer::Type* a, const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf::value && + mozilla::IsPointer::value, bool>::Type +operator!=(const typename mozilla::RemovePointer::Type* a, const T& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf::value && + mozilla::IsPointer::value, bool>::Type +operator==(const T& a, const typename mozilla::RemovePointer::Type* b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf::value && + mozilla::IsPointer::value, bool>::Type +operator!=(const T& a, const typename mozilla::RemovePointer::Type* b) { + return !(a == b); +} + +// Case 4: For pointer wrappers, comparison between the wrapper and nullptr. + +template +typename mozilla::EnableIf::value && + mozilla::IsPointer::value, bool>::Type +operator==(std::nullptr_t a, const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf::value && + mozilla::IsPointer::value, bool>::Type +operator!=(std::nullptr_t a, const T& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf::value && + mozilla::IsPointer::value, bool>::Type +operator==(const T& a, std::nullptr_t b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf::value && + mozilla::IsPointer::value, bool>::Type +operator!=(const T& a, std::nullptr_t b) { + return !(a == b); +} + #undef DELETE_ASSIGNMENT_OPS #endif /* js_RootingAPI_h */ diff --git a/js/src/ds/PageProtectingVector.h b/js/src/ds/PageProtectingVector.h index bf7665712abb..ecf1f6caf77e 100644 --- a/js/src/ds/PageProtectingVector.h +++ b/js/src/ds/PageProtectingVector.h @@ -15,10 +15,12 @@ namespace js { /* - * PageProtectingVector is a vector that can only grow or be cleared, and marks - * all of its fully used memory pages as read-only. It can be used to detect - * heap corruption in important buffers, since anything that tries to write - * into its protected pages will crash. + * PageProtectingVector is a vector that can only grow or be cleared, restricts + * access to memory pages that haven't been used yet, and marks all of its fully + * used memory pages as read-only. It can be used to detect heap corruption in + * important buffers, since anything that tries to write into its protected + * pages will crash. On Nightly and Aurora, these crashes will additionally be + * annotated with a moz crash reason using MemoryProtectionExceptionHandler. * * PageProtectingVector's protection is limited to full pages. If the front * of its buffer is not aligned on a page boundary, bytes preceding the first @@ -28,7 +30,10 @@ namespace js { */ template + class AllocPolicy = mozilla::MallocAllocPolicy, + bool ProtectUsed = true, + bool ProtectUnused = true, + size_t InitialLowerBound = 0> class PageProtectingVector final { mozilla::Vector vector; @@ -44,21 +49,34 @@ class PageProtectingVector final */ size_t offsetToPage; + /* + * The offset in bytes of the first completely unused page in the buffer. + * Note: this page might extend or even begin past the end of the buffer. + */ + size_t firstUnusedPage; + /* The number of currently protected bytes (a multiple of pageSize). */ size_t protectedBytes; + size_t protectedUnusedBytes; /* - * The number of bytes that are currently unprotected, but could be. + * The number of used bytes that are currently unprotected, but could be. * This number starts at |-offsetToPage|, since any bytes before * |vector.begin() + offsetToPage| can never be protected (as we do not own * the whole page). As a result, if |unprotectedBytes >= pageSize|, we know * we can protect at least one more page, and |unprotectedBytes & ~pageMask| * is always the number of additional bytes we can protect. Put another way, - * |offsetToPage + protectedBytes + unprotectedBytes == vector.length()| + * |offsetToPage + protectedBytes + unprotectedBytes == [size in bytes]| * always holds, and if |protectedBytes != 0| then |unprotectedBytes >= 0|. */ intptr_t unprotectedBytes; + /* + * The number of unprotected, unused pages. Note that this value + * may not be up to date if unused page protection is disabled. + */ + intptr_t unprotectedUnusedPages; + /* * The size in bytes that a buffer needs to be before its pages will be * protected. This is intended to reduce churn for small vectors while @@ -66,21 +84,42 @@ class PageProtectingVector final */ size_t protectionLowerBound; - bool protectionEnabled; + bool protectUsedEnabled; + bool protectUnusedEnabled; bool regionUnprotected; + bool protectionDisabled; - void updateOffsetToPage() { + void updateProtectUsedOffsets() { + MOZ_ASSERT(!protectedBytes); unprotectedBytes += offsetToPage; offsetToPage = (pageSize - (uintptr_t(vector.begin()) & pageMask)) & pageMask; unprotectedBytes -= offsetToPage; -#ifndef RELEASE_OR_BETA - protectionEnabled = vector.capacity() >= protectionLowerBound && - vector.capacity() >= pageSize + offsetToPage; -#endif + protectUsedEnabled = ProtectUsed && !protectionDisabled && + vector.capacity() * sizeof(T) >= protectionLowerBound && + vector.capacity() * sizeof(T) >= pageSize + offsetToPage; + } + + void updateProtectUnusedOffsets() { + MOZ_ASSERT(!protectedUnusedBytes); + firstUnusedPage = ((vector.length() * sizeof(T) - offsetToPage - 1) | pageMask) + + offsetToPage + 1; + if (MOZ_LIKELY(vector.capacity() * sizeof(T) >= firstUnusedPage)) + unprotectedUnusedPages = (vector.capacity() * sizeof(T) - firstUnusedPage) / pageSize; + else + unprotectedUnusedPages = 0; + protectUnusedEnabled = ProtectUnused && !protectionDisabled && + vector.capacity() * sizeof(T) >= protectionLowerBound && + vector.capacity() * sizeof(T) >= pageSize + offsetToPage; + } + + void updateProtectionOffsets() { + updateProtectUsedOffsets(); + updateProtectUnusedOffsets(); } void protect() { - if (!regionUnprotected && protectionEnabled && unprotectedBytes >= intptr_t(pageSize)) { + MOZ_ASSERT(!regionUnprotected); + if (MOZ_UNLIKELY(protectUsedEnabled && unprotectedBytes >= intptr_t(pageSize))) { size_t toProtect = size_t(unprotectedBytes) & ~pageMask; uintptr_t addr = uintptr_t(vector.begin()) + offsetToPage + protectedBytes; gc::MakePagesReadOnly(reinterpret_cast(addr), toProtect); @@ -89,9 +128,30 @@ class PageProtectingVector final } } + void protectUnused() { + MOZ_ASSERT(!protectedUnusedBytes); + if (protectUnusedEnabled && unprotectedUnusedPages) { + size_t toProtect = unprotectedUnusedPages * pageSize; + uintptr_t addr = uintptr_t(vector.begin()) + firstUnusedPage; + gc::ProtectPages(reinterpret_cast(addr), toProtect); + unprotectedUnusedPages = 0; + protectedUnusedBytes = toProtect; + } + } + + void protectNewBuffer() { + updateProtectionOffsets(); + if (protectUsedEnabled || protectUnusedEnabled) + MemoryProtectionExceptionHandler::addRegion(vector.begin(), + vector.capacity() * sizeof(T)); + protect(); + protectUnused(); + } + void unprotect() { - MOZ_ASSERT_IF(!protectionEnabled, !protectedBytes); - if (!regionUnprotected && protectedBytes) { + MOZ_ASSERT(!regionUnprotected); + MOZ_ASSERT_IF(!protectUsedEnabled, !protectedBytes); + if (protectedBytes) { uintptr_t addr = uintptr_t(vector.begin()) + offsetToPage; gc::UnprotectPages(reinterpret_cast(addr), protectedBytes); unprotectedBytes += protectedBytes; @@ -99,17 +159,24 @@ class PageProtectingVector final } } - void protectNewBuffer() { - updateOffsetToPage(); - if (protectionEnabled) - MemoryProtectionExceptionHandler::addRegion(vector.begin(), vector.capacity()); - protect(); + void unprotectUnused(size_t newSize) { + MOZ_ASSERT_IF(!protectUnusedEnabled, !protectedUnusedBytes); + if (MOZ_UNLIKELY(protectedUnusedBytes && newSize > firstUnusedPage)) { + size_t toUnprotect = ((newSize - firstUnusedPage) + pageMask) & ~pageMask; + if (toUnprotect > protectedUnusedBytes) + toUnprotect = protectedUnusedBytes; + uintptr_t addr = uintptr_t(vector.begin()) + firstUnusedPage; + gc::UnprotectPages(reinterpret_cast(addr), toUnprotect); + firstUnusedPage += toUnprotect; + protectedUnusedBytes -= toUnprotect; + } } void unprotectOldBuffer() { - if (protectionEnabled) - MemoryProtectionExceptionHandler::removeRegion(vector.begin()); unprotect(); + unprotectUnused(vector.capacity() * sizeof(T)); + if (protectUsedEnabled || protectUnusedEnabled) + MemoryProtectionExceptionHandler::removeRegion(vector.begin()); } bool anyProtected(size_t first, size_t last) { @@ -128,11 +195,16 @@ class PageProtectingVector final *addr = firstPage; } - void increaseElemsUsed(size_t used) { - unprotectedBytes += used * sizeof(T); + void protectAfterUsing(size_t size) { + unprotectedBytes += size * sizeof(T); protect(); } + void unprotectBeforeUsing(size_t size) { + MOZ_ASSERT(vector.length() + size <= vector.capacity()); + unprotectUnused((vector.length() + size) * sizeof(T)); + } + /* A helper class to simplify unprotecting and reprotecting when needed. */ class AutoUnprotect { @@ -162,14 +234,32 @@ class PageProtectingVector final pageSize(gc::SystemPageSize()), pageMask(pageSize - 1), offsetToPage(0), + firstUnusedPage(0), protectedBytes(0), + protectedUnusedBytes(0), unprotectedBytes(0), - protectionLowerBound(0), - protectionEnabled(false), - regionUnprotected(false) { protectNewBuffer(); } + unprotectedUnusedPages(0), + protectionLowerBound(InitialLowerBound), + protectUsedEnabled(false), + protectUnusedEnabled(false), + regionUnprotected(false), + protectionDisabled(false) { protectNewBuffer(); } ~PageProtectingVector() { unprotectOldBuffer(); } + void disableProtection() { + MOZ_ASSERT(!protectionDisabled); + unprotectOldBuffer(); + protectionDisabled = true; + updateProtectionOffsets(); + } + + void enableProtection() { + MOZ_ASSERT(protectionDisabled); + protectionDisabled = false; + protectNewBuffer(); + } + /* * Sets the lower bound on the size, in bytes, that this vector's underlying * capacity has to be before its used pages will be protected. @@ -233,8 +323,9 @@ class PageProtectingVector final template MOZ_ALWAYS_INLINE void infallibleAppend(const U* values, size_t size) { + unprotectBeforeUsing(size); vector.infallibleAppend(values, size); - increaseElemsUsed(size); + protectAfterUsing(size); } template @@ -244,10 +335,12 @@ class PageProtectingVector final AutoUnprotect guard; if (MOZ_UNLIKELY(vector.length() + size > vector.capacity())) guard.emplace(this); + else + unprotectBeforeUsing(size); ret = vector.append(values, size); } if (ret) - increaseElemsUsed(size); + protectAfterUsing(size); return ret; } }; diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index fa10c01db764..0da81a2fc0e5 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -352,7 +352,8 @@ class WriteBarrieredBase : public BarrieredBase explicit WriteBarrieredBase(const T& v) : BarrieredBase(v) {} public: - DECLARE_POINTER_COMPARISON_OPS(T); + using ElementType = T; + DECLARE_POINTER_CONSTREF_OPS(T); // Use this if the automatic coercion to T isn't working. @@ -449,10 +450,6 @@ class GCPtr : public WriteBarrieredBase DECLARE_POINTER_ASSIGN_OPS(GCPtr, T); - T unbarrieredGet() const { - return this->value; - } - private: void set(const T& v) { this->pre(); @@ -603,14 +600,13 @@ class ReadBarriered : public ReadBarrieredBase return *this; } - const T get() const { - if (!InternalBarrierMethods::isMarkable(this->value)) - return JS::GCPolicy::initial(); - this->read(); + const T& get() const { + if (InternalBarrierMethods::isMarkable(this->value)) + this->read(); return this->value; } - const T unbarrieredGet() const { + const T& unbarrieredGet() const { return this->value; } @@ -618,9 +614,9 @@ class ReadBarriered : public ReadBarrieredBase return bool(this->value); } - operator const T() const { return get(); } + operator const T&() const { return get(); } - const T operator->() const { return get(); } + const T& operator->() const { return get(); } T* unsafeGet() { return &this->value; } T const* unsafeGet() const { return &this->value; } @@ -951,6 +947,35 @@ typedef ReadBarriered ReadBarrieredWasmTableObject; typedef ReadBarriered ReadBarrieredValue; +namespace detail { + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const PreBarriered& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const GCPtr& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const HeapPtr& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const ReadBarriered& v) { return v.unbarrieredGet(); } +}; + +template <> +struct DefineComparisonOps : mozilla::TrueType { + static const Value& get(const HeapSlot& v) { return v.get(); } +}; + +} /* namespace detail */ + } /* namespace js */ #endif /* gc_Barrier_h */ diff --git a/js/src/jit-test/tests/ion/bug1322932.js b/js/src/jit-test/tests/ion/bug1322932.js new file mode 100644 index 000000000000..0de9737eeff1 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1322932.js @@ -0,0 +1,12 @@ +// |jit-test| error: ReferenceError + +(function() { + for (var i = 0; i < 4; ++i) { + if (i % 3 == 0) { + for (var x in y) {} + } else { + continue; + } + } +})() + diff --git a/js/src/jit/BaselineCacheIR.cpp b/js/src/jit/BaselineCacheIR.cpp index 05ed7f79746e..9f2da2fe9293 100644 --- a/js/src/jit/BaselineCacheIR.cpp +++ b/js/src/jit/BaselineCacheIR.cpp @@ -1711,6 +1711,60 @@ BaselineCacheIRCompiler::emitLoadDenseElementResult() return true; } +bool +BaselineCacheIRCompiler::emitGuardNoDenseElements() +{ + Register obj = allocator.useRegister(masm, reader.objOperandId()); + AutoScratchRegister scratch(allocator, masm); + + FailurePath* failure; + if (!addFailurePath(&failure)) + return false; + + // Load obj->elements. + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch); + + // Make sure there are no dense elements. + Address initLength(scratch, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::NotEqual, initLength, Imm32(0), failure->label()); + return true; +} + +bool +BaselineCacheIRCompiler::emitLoadDenseElementHoleResult() +{ + Register obj = allocator.useRegister(masm, reader.objOperandId()); + Register index = allocator.useRegister(masm, reader.int32OperandId()); + AutoScratchRegister scratch(allocator, masm); + + FailurePath* failure; + if (!addFailurePath(&failure)) + return false; + + // Make sure the index is nonnegative. + masm.branch32(Assembler::LessThan, index, Imm32(0), failure->label()); + + // Load obj->elements. + masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch); + + // Guard on the initialized length. + Label hole; + Address initLength(scratch, ObjectElements::offsetOfInitializedLength()); + masm.branch32(Assembler::BelowOrEqual, initLength, index, &hole); + + // Load the value. + Label done; + masm.loadValue(BaseObjectElementIndex(scratch, index), R0); + masm.branchTestMagic(Assembler::NotEqual, R0, &done); + + // Load undefined for the hole. + masm.bind(&hole); + masm.moveValue(UndefinedValue(), R0); + + masm.bind(&done); + return true; +} + bool BaselineCacheIRCompiler::emitLoadUnboxedArrayElementResult() { diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 1f7bc7e56342..6947df5596a2 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -96,6 +96,8 @@ GetPropIRGenerator::tryAttachStub() ValOperandId indexId = getElemKeyValueId(); if (tryAttachDenseElement(obj, objId, indexId)) return true; + if (tryAttachDenseElementHole(obj, objId, indexId)) + return true; if (tryAttachUnboxedArrayElement(obj, objId, indexId)) return true; if (tryAttachArgumentsObjectArg(obj, objId, indexId)) @@ -908,6 +910,88 @@ GetPropIRGenerator::tryAttachDenseElement(HandleObject obj, ObjOperandId objId, return true; } +static bool +CanAttachDenseElementHole(JSObject* obj) +{ + // Make sure this object already has dense elements. + if (obj->as().getDenseInitializedLength() == 0) + return false; + + // Now we have to make sure the objects on the prototype don't + // have any int32 properties or that such properties can't appear + // without a shape change. + // Otherwise returning undefined for holes would obviously be incorrect, + // because we would have to lookup a property on the prototype instead. + do { + if (obj->isIndexed()) + return false; + + if (ClassCanHaveExtraProperties(obj->getClass())) + return false; + + JSObject* proto = obj->staticPrototype(); + if (!proto) + break; + + if (!proto->isNative()) + return false; + + // Make sure objects on the prototype don't have dense elements. + if (proto->as().getDenseInitializedLength() != 0) + return false; + + obj = proto; + } while (true); + + return true; +} + +bool +GetPropIRGenerator::tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId, + ValOperandId indexId) +{ + MOZ_ASSERT(idVal_.isInt32()); + + if (idVal_.toInt32() < 0) + return false; + + if (!obj->isNative() || !CanAttachDenseElementHole(obj)) + return false; + + // Guard on the shape, to prevent non-dense elements from appearing. + writer.guardShape(objId, obj->as().lastProperty()); + + if (obj->hasUncacheableProto()) { + // If the shape does not imply the proto, emit an explicit proto guard. + writer.guardProto(objId, obj->staticPrototype()); + } + + JSObject* pobj = obj->staticPrototype(); + while (pobj) { + ObjOperandId protoId = writer.loadObject(pobj); + + // Non-singletons with uncacheable protos can change their proto + // without a shape change, so also guard on the group (which determines + // the proto) in this case. + if (pobj->hasUncacheableProto() && !pobj->isSingleton()) + writer.guardGroup(protoId, pobj->group()); + + // Make sure the shape matches, to avoid non-dense elements or anything + // else that is being checked by CanAttachDenseElementHole. + writer.guardShape(protoId, pobj->as().lastProperty()); + + // Also make sure there are no dense elements. + writer.guardNoDenseElements(protoId); + + pobj = pobj->staticPrototype(); + } + + Int32OperandId int32IndexId = writer.guardIsInt32(indexId); + writer.loadDenseElementHoleResult(objId, int32IndexId); + writer.typeMonitorResult(); + return true; +} + bool GetPropIRGenerator::tryAttachUnboxedArrayElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId) diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index f1976b056e8e..55f80cffbb2b 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -145,6 +145,7 @@ enum class CacheKind : uint8_t _(GuardNoDetachedTypedObjects) \ _(GuardMagicValue) \ _(GuardFrameHasNoArgumentsObject) \ + _(GuardNoDenseElements) \ _(GuardNoUnboxedExpando) \ _(GuardAndLoadUnboxedExpando) \ _(LoadObject) \ @@ -160,6 +161,7 @@ enum class CacheKind : uint8_t _(LoadUnboxedPropertyResult) \ _(LoadTypedObjectResult) \ _(LoadDenseElementResult) \ + _(LoadDenseElementHoleResult) \ _(LoadUnboxedArrayElementResult) \ _(LoadTypedElementResult) \ _(LoadInt32ArrayLengthResult) \ @@ -450,6 +452,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter void loadFrameArgumentResult(Int32OperandId index) { writeOpWithOperandId(CacheOp::LoadFrameArgumentResult, index); } + void guardNoDenseElements(ObjOperandId obj) { + writeOpWithOperandId(CacheOp::GuardNoDenseElements, obj); + } void guardNoUnboxedExpando(ObjOperandId obj) { writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj); } @@ -534,6 +539,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter writeOpWithOperandId(CacheOp::LoadDenseElementResult, obj); writeOperandId(index); } + void loadDenseElementHoleResult(ObjOperandId obj, Int32OperandId index) { + writeOpWithOperandId(CacheOp::LoadDenseElementHoleResult, obj); + writeOperandId(index); + } void loadUnboxedArrayElementResult(ObjOperandId obj, Int32OperandId index, JSValueType elementType) { writeOpWithOperandId(CacheOp::LoadUnboxedArrayElementResult, obj); writeOperandId(index); @@ -682,6 +691,7 @@ class MOZ_RAII GetPropIRGenerator bool tryAttachArgumentsObjectArg(HandleObject obj, ObjOperandId objId, ValOperandId indexId); bool tryAttachDenseElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId); + bool tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId, ValOperandId indexId); bool tryAttachUnboxedArrayElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId); bool tryAttachTypedElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index fd15c55e6e3b..661b4d26138c 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -4512,6 +4512,7 @@ jit::MarkLoopBlocks(MIRGraph& graph, MBasicBlock* header, bool* canOsr) // A block not marked by the time we reach it is not in the loop. if (!block->isMarked()) continue; + // This block is in the loop; trace to its predecessors. for (size_t p = 0, e = block->numPredecessors(); p != e; ++p) { MBasicBlock* pred = block->getPredecessor(p); @@ -4546,7 +4547,7 @@ jit::MarkLoopBlocks(MIRGraph& graph, MBasicBlock* header, bool* canOsr) // If the nested loop is not contiguous, we may have already // passed its backedge. If this happens, back up. - if (backedge->id() > block->id()) { + if (innerBackedge->id() > block->id()) { i = graph.poBegin(innerBackedge); --i; } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index c10718822592..5f4d1b462024 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -1507,8 +1507,10 @@ IonBuilder::visitBlock(const CFGBlock* cfgblock, MBasicBlock* mblock) // Optimization to move a predecessor that only has this block as successor // just before this block. - if (mblock->numPredecessors() == 1 && mblock->getPredecessor(0)->numSuccessors() == 1) - graph().moveBlockToEnd(mblock->getPredecessor(0)); + if (mblock->numPredecessors() == 1 && mblock->getPredecessor(0)->numSuccessors() == 1) { + graph().removeBlockFromList(mblock->getPredecessor(0)); + graph().addBlock(mblock->getPredecessor(0)); + } if (!setCurrentAndSpecializePhis(mblock)) return false; diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index b6406f2b5e44..b0ea00d934ab 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1536,10 +1536,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM // Instrumentation for entering and leaving the profiler. void profilerEnterFrame(Register framePtr, Register scratch); void profilerExitFrame(); - - struct AutoPrepareForPatching { - explicit AutoPrepareForPatching(MacroAssemblerARMCompat&) {} - }; }; typedef MacroAssemblerARMCompat MacroAssemblerSpecific; diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index b95831443501..27a51f461587 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -2316,10 +2316,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler return nextOffset().getOffset(); } - struct AutoPrepareForPatching { - explicit AutoPrepareForPatching(MacroAssemblerCompat&) {} - }; - protected: bool buildOOLFakeExitFrame(void* fakeReturnAddr) { uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS, diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared.h index c9bd4a4d9027..75838c4b0670 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.h @@ -249,11 +249,6 @@ class MacroAssemblerMIPSShared : public Assembler void atomicExchange(int nbytes, bool signExtend, const BaseIndex& address, Register value, Register valueTemp, Register offsetTemp, Register maskTemp, Register output); - - public: - struct AutoPrepareForPatching { - explicit AutoPrepareForPatching(MacroAssemblerMIPSShared&) {} - }; }; } // namespace jit diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index f27de5153e79..89a53490e103 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -425,12 +425,6 @@ class MacroAssemblerNone : public Assembler Address ToPayload(Address) { MOZ_CRASH(); } Address ToType(Address) { MOZ_CRASH(); } #endif - - struct AutoPrepareForPatching { - explicit AutoPrepareForPatching(MacroAssemblerNone&) { - MOZ_CRASH(); - } - }; }; typedef MacroAssemblerNone MacroAssemblerSpecific; diff --git a/js/src/jit/x86-shared/Assembler-x86-shared.h b/js/src/jit/x86-shared/Assembler-x86-shared.h index d781b79ed101..4bf5a0d29e36 100644 --- a/js/src/jit/x86-shared/Assembler-x86-shared.h +++ b/js/src/jit/x86-shared/Assembler-x86-shared.h @@ -1060,14 +1060,7 @@ class AssemblerX86Shared : public AssemblerShared return CodeOffset(masm.call().offset()); } - struct AutoPrepareForPatching : X86Encoding::AutoUnprotectAssemblerBufferRegion { - explicit AutoPrepareForPatching(AssemblerX86Shared& masm) - : X86Encoding::AutoUnprotectAssemblerBufferRegion(masm.masm, 0, masm.size()) - {} - }; - void patchCall(uint32_t callerOffset, uint32_t calleeOffset) { - // The caller uses AutoUnprotectBuffer. unsigned char* code = masm.data(); X86Encoding::SetRel32(code + callerOffset, code + calleeOffset); } @@ -1075,7 +1068,6 @@ class AssemblerX86Shared : public AssemblerShared return CodeOffset(masm.jmp().offset()); } void patchFarJump(CodeOffset farJump, uint32_t targetOffset) { - // The caller uses AutoUnprotectBuffer. unsigned char* code = masm.data(); X86Encoding::SetRel32(code + farJump.offset(), code + targetOffset); } diff --git a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h index 8cb5577848e6..4c583f863e17 100644 --- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h +++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h @@ -84,12 +84,7 @@ namespace jit { } public: - AssemblerBuffer() - : m_oom(false) - { - // Provide memory protection once the buffer starts to get big. - m_buffer.setLowerBoundForProtection(32 * 1024); - } + AssemblerBuffer() : m_oom(false) {} void ensureSpace(size_t space) { @@ -141,13 +136,6 @@ namespace jit { return m_buffer.begin(); } - void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) { - m_buffer.unprotectRegion(firstByteOffset, lastByteOffset); - } - void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) { - m_buffer.reprotectRegion(firstByteOffset, lastByteOffset); - } - protected: /* * OOM handling: This class can OOM in the ensureSpace() method trying @@ -168,7 +156,13 @@ namespace jit { m_buffer.clear(); } - PageProtectingVector m_buffer; +#ifndef RELEASE_OR_BETA + PageProtectingVector m_buffer; +#else + mozilla::Vector m_buffer; +#endif bool m_oom; }; diff --git a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h index 844fd5c0ed9c..c2c21507e52f 100644 --- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h @@ -45,17 +45,6 @@ namespace X86Encoding { class BaseAssembler; -class AutoUnprotectAssemblerBufferRegion -{ - BaseAssembler* assembler; - size_t firstByteOffset; - size_t lastByteOffset; - - public: - AutoUnprotectAssemblerBufferRegion(BaseAssembler& holder, int32_t offset, size_t size); - ~AutoUnprotectAssemblerBufferRegion(); -}; - class BaseAssembler : public GenericAssembler { public: BaseAssembler() @@ -3819,7 +3808,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off MOZ_RELEASE_ASSERT(to.offset() == -1 || size_t(to.offset()) <= size()); unsigned char* code = m_formatter.data(); - AutoUnprotectAssemblerBufferRegion unprotect(*this, from.offset() - 4, 4); SetInt32(code + from.offset(), to.offset()); } @@ -3838,7 +3826,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off spew(".set .Lfrom%d, .Llabel%d", from.offset(), to.offset()); unsigned char* code = m_formatter.data(); - AutoUnprotectAssemblerBufferRegion unprotect(*this, from.offset() - 4, 4); SetRel32(code + from.offset(), code + to.offset()); } @@ -3851,13 +3838,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off return m_formatter.append(other.m_formatter.buffer(), other.size()); } - void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) { - m_formatter.unprotectDataRegion(firstByteOffset, lastByteOffset); - } - void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) { - m_formatter.reprotectDataRegion(firstByteOffset, lastByteOffset); - } - protected: static bool CAN_SIGN_EXTEND_8_32(int32_t value) { return value == (int32_t)(int8_t)value; } static bool CAN_SIGN_EXTEND_16_32(int32_t value) { return value == (int32_t)(int16_t)value; } @@ -5129,13 +5109,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off return m_buffer.append(values, size); } - void unprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) { - m_buffer.unprotectDataRegion(firstByteOffset, lastByteOffset); - } - void reprotectDataRegion(size_t firstByteOffset, size_t lastByteOffset) { - m_buffer.reprotectDataRegion(firstByteOffset, lastByteOffset); - } - private: // Internals; ModRm and REX formatters. @@ -5368,23 +5341,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off bool useVEX_; }; -MOZ_ALWAYS_INLINE -AutoUnprotectAssemblerBufferRegion::AutoUnprotectAssemblerBufferRegion(BaseAssembler& holder, - int32_t offset, size_t size) -{ - assembler = &holder; - MOZ_ASSERT(offset >= 0); - firstByteOffset = size_t(offset); - lastByteOffset = firstByteOffset + (size - 1); - assembler->unprotectDataRegion(firstByteOffset, lastByteOffset); -} - -MOZ_ALWAYS_INLINE -AutoUnprotectAssemblerBufferRegion::~AutoUnprotectAssemblerBufferRegion() -{ - assembler->reprotectDataRegion(firstByteOffset, lastByteOffset); -} - } // namespace X86Encoding } // namespace jit diff --git a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp index 74512a53fa29..e68aa456ff77 100644 --- a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp +++ b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp @@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "mozilla/TypeTraits.h" #include "mozilla/UniquePtr.h" #include "js/RootingAPI.h" @@ -151,3 +152,111 @@ TestHeapPostBarrierInitFailure() } END_TEST(testGCHeapPostBarriers) + +BEGIN_TEST(testUnbarrieredEquality) +{ + // Use ArrayBuffers because they have finalizers, which allows using them + // in ObjectPtr without awkward conversations about nursery allocatability. + JS::RootedObject robj(cx, JS_NewArrayBuffer(cx, 20)); + JS::RootedObject robj2(cx, JS_NewArrayBuffer(cx, 30)); + cx->gc.evictNursery(); // Need tenured objects + + // Need some bare pointers to compare against. + JSObject* obj = robj; + JSObject* obj2 = robj2; + const JSObject* constobj = robj; + const JSObject* constobj2 = robj2; + + // Make them gray. We will make sure they stay gray. (For most reads, the + // barrier will unmark gray.) + using namespace js::gc; + TenuredCell* cell = &obj->asTenured(); + TenuredCell* cell2 = &obj2->asTenured(); + cell->markIfUnmarked(GRAY); + cell2->markIfUnmarked(GRAY); + MOZ_ASSERT(cell->isMarked(GRAY)); + MOZ_ASSERT(cell2->isMarked(GRAY)); + + { + JS::Heap heap(obj); + JS::Heap heap2(obj2); + CHECK(TestWrapper(obj, obj2, heap, heap2)); + CHECK(TestWrapper(constobj, constobj2, heap, heap2)); + } + + { + JS::TenuredHeap heap(obj); + JS::TenuredHeap heap2(obj2); + CHECK(TestWrapper(obj, obj2, heap, heap2)); + CHECK(TestWrapper(constobj, constobj2, heap, heap2)); + } + + { + JS::ObjectPtr objptr(obj); + JS::ObjectPtr objptr2(obj2); + CHECK(TestWrapper(obj, obj2, objptr, objptr2)); + CHECK(TestWrapper(constobj, constobj2, objptr, objptr2)); + objptr.finalize(cx); + objptr2.finalize(cx); + } + + // Sanity check that the barriers normally mark things black. + { + JS::Heap heap(obj); + JS::Heap heap2(obj2); + heap.get(); + heap2.get(); + CHECK(cell->isMarked(BLACK)); + CHECK(cell2->isMarked(BLACK)); + } + + return true; +} + +template +bool +TestWrapper(ObjectT obj, ObjectT obj2, WrapperT& wrapper, WrapperT& wrapper2) +{ + using namespace js::gc; + + const TenuredCell& cell = obj->asTenured(); + const TenuredCell& cell2 = obj2->asTenured(); + + int x = 0; + + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += obj == obj2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += obj == wrapper2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += wrapper == obj2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += wrapper == wrapper2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + + CHECK(x == 0); + + x += obj != obj2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += obj != wrapper2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += wrapper != obj2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += wrapper != wrapper2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + + CHECK(x == 4); + + return true; +} + +END_TEST(testUnbarrieredEquality) diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 7f46a83d7594..0686f1789e01 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -291,7 +291,7 @@ NativeObject::setSlotWithType(ExclusiveContext* cx, Shape* shape, inline void NativeObject::updateShapeAfterMovingGC() { - Shape* shape = shape_.unbarrieredGet(); + Shape* shape = shape_; if (IsForwarded(shape)) shape_.unsafeSet(Forwarded(shape)); } diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 5d5f083f6f07..dffebc3dd496 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -418,7 +418,7 @@ struct ObjectGroupCompartment::NewEntry } static inline bool match(const ObjectGroupCompartment::NewEntry& key, const Lookup& lookup) { - TaggedProto proto = key.group.unbarrieredGet()->proto().unbarrieredGet(); + TaggedProto proto = key.group.unbarrieredGet()->proto(); JSObject* assoc = key.associated; MOZ_ASSERT(proto.hasUniqueId()); MOZ_ASSERT_IF(assoc, assoc->zone()->hasUniqueId(assoc)); diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index b8c48780e59d..210c7d092f76 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -124,7 +124,7 @@ Shape::new_(ExclusiveContext* cx, Handle other, uint32_t nfixed) inline void Shape::updateBaseShapeAfterMovingGC() { - BaseShape* base = base_.unbarrieredGet(); + BaseShape* base = base_; if (IsForwarded(base)) base_.unsafeSet(Forwarded(base)); } diff --git a/js/src/vm/SharedMem.h b/js/src/vm/SharedMem.h index 9701a708dc79..a8f78899800c 100644 --- a/js/src/vm/SharedMem.h +++ b/js/src/vm/SharedMem.h @@ -12,8 +12,8 @@ template class SharedMem { - static_assert(mozilla::IsPointer::value, - "SharedMem encapsulates pointer types"); + // static_assert(mozilla::IsPointer::value, + // "SharedMem encapsulates pointer types"); enum Sharedness { IsUnshared, diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp index 3b0c04953b49..2fa8ec3ddcf8 100644 --- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -272,8 +272,6 @@ typedef HashMap, SystemAllocPolicy> bool ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits) { - MacroAssembler::AutoPrepareForPatching patching(masm_); - masm_.haltingAlign(CodeAlignment); // Create far jumps for calls that have relative offsets that may otherwise @@ -369,8 +367,6 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits) bool ModuleGenerator::patchFarJumps(const TrapExitOffsetArray& trapExits) { - MacroAssembler::AutoPrepareForPatching patching(masm_); - for (CallThunk& callThunk : metadata_->callThunks) { uint32_t funcIndex = callThunk.u.funcIndex; callThunk.u.codeRangeIndex = funcToCodeRange_[funcIndex]; diff --git a/js/xpconnect/src/XPCInlines.h b/js/xpconnect/src/XPCInlines.h index 20c63c9729d1..b274e0deda69 100644 --- a/js/xpconnect/src/XPCInlines.h +++ b/js/xpconnect/src/XPCInlines.h @@ -471,7 +471,7 @@ inline void XPCWrappedNativeTearOff::JSObjectMoved(JSObject* obj, const JSObject* old) { MOZ_ASSERT(!IsMarked()); - MOZ_ASSERT(mJSObject.unbarrieredGetPtr() == old); + MOZ_ASSERT(mJSObject == old); mJSObject = obj; } diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 152abdf9ba91..aefbe4c97ba4 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -940,7 +940,7 @@ void XPCWrappedNative::FlatJSObjectMoved(JSObject* obj, const JSObject* old) { JS::AutoAssertGCCallback inCallback(obj); - MOZ_ASSERT(mFlatJSObject.unbarrieredGetPtr() == old); + MOZ_ASSERT(mFlatJSObject == old); nsWrapperCache* cache = nullptr; CallQueryInterface(mIdentity, &cache); diff --git a/js/xpconnect/src/XPCWrappedNativeProto.cpp b/js/xpconnect/src/XPCWrappedNativeProto.cpp index d9c95a3e665b..825ae45f96c6 100644 --- a/js/xpconnect/src/XPCWrappedNativeProto.cpp +++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp @@ -115,7 +115,7 @@ XPCWrappedNativeProto::CallPostCreatePrototype() void XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj) { - MOZ_ASSERT(obj == mJSProtoObject.unbarrieredGet(), "huh?"); + MOZ_ASSERT(obj == mJSProtoObject, "huh?"); // Only remove this proto from the map if it is the one in the map. ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap(); @@ -130,7 +130,7 @@ XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj) void XPCWrappedNativeProto::JSProtoObjectMoved(JSObject* obj, const JSObject* old) { - MOZ_ASSERT(mJSProtoObject.unbarrieredGet() == old); + MOZ_ASSERT(mJSProtoObject == old); mJSProtoObject.init(obj); // Update without triggering barriers. } diff --git a/layout/generic/test/file_bug514732_window.xul b/layout/generic/test/file_bug514732_window.xul index c6aae6ace829..1dc40b14fe06 100644 --- a/layout/generic/test/file_bug514732_window.xul +++ b/layout/generic/test/file_bug514732_window.xul @@ -74,5 +74,5 @@ ]]> - + diff --git a/layout/reftests/bugs/558011-1-ref.xul b/layout/reftests/bugs/558011-1-ref.xul index 2183e8741b33..e129def01116 100644 --- a/layout/reftests/bugs/558011-1-ref.xul +++ b/layout/reftests/bugs/558011-1-ref.xul @@ -8,7 +8,7 @@ this is a really really really really long test sentence - + diff --git a/layout/reftests/bugs/558011-1.xul b/layout/reftests/bugs/558011-1.xul index 28af46859e5d..c2c58ad640f3 100644 --- a/layout/reftests/bugs/558011-1.xul +++ b/layout/reftests/bugs/558011-1.xul @@ -8,7 +8,7 @@ this is a really really really really long test sentence - + diff --git a/layout/reftests/reftest.list b/layout/reftests/reftest.list index b2da025d5f86..f51103ec06de 100644 --- a/layout/reftests/reftest.list +++ b/layout/reftests/reftest.list @@ -365,6 +365,9 @@ include transform-3d/reftest.list # unicode/ (verify that we don't do expend effort doing unicode-aware case checks) include unicode/reftest.list +# usercss +include usercss/reftest.list + include view-source/reftest.list # web-animations diff --git a/layout/reftests/usercss/reftest.list b/layout/reftests/usercss/reftest.list new file mode 100644 index 000000000000..511167c92e28 --- /dev/null +++ b/layout/reftests/usercss/reftest.list @@ -0,0 +1 @@ +== usercss.html usercss-ref.html diff --git a/layout/reftests/usercss/usercss-ref.html b/layout/reftests/usercss/usercss-ref.html new file mode 100644 index 000000000000..78538612c722 --- /dev/null +++ b/layout/reftests/usercss/usercss-ref.html @@ -0,0 +1,10 @@ + + + + + + +

This paragraph should have a green background.

+

This paragraph should have a green background, too.

+ + diff --git a/layout/reftests/usercss/usercss.html b/layout/reftests/usercss/usercss.html new file mode 100644 index 000000000000..ce8e3bd4f4ce --- /dev/null +++ b/layout/reftests/usercss/usercss.html @@ -0,0 +1,10 @@ + + + + + + +

This paragraph should have a green background.

+

This paragraph should have a green background, too.

+ + diff --git a/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list b/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list index 0649186f5d84..0c8d707a8275 100644 --- a/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list +++ b/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list @@ -3,7 +3,7 @@ # text-emphasis-style == text-emphasis-style-property-001.html text-emphasis-style-property-001-ref.html -fuzzy-if(gtkWidget,3,4) fuzzy-if(skiaContent,87,80) == text-emphasis-style-property-002.html text-emphasis-style-property-002-ref.html +fuzzy-if(gtkWidget,3,4) fuzzy-if(skiaContent,103,80) == text-emphasis-style-property-002.html text-emphasis-style-property-002-ref.html skip-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == text-emphasis-style-property-003.html text-emphasis-style-property-003-ref.html skip-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == text-emphasis-style-property-004.html text-emphasis-style-property-004-ref.html == text-emphasis-style-property-005.html text-emphasis-style-property-005-ref.html @@ -53,7 +53,7 @@ fuzzy-if(gtkWidget,3,4) == text-emphasis-color-property-002.html text-emphasis-c # text-emphasis == text-emphasis-property-001.html text-emphasis-style-property-001-ref.html -fuzzy-if(gtkWidget,3,4) fuzzy-if(skiaContent,87,80) == text-emphasis-property-002.html text-emphasis-style-property-002-ref.html +fuzzy-if(gtkWidget,3,4) fuzzy-if(skiaContent,103,80) == text-emphasis-property-002.html text-emphasis-style-property-002-ref.html fuzzy-if(gtkWidget,3,4) == text-emphasis-property-003.html text-emphasis-style-property-012-ref.html fuzzy-if(gtkWidget,3,4) == text-emphasis-property-003a.html text-emphasis-style-property-012-ref.html fuzzy-if(gtkWidget,3,4) == text-emphasis-property-003b.html text-emphasis-style-property-012-ref.html diff --git a/layout/tools/layout-debug/ui/content/layoutdebug.xul b/layout/tools/layout-debug/ui/content/layoutdebug.xul index 8de04847f8bf..93b947218859 100644 --- a/layout/tools/layout-debug/ui/content/layoutdebug.xul +++ b/layout/tools/layout-debug/ui/content/layoutdebug.xul @@ -177,7 +177,7 @@ - diff --git a/layout/tools/recording/recording.xul b/layout/tools/recording/recording.xul index 276d3aa71f80..e98aaebdc1aa 100644 --- a/layout/tools/recording/recording.xul +++ b/layout/tools/recording/recording.xul @@ -9,5 +9,5 @@ style="background:white; overflow:hidden; width:800px; height:600px;" > diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/empty-but-slow-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/empty-but-slow-worker.js new file mode 100644 index 000000000000..92abac7a384d --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/empty-but-slow-worker.js @@ -0,0 +1,8 @@ +addEventListener('fetch', evt => { + if (evt.request.url.endsWith('slow')) { + // Performance.now() might be a bit better here, but Date.now() has + // better compat in workers right now. + let start = Date.now(); + while(Date.now() - start < 2000); + } +}); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audiobuffer-interface/idl-test.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audiobuffer-interface/idl-test.html index 4ef8b7ad1e12..46dd6b89a636 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audiobuffer-interface/idl-test.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audiobuffer-interface/idl-test.html @@ -73,7 +73,14 @@ interface AudioContext : EventTarget { };
-
interface AudioBuffer {
+   
dictionary AudioBufferOptions {
+             unsigned long numberOfChannels = 1;
+    required unsigned long length;
+             float         sampleRate;
+};
+
+[Constructor(AudioContext context, AudioBufferOptions options)]
+interface AudioBuffer {
 
     readonly attribute float sampleRate;
     readonly attribute long length;
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/idl-test.html b/testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/idl-test.html
index 841bd992a295..d8e92fd8e57f 100644
--- a/testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/idl-test.html
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/idl-test.html
@@ -125,7 +125,13 @@ interface AudioNode : EventTarget {
 
 };
-
interface DelayNode : AudioNode {
+
dictionary DelayOptions : AudioNodeOptions {
+             double maxDelayTime = 1;
+             double delayTime = 0;
+};
+
+[Constructor(AudioContext context, optional DelayOptions options)]
+interface DelayNode : AudioNode {
 
     readonly attribute AudioParam delayTime;
 
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-gainnode-interface/idl-test.html b/testing/web-platform/tests/webaudio/the-audio-api/the-gainnode-interface/idl-test.html
index ff28f4d57ff4..d23b38402053 100644
--- a/testing/web-platform/tests/webaudio/the-audio-api/the-gainnode-interface/idl-test.html
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-gainnode-interface/idl-test.html
@@ -125,7 +125,12 @@ interface AudioNode : EventTarget {
 
 };
-
interface GainNode : AudioNode {
+
dictionary GainOptions : AudioNodeOptions {
+             float gain = 1.0;
+};
+
+[Constructor(AudioContext context, optional GainOptions options)]
+interface GainNode : AudioNode {
 
     readonly attribute AudioParam gain;
 
diff --git a/toolkit/components/printing/content/printUtils.js b/toolkit/components/printing/content/printUtils.js
index 08abb6d799f9..e39da7f0ee2d 100644
--- a/toolkit/components/printing/content/printUtils.js
+++ b/toolkit/components/printing/content/printUtils.js
@@ -20,7 +20,7 @@
  * sends.
  *
  * This also means that 's that hope to use PrintUtils must have
- * their type attribute set to either "content" or "content-primary".
+ * their type attribute set to "content".
  *
  * PrintUtils sends messages at different points in its implementation, but
  * their documentation is consolidated here for ease-of-access.
@@ -165,13 +165,12 @@ var PrintUtils = {
    *
    *        getPrintPreviewBrowser:
    *          Returns the  to display the print preview in. This
-   *           must have its type attribute set to "content" or
-   *          "content-primary".
+   *           must have its type attribute set to "content".
    *
    *        getSourceBrowser:
    *          Returns the  that contains the document being
    *          printed. This  must have its type attribute set to
-   *          "content" or "content-primary".
+   *          "content".
    *
    *        getNavToolbox:
    *          Returns the primary toolbox for this window.
diff --git a/toolkit/components/viewsource/content/viewPartialSource.xul b/toolkit/components/viewsource/content/viewPartialSource.xul
index fdec367b1c1a..92f26bfc408f 100644
--- a/toolkit/components/viewsource/content/viewPartialSource.xul
+++ b/toolkit/components/viewsource/content/viewPartialSource.xul
@@ -155,7 +155,7 @@
   
 
   
-    
     
   
diff --git a/toolkit/components/viewsource/content/viewSource.xul b/toolkit/components/viewsource/content/viewSource.xul
index c6ca58234e1c..35d4833578ce 100644
--- a/toolkit/components/viewsource/content/viewSource.xul
+++ b/toolkit/components/viewsource/content/viewSource.xul
@@ -223,7 +223,8 @@
 
   
 
-    
     
   
diff --git a/toolkit/content/tests/chrome/bug263683_window.xul b/toolkit/content/tests/chrome/bug263683_window.xul
index 2df67d121b40..c2d831a5e105 100644
--- a/toolkit/content/tests/chrome/bug263683_window.xul
+++ b/toolkit/content/tests/chrome/bug263683_window.xul
@@ -228,7 +228,7 @@
     }
   ]]>
 
-  
-  
+  
+  
   
 
diff --git a/toolkit/content/tests/chrome/bug304188_window.xul b/toolkit/content/tests/chrome/bug304188_window.xul
index 931fd5c735a5..292b337e2dfc 100644
--- a/toolkit/content/tests/chrome/bug304188_window.xul
+++ b/toolkit/content/tests/chrome/bug304188_window.xul
@@ -88,7 +88,7 @@ find-menu appears in editor element which has had makeEditable() called but desi
     }
   ]]>
 
-  
-  
+  
+  
   
 
diff --git a/toolkit/content/tests/chrome/bug331215_window.xul b/toolkit/content/tests/chrome/bug331215_window.xul
index 90a03d961386..223cf802c0cc 100644
--- a/toolkit/content/tests/chrome/bug331215_window.xul
+++ b/toolkit/content/tests/chrome/bug331215_window.xul
@@ -99,7 +99,7 @@
   
     
   
-  
-  
+  
+  
   
 
diff --git a/toolkit/content/tests/chrome/bug360437_window.xul b/toolkit/content/tests/chrome/bug360437_window.xul
index 08498b58b2de..caafdf2dbfa9 100644
--- a/toolkit/content/tests/chrome/bug360437_window.xul
+++ b/toolkit/content/tests/chrome/bug360437_window.xul
@@ -114,7 +114,7 @@
     }
   ]]>
   
-  
-  
+  
+  
   
 
diff --git a/toolkit/content/tests/chrome/bug409624_window.xul b/toolkit/content/tests/chrome/bug409624_window.xul
index 002cbe0421ee..b1c5091488ec 100644
--- a/toolkit/content/tests/chrome/bug409624_window.xul
+++ b/toolkit/content/tests/chrome/bug409624_window.xul
@@ -93,6 +93,6 @@
     SimpleTest.waitForFocus(startTest, window);
   ]]>
 
-  
+  
   
 
diff --git a/toolkit/content/tests/chrome/bug429723_window.xul b/toolkit/content/tests/chrome/bug429723_window.xul
index 28439ae8e796..720dbe3fb239 100644
--- a/toolkit/content/tests/chrome/bug429723_window.xul
+++ b/toolkit/content/tests/chrome/bug429723_window.xul
@@ -79,6 +79,6 @@
   
     
   
-  
+  
   
 
diff --git a/toolkit/content/tests/chrome/bug451540_window.xul b/toolkit/content/tests/chrome/bug451540_window.xul
index f5fb45377c23..152c8996e40e 100644
--- a/toolkit/content/tests/chrome/bug451540_window.xul
+++ b/toolkit/content/tests/chrome/bug451540_window.xul
@@ -233,7 +233,7 @@
     SimpleTest.waitForFocus(startTest, window);
   ]]>
 
-  
-  
+  
+  
   
 
diff --git a/toolkit/content/tests/chrome/findbar_entireword_window.xul b/toolkit/content/tests/chrome/findbar_entireword_window.xul
index 35a2cae9a135..8e7656eb6399 100644
--- a/toolkit/content/tests/chrome/findbar_entireword_window.xul
+++ b/toolkit/content/tests/chrome/findbar_entireword_window.xul
@@ -267,7 +267,7 @@
   
     
   
-  
-  
+  
+  
   
 
diff --git a/toolkit/content/tests/chrome/findbar_events_window.xul b/toolkit/content/tests/chrome/findbar_events_window.xul
index 1eeb0271c81c..bf2188c5099d 100644
--- a/toolkit/content/tests/chrome/findbar_events_window.xul
+++ b/toolkit/content/tests/chrome/findbar_events_window.xul
@@ -173,7 +173,7 @@
     }
   ]]>
 
-  
-  
+  
+  
   
 
diff --git a/toolkit/content/tests/chrome/findbar_window.xul b/toolkit/content/tests/chrome/findbar_window.xul
index 72a259f0a408..037c9c819a5e 100644
--- a/toolkit/content/tests/chrome/findbar_window.xul
+++ b/toolkit/content/tests/chrome/findbar_window.xul
@@ -770,7 +770,7 @@
   
     
   
-  
-  
+  
+  
   
 
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js b/toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js
index 05c30d3ee658..529aec5a1c3c 100644
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js
+++ b/toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js
@@ -409,7 +409,8 @@ function() {
 
       this._restoreBrowser(browser);
 
-      browser.setAttribute("type", "content-primary");
+      browser.setAttribute("type", "content");
+      browser.setAttribute("primary", "true");
 
       this.beginBatchOperation();
 
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js b/toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js
index c363455d1663..acd6b5905a58 100644
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js
+++ b/toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js
@@ -213,7 +213,8 @@ BrowserView.prototype = {
       currentBrowser.docShell.isOffScreenBrowser = false;
     }
 
-    browser.setAttribute("type", "content-primary");
+    browser.setAttribute("type", "content");
+    browser.setAttribute("primary", "true");
     if (!skipZoom)
       browser.docShell.isOffScreenBrowser = true;
 
diff --git a/xpfe/appshell/nsChromeTreeOwner.cpp b/xpfe/appshell/nsChromeTreeOwner.cpp
index fec0dabe237a..8e2f26805825 100644
--- a/xpfe/appshell/nsChromeTreeOwner.cpp
+++ b/xpfe/appshell/nsChromeTreeOwner.cpp
@@ -139,10 +139,10 @@ NS_IMETHODIMP nsChromeTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
 
 NS_IMETHODIMP
 nsChromeTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
-                                     bool aPrimary, const nsAString& aID)
+                                     bool aPrimary)
 {
   NS_ENSURE_STATE(mXULWindow);
-  return mXULWindow->ContentShellAdded(aContentShell, aPrimary, aID);
+  return mXULWindow->ContentShellAdded(aContentShell, aPrimary);
 }
 
 NS_IMETHODIMP
diff --git a/xpfe/appshell/nsContentTreeOwner.cpp b/xpfe/appshell/nsContentTreeOwner.cpp
index 34f79ff79e4e..78db2058cb6b 100644
--- a/xpfe/appshell/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/nsContentTreeOwner.cpp
@@ -172,10 +172,10 @@ NS_IMETHODIMP nsContentTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
 
 NS_IMETHODIMP
 nsContentTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
-                                      bool aPrimary, const nsAString& aID)
+                                      bool aPrimary)
 {
   NS_ENSURE_STATE(mXULWindow);
-  return mXULWindow->ContentShellAdded(aContentShell, aPrimary, aID);
+  return mXULWindow->ContentShellAdded(aContentShell, aPrimary);
 }
 
 NS_IMETHODIMP
diff --git a/xpfe/appshell/nsIXULWindow.idl b/xpfe/appshell/nsIXULWindow.idl
index bc57554808a0..ceeb7f1b4d90 100644
--- a/xpfe/appshell/nsIXULWindow.idl
+++ b/xpfe/appshell/nsIXULWindow.idl
@@ -51,16 +51,6 @@ interface nsIXULWindow : nsISupports
   void tabParentAdded(in nsITabParent aTab, in boolean aPrimary);
   void tabParentRemoved(in nsITabParent aTab);
 
-  /**
-   * The content shell specified by the supplied id.
-   *
-   * Note that this is a docshell tree item and therefore can not be assured of
-   * what object it is.  It could be an editor, a docshell, or a browser object.
-   * Or down the road any other object that supports being a DocShellTreeItem
-   * Query accordingly to determine the capabilities.
-   */
-  nsIDocShellTreeItem getContentShellById(in wstring ID);
-
   /**
    * Tell this window that it has picked up a child XUL window
    * @param aChild the child window being added
diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp
index ed6bbc50c51b..f160a6949898 100644
--- a/xpfe/appshell/nsWebShellWindow.cpp
+++ b/xpfe/appshell/nsWebShellWindow.cpp
@@ -622,7 +622,6 @@ nsWebShellWindow::OnStateChange(nsIWebProgress *aProgress,
 #endif // USE_NATIVE_MENUS
 
   OnChromeLoaded();
-  LoadContentAreas();
 
   return NS_OK;
 }
@@ -657,81 +656,6 @@ nsWebShellWindow::OnSecurityChange(nsIWebProgress *aWebProgress,
 }
 
 
-//----------------------------------------
-
-// if the main document URL specified URLs for any content areas, start them loading
-void nsWebShellWindow::LoadContentAreas() {
-
-  nsAutoString searchSpec;
-
-  // fetch the chrome document URL
-  nsCOMPtr contentViewer;
-  // yes, it's possible for the docshell to be null even this early
-  // see bug 57514.
-  if (mDocShell)
-    mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
-  if (contentViewer) {
-    nsIDocument* doc = contentViewer->GetDocument();
-    if (doc) {
-      nsIURI* mainURL = doc->GetDocumentURI();
-
-      nsCOMPtr url = do_QueryInterface(mainURL);
-      if (url) {
-        nsAutoCString search;
-        url->GetQuery(search);
-
-        AppendUTF8toUTF16(search, searchSpec);
-      }
-    }
-  }
-
-  // content URLs are specified in the search part of the URL
-  // as =[;(repeat)]
-  if (!searchSpec.IsEmpty()) {
-    int32_t     begPos,
-                eqPos,
-                endPos;
-    nsString    contentAreaID,
-                contentURL;
-    char        *urlChar;
-    nsresult rv;
-    for (endPos = 0; endPos < (int32_t)searchSpec.Length(); ) {
-      // extract contentAreaID and URL substrings
-      begPos = endPos;
-      eqPos = searchSpec.FindChar('=', begPos);
-      if (eqPos < 0)
-        break;
-
-      endPos = searchSpec.FindChar(';', eqPos);
-      if (endPos < 0)
-        endPos = searchSpec.Length();
-      searchSpec.Mid(contentAreaID, begPos, eqPos-begPos);
-      searchSpec.Mid(contentURL, eqPos+1, endPos-eqPos-1);
-      endPos++;
-
-      // see if we have a docshell with a matching contentAreaID
-      nsCOMPtr content;
-      rv = GetContentShellById(contentAreaID.get(), getter_AddRefs(content));
-      if (NS_SUCCEEDED(rv) && content) {
-        nsCOMPtr webNav(do_QueryInterface(content));
-        if (webNav) {
-          urlChar = ToNewCString(contentURL);
-          if (urlChar) {
-            nsUnescape(urlChar);
-            contentURL.AssignWithConversion(urlChar);
-            webNav->LoadURI(contentURL.get(),
-                          nsIWebNavigation::LOAD_FLAGS_NONE,
-                          nullptr,
-                          nullptr,
-                          nullptr);
-            free(urlChar);
-          }
-        }
-      }
-    }
-  }
-}
-
 /**
  * ExecuteCloseHandler - Run the close handler, if any.
  * @return true iff we found a close handler to run.
diff --git a/xpfe/appshell/nsWebShellWindow.h b/xpfe/appshell/nsWebShellWindow.h
index cf2b0da9ceba..5d267d856d88 100644
--- a/xpfe/appshell/nsWebShellWindow.h
+++ b/xpfe/appshell/nsWebShellWindow.h
@@ -70,7 +70,6 @@ protected:
   
   virtual ~nsWebShellWindow();
 
-  void                     LoadContentAreas();
   bool                     ExecuteCloseHandler();
   void                     ConstrainToOpenerScreen(int32_t* aX, int32_t* aY);
 
diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp
index 88fcbc5d81ab..fa705b5cdc2c 100644
--- a/xpfe/appshell/nsXULWindow.cpp
+++ b/xpfe/appshell/nsXULWindow.cpp
@@ -344,25 +344,6 @@ nsXULWindow::GetPrimaryTabParent(nsITabParent** aTab)
   return NS_OK;
 }
 
-NS_IMETHODIMP nsXULWindow::GetContentShellById(const char16_t* aID, 
-   nsIDocShellTreeItem** aDocShellTreeItem)
-{
-  NS_ENSURE_ARG_POINTER(aDocShellTreeItem);
-  *aDocShellTreeItem = nullptr;
-
-  uint32_t count = mContentShells.Length();
-  for (uint32_t i = 0; i < count; i++) {
-    nsContentShellInfo* shellInfo = mContentShells.ElementAt(i);
-    if (shellInfo->id.Equals(aID)) {
-      *aDocShellTreeItem = nullptr;
-      if (shellInfo->child)
-        CallQueryReferent(shellInfo->child.get(), aDocShellTreeItem);
-      return NS_OK;
-    }
-  }
-  return NS_ERROR_FAILURE;
-}
-
 NS_IMETHODIMP nsXULWindow::AddChildWindow(nsIXULWindow *aChild)
 {
   // we're not really keeping track of this right now
@@ -510,13 +491,6 @@ NS_IMETHODIMP nsXULWindow::Destroy()
     mDocShell = nullptr; // this can cause reentrancy of this function
   }
 
-  // Remove our ref on the content shells
-  uint32_t count = mContentShells.Length();
-  for (uint32_t i = 0; i < count; i++) {
-    nsContentShellInfo* shellInfo = mContentShells.ElementAt(i);
-    delete shellInfo;
-  }
-  mContentShells.Clear();
   mPrimaryContentShell = nullptr;
 
   if (mContentTreeOwner) {
@@ -1685,28 +1659,8 @@ nsXULWindow::GetWindowDOMElement() const
 }
 
 nsresult nsXULWindow::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
-   bool aPrimary, const nsAString& aID)
+   bool aPrimary)
 {
-  nsContentShellInfo* shellInfo = nullptr;
-
-  uint32_t i, count = mContentShells.Length();
-  nsWeakPtr contentShellWeak = do_GetWeakReference(aContentShell);
-  for (i = 0; i < count; i++) {
-    nsContentShellInfo* info = mContentShells.ElementAt(i);
-    if (info->id.Equals(aID)) {
-      // We already exist. Do a replace.
-      info->child = contentShellWeak;
-      shellInfo = info;
-    }
-    else if (info->child == contentShellWeak)
-      info->child = nullptr;
-  }
-
-  if (!shellInfo) {
-    shellInfo = new nsContentShellInfo(aID, contentShellWeak);
-    mContentShells.AppendElement(shellInfo);
-  }
-    
   // Set the default content tree owner
   if (aPrimary) {
     NS_ENSURE_SUCCESS(EnsurePrimaryContentTreeOwner(), NS_ERROR_FAILURE);
@@ -1729,17 +1683,6 @@ nsresult nsXULWindow::ContentShellRemoved(nsIDocShellTreeItem* aContentShell)
   if (mPrimaryContentShell == aContentShell) {
     mPrimaryContentShell = nullptr;
   }
-
-  int32_t i, count = mContentShells.Length();
-  for (i = count - 1; i >= 0; --i) {
-    nsContentShellInfo* info = mContentShells.ElementAt(i);
-    nsCOMPtr curItem = do_QueryReferent(info->child);
-    if (!curItem || SameCOMIdentity(curItem, aContentShell)) {
-      mContentShells.RemoveElementAt(i);
-      delete info;
-    }
-  }
-
   return NS_OK;
 }
 
@@ -2271,20 +2214,3 @@ nsXULWindow::GetTabCount(uint32_t* aResult)
   return NS_OK;
 }
 
-//*****************************************************************************
-//*** nsContentShellInfo: Object Management
-//*****************************************************************************   
-
-nsContentShellInfo::nsContentShellInfo(const nsAString& aID,
-                                       nsIWeakReference* aContentShell)
-  : id(aID),
-    child(aContentShell)
-{
-  MOZ_COUNT_CTOR(nsContentShellInfo);
-}
-
-nsContentShellInfo::~nsContentShellInfo()
-{
-  MOZ_COUNT_DTOR(nsContentShellInfo);
-   //XXX Set Tree Owner to null if the tree owner is nsXULWindow->mContentTreeOwner
-} 
diff --git a/xpfe/appshell/nsXULWindow.h b/xpfe/appshell/nsXULWindow.h
index 3b92665d00ef..16d6fe19befa 100644
--- a/xpfe/appshell/nsXULWindow.h
+++ b/xpfe/appshell/nsXULWindow.h
@@ -106,8 +106,7 @@ protected:
 
    // See nsIDocShellTreeOwner for docs on next two methods
    nsresult ContentShellAdded(nsIDocShellTreeItem* aContentShell,
-                              bool aPrimary,
-                              const nsAString& aID);
+                              bool aPrimary);
    nsresult ContentShellRemoved(nsIDocShellTreeItem* aContentShell);
    NS_IMETHOD GetPrimaryContentSize(int32_t* aWidth,
                                     int32_t* aHeight);
@@ -146,7 +145,6 @@ protected:
    nsCOMPtr mAuthPrompter;
    nsCOMPtr mXULBrowserWindow;
    nsCOMPtr mPrimaryContentShell;
-   nsTArray mContentShells; // array of doc shells by id
    nsresult                mModalStatus;
    bool                    mContinueModalLoop;
    bool                    mDebuting;       // being made visible right now
@@ -178,20 +176,4 @@ private:
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsXULWindow, NS_XULWINDOW_IMPL_CID)
-
-// nsContentShellInfo
-// Used to map shell IDs to nsIDocShellTreeItems.
-
-class nsContentShellInfo
-{
-public:
-   nsContentShellInfo(const nsAString& aID,
-                      nsIWeakReference* aContentShell);
-   ~nsContentShellInfo();
-
-public:
-   nsString id; // The identifier of the content shell
-   nsWeakPtr child; // content shell (weak reference to nsIDocShellTreeItem)
-};
-
 #endif /* nsXULWindow_h__ */