Merge m-c to autoland

This commit is contained in:
Phil Ringnalda 2016-12-15 17:52:23 -08:00
commit 082cc32ea9
318 changed files with 17148 additions and 14870 deletions

View File

@ -76,6 +76,33 @@ AccessibleNode::GetStates(nsTArray<nsString>& aStates)
mStates->Add(NS_LITERAL_STRING("defunct"));
}
bool
AccessibleNode::Is(const Sequence<nsString>& 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()
{

View File

@ -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<nsString>& aStates);
nsINode* GetDOMNode();
bool Is(const Sequence<nsString>& aFlavors);
a11y::Accessible* Internal() const { return mIntl; }
protected:

View File

@ -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 += [

View File

@ -77,6 +77,9 @@
}
}
ok(anode.is('document', 'focusable'),
'correct role and state on an accessible node');
finish();
}
</script>

View File

@ -24,7 +24,8 @@
<xul:hbox flex="1" class="browserSidebarContainer">
<xul:vbox flex="1" class="browserContainer">
<xul:stack flex="1" class="browserStack" anonid="browserStack">
<xul:browser anonid="initialBrowser" type="content-primary" message="true" messagemanagergroup="browsers"
<xul:browser anonid="initialBrowser" type="content" message="true" messagemanagergroup="browsers"
primary="true"
xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,selectmenulist,datetimepicker"/>
</xul:stack>
</xul:vbox>
@ -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", {

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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);
};

View File

@ -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<nsIContentViewer> safeViewers;
@ -1182,7 +1184,7 @@ nsSHistory::GloballyEvictContentViewers()
nsTArray<TransactionAndDistance> 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<nsISHTransaction> 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<nsISHTransaction> 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;

View File

@ -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

View File

@ -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.
});
});

View File

@ -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");
});
});

View File

@ -111,5 +111,5 @@
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -156,5 +156,5 @@
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -156,5 +156,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -70,5 +70,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -141,6 +141,6 @@
<command id="cmd_find"
oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
</commandset>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
<findbar id="FindToolbar" browserid="content"/>
</window>

View File

@ -244,5 +244,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -95,5 +95,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -195,5 +195,5 @@ function step4B(aWebProgress, aRequest, aLocation, aFlags) {
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -127,5 +127,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -128,5 +128,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -266,5 +266,5 @@
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -163,5 +163,5 @@
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -116,5 +116,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -82,5 +82,5 @@
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -123,5 +123,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -170,5 +170,5 @@
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -76,5 +76,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -112,5 +112,5 @@
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -40,5 +40,5 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<browser type="content" primary="true" flex="1" id="content" src="about:blank"/>
</window>

View File

@ -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> 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<JSObject*> 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
} // namespace mozilla

View File

@ -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<nsISupportsHashKey, nsTArray<nsWeakPtr>>
CandidateMap;
typedef JS::GCHashMap<JS::Heap<JSObject*>,
nsCOMPtr<nsIAtom>,
js::MovableCellHasher<JS::Heap<JSObject*>>,
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<nsISupportsHashKey, Promise>
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.

View File

@ -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<nsIPartialSHistory> partialHistory = aPartial;
nsCOMPtr<nsIPartialSHistory> 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<nsIFrameLoader> 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;
}

View File

@ -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<nsISHistory> 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<nsIGroupedSHistory> 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<nsIGroupedSHistory> 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

View File

@ -42,11 +42,16 @@ private:
already_AddRefed<nsISHistory> GetSessionHistory();
already_AddRefed<TabParent> 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;

View File

@ -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<nsIRunnable> 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);
}
}

View File

@ -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();

View File

@ -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<nsGenericHTMLElement>
CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
ErrorResult& aRv)
{
// Step 1.
nsCOMPtr<nsPIDOMWindowInner> 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<mozilla::dom::CustomElementRegistry> 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<JSObject*> newTarget(cx, &aCallArgs.newTarget().toObject());
CustomElementDefinition* definition =
registry->LookupCustomElementDefinition(cx, newTarget);
if (!definition) {
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
return nullptr;
}
// The callee might be an Xray. Unwrap it to get actual callee.
JS::Rooted<JSObject*> 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<JSObject*> constructor(cx, HTMLElementBinding::GetConstructorObject(cx));
if (!constructor) {
aRv.NoteJSContextException(cx);
return nullptr;
}
if (callee != constructor) {
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
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<MSG_ILLEGAL_CONSTRUCTOR>();
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<MSG_ILLEGAL_CONSTRUCTOR>();
return nullptr;
}
JS::Rooted<JSObject*> constructor(cx, cb(cx));
if (!constructor) {
aRv.NoteJSContextException(cx);
return nullptr;
}
if (callee != constructor) {
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
return nullptr;
}
}
RefPtr<mozilla::dom::NodeInfo> 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<nsGenericHTMLElement> 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

View File

@ -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<JSObject*> 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<nsGenericHTMLElement>
CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
ErrorResult& aRv);
void
SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
UseCounter aUseCounter);

View File

@ -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

View File

@ -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<JSObject*> 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<JSObject*> 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<JSObject*> 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

View File

@ -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

View File

@ -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")

View File

@ -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.")

View File

@ -1425,6 +1425,12 @@ public:
void SetNeedsCallerTypeAttr(bool, CallerType);
};
class TestHTMLConstructorInterface : public nsGenericHTMLElement
{
public:
virtual nsISupports* GetParentObject();
};
} // namespace dom
} // namespace mozilla

View File

@ -1262,3 +1262,7 @@ interface TestWorkerExposedInterface {
[NeedsCallerType] void needsCallerTypeMethod();
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
};
[HTMLConstructor]
interface TestHTMLConstructorInterface {
};

View File

@ -1163,7 +1163,10 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
}
if (aEventType.LowerCaseEqualsLiteral("storageevent")) {
LOG_EVENT_CREATION(STORAGEEVENT);
return NS_NewDOMStorageEvent(aOwner);
RefPtr<Event> event =
StorageEvent::Constructor(aOwner, EmptyString(), StorageEventInit());
event->MarkUninitialized();
return event.forget();
}
#undef LOG_EVENT_CREATION

View File

@ -99,16 +99,3 @@ StorageEvent::InitStorageEvent(const nsAString& aType, bool aCanBubble,
} // namespace dom
} // namespace mozilla
using namespace mozilla;
using namespace mozilla::dom;
already_AddRefed<StorageEvent>
NS_NewDOMStorageEvent(EventTarget* aOwner)
{
RefPtr<StorageEvent> e = new StorageEvent(aOwner);
e->SetTrusted(e->Init(aOwner));
return e.forget();
}

View File

@ -13,10 +13,6 @@
#include "mozilla/dom/Event.h"
#include "mozilla/dom/StorageEventBinding.h"
// Helper for EventDispatcher.
already_AddRefed<mozilla::dom::StorageEvent>
NS_NewDOMStorageEvent(mozilla::dom::EventTarget* aOwner);
namespace mozilla {
namespace dom {

View File

@ -3,7 +3,7 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
width="640" height="480">
<browser id="browser" type="content-primary" flex="1" src="about:blank"
<browser id="browser" type="content" primary="true" flex="1" src="about:blank"
disablehistory="true" disablesecurity="true"/>
</window>

View File

@ -96,14 +96,12 @@ NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& 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
};

View File

@ -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

View File

@ -661,8 +661,7 @@ TabChild::Init()
if (GroupedSHistory::GroupedHistoryEnabled()) {
// Set session history listener.
nsCOMPtr<nsISHistory> shistory;
mWebNav->GetSessionHistory(getter_AddRefs(shistory));
nsCOMPtr<nsISHistory> 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<nsISHistory> shistory;
mWebNav->GetSessionHistory(getter_AddRefs(shistory));
nsCOMPtr<nsISHistory> 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<nsISHistory> shistory;
mWebNav->GetSessionHistory(getter_AddRefs(shistory));
nsCOMPtr<nsISHistory> 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<nsISHistory> shistory;
mWebNav->GetSessionHistory(getter_AddRefs(shistory));
nsCOMPtr<nsISHistory> 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<nsISHistory>
TabChild::GetRelatedSHistory()
{
nsCOMPtr<nsISHistory> shistory;
mWebNav->GetSessionHistory(getter_AddRefs(shistory));
return shistory.forget();
}
nsresult
TabChildSHistoryListener::SHistoryDidUpdate(bool aTruncate /* = false */)
{
RefPtr<TabChild> tabChild(mTabChild);
if (NS_WARN_IF(!tabChild)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsISHistory> 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> 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

View File

@ -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<nsISHistory> GetRelatedSHistory();
protected:
virtual ~TabChild();

View File

@ -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<nsFrameLoader> 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();
}

View File

@ -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;

View File

@ -101,6 +101,45 @@ public:
uint32_t mChunksToProcess = 0;
};
/* static */ already_AddRefed<AnalyserNode>
AnalyserNode::Create(AudioContext& aAudioContext,
const AnalyserOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<AnalyserNode> 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,

View File

@ -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<AnalyserNode>
Create(AudioContext& aAudioContext, const AnalyserOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<AnalyserNode>
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<AudioChunk> mChunks;
double mMinDecibels;

View File

@ -180,6 +180,24 @@ AudioBuffer::~AudioBuffer()
mozilla::DropJSObjects(this);
}
/* static */ already_AddRefed<AudioBuffer>
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()
{

View File

@ -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<AudioBuffer>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const AudioBufferOptions& aOptions, ErrorResult& aRv);
nsPIDOMWindowInner* GetParentObject() const
{
nsCOMPtr<nsPIDOMWindowInner> parentObject = do_QueryReferent(mOwnerWindow);
@ -134,4 +139,3 @@ protected:
} // namespace mozilla
#endif

View File

@ -608,10 +608,30 @@ AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
mStream->AddMainThreadListener(this);
}
AudioBufferSourceNode::~AudioBufferSourceNode()
/* static */ already_AddRefed<AudioBufferSourceNode>
AudioBufferSourceNode::Create(JSContext* aCx, AudioContext& aAudioContext,
const AudioBufferSourceOptions& aOptions,
ErrorResult& aRv)
{
}
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<AudioBufferSourceNode> 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()
{

View File

@ -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<AudioBufferSourceNode>
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<AudioBufferSourceNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const AudioBufferSourceOptions& aOptions, ErrorResult& aRv)
{
return Create(aGlobal.Context(), aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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

View File

@ -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<AudioBufferSourceNode>
AudioContext::CreateBufferSource(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<AudioBufferSourceNode> bufferNode =
new AudioBufferSourceNode(this);
return bufferNode.forget();
return AudioBufferSourceNode::Create(nullptr, *this,
AudioBufferSourceOptions(),
aRv);
}
already_AddRefed<ConstantSourceNode>
@ -299,18 +311,8 @@ bool IsValidBufferSize(uint32_t aBufferSize) {
already_AddRefed<MediaStreamAudioDestinationNode>
AudioContext::CreateMediaStreamDestination(ErrorResult& aRv)
{
if (mIsOffline) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<MediaStreamAudioDestinationNode> node =
new MediaStreamAudioDestinationNode(this);
return node.forget();
return MediaStreamAudioDestinationNode::Create(*this, AudioNodeOptions(),
aRv);
}
already_AddRefed<ScriptProcessorNode>
@ -340,186 +342,93 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize,
already_AddRefed<AnalyserNode>
AudioContext::CreateAnalyser(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<AnalyserNode> analyserNode = new AnalyserNode(this);
return analyserNode.forget();
return AnalyserNode::Create(*this, AnalyserOptions(), aRv);
}
already_AddRefed<StereoPannerNode>
AudioContext::CreateStereoPanner(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<StereoPannerNode> stereoPannerNode = new StereoPannerNode(this);
return stereoPannerNode.forget();
return StereoPannerNode::Create(*this, StereoPannerOptions(), aRv);
}
already_AddRefed<MediaElementAudioSourceNode>
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<DOMMediaStream> 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<MediaStreamAudioSourceNode>
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<GainNode>
AudioContext::CreateGain(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<GainNode> gainNode = new GainNode(this);
return gainNode.forget();
return GainNode::Create(*this, GainOptions(), aRv);
}
already_AddRefed<WaveShaperNode>
AudioContext::CreateWaveShaper(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<WaveShaperNode> waveShaperNode = new WaveShaperNode(this);
return waveShaperNode.forget();
return WaveShaperNode::Create(*this, WaveShaperOptions(), aRv);
}
already_AddRefed<DelayNode>
AudioContext::CreateDelay(double aMaxDelayTime, ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
if (aMaxDelayTime > 0. && aMaxDelayTime < 180.) {
RefPtr<DelayNode> 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<PannerNode>
AudioContext::CreatePanner(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<PannerNode> pannerNode = new PannerNode(this);
mPannerNodes.PutEntry(pannerNode);
return pannerNode.forget();
return PannerNode::Create(*this, PannerOptions(), aRv);
}
already_AddRefed<ConvolverNode>
AudioContext::CreateConvolver(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<ConvolverNode> convolverNode = new ConvolverNode(this);
return convolverNode.forget();
return ConvolverNode::Create(nullptr, *this, ConvolverOptions(), aRv);
}
already_AddRefed<ChannelSplitterNode>
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<ChannelSplitterNode> splitterNode =
new ChannelSplitterNode(this, aNumberOfOutputs);
return splitterNode.forget();
ChannelSplitterOptions options;
options.mNumberOfOutputs = aNumberOfOutputs;
return ChannelSplitterNode::Create(*this, options, aRv);
}
already_AddRefed<ChannelMergerNode>
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<ChannelMergerNode> mergerNode =
new ChannelMergerNode(this, aNumberOfInputs);
return mergerNode.forget();
ChannelMergerOptions options;
options.mNumberOfInputs = aNumberOfInputs;
return ChannelMergerNode::Create(*this, options, aRv);
}
already_AddRefed<DynamicsCompressorNode>
AudioContext::CreateDynamicsCompressor(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<DynamicsCompressorNode> compressorNode =
new DynamicsCompressorNode(this);
return compressorNode.forget();
return DynamicsCompressorNode::Create(*this, DynamicsCompressorOptions(), aRv);
}
already_AddRefed<BiquadFilterNode>
AudioContext::CreateBiquadFilter(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<BiquadFilterNode> filterNode =
new BiquadFilterNode(this);
return filterNode.forget();
return BiquadFilterNode::Create(*this, BiquadFilterOptions(), aRv);
}
already_AddRefed<IIRFilterNode>
@ -527,47 +436,16 @@ AudioContext::CreateIIRFilter(const mozilla::dom::binding_detail::AutoSequence<d
const mozilla::dom::binding_detail::AutoSequence<double>& 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<IIRFilterNode> 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<OscillatorNode>
AudioContext::CreateOscillator(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<OscillatorNode> oscillatorNode =
new OscillatorNode(this);
return oscillatorNode.forget();
return OscillatorNode::Create(*this, OscillatorOptions(), aRv);
}
already_AddRefed<PeriodicWave>

View File

@ -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<MediaStream*> GetAllStreams() const;
private:

View File

@ -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
{

View File

@ -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);

View File

@ -263,8 +263,29 @@ BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
aContext->Graph());
}
BiquadFilterNode::~BiquadFilterNode()
/* static */ already_AddRefed<BiquadFilterNode>
BiquadFilterNode::Create(AudioContext& aAudioContext,
const BiquadFilterOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<BiquadFilterNode> 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

View File

@ -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<BiquadFilterNode>
Create(AudioContext& aAudioContext, const BiquadFilterOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BiquadFilterNode, AudioNode)
static already_AddRefed<BiquadFilterNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const BiquadFilterOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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<AudioParam> mFrequency;
RefPtr<AudioParam> mDetune;
@ -79,4 +89,3 @@ private:
} // namespace mozilla
#endif

View File

@ -75,8 +75,30 @@ ChannelMergerNode::ChannelMergerNode(AudioContext* aContext,
aContext->Graph());
}
ChannelMergerNode::~ChannelMergerNode()
/* static */ already_AddRefed<ChannelMergerNode>
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<ChannelMergerNode> 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<JSObject*> aGivenProto)
} // namespace dom
} // namespace mozilla

View File

@ -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<ChannelMergerNode>
Create(AudioContext& aAudioContext, const ChannelMergerOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<ChannelMergerNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const ChannelMergerOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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

View File

@ -66,8 +66,30 @@ ChannelSplitterNode::ChannelSplitterNode(AudioContext* aContext,
aContext->Graph());
}
ChannelSplitterNode::~ChannelSplitterNode()
/* static */ already_AddRefed<ChannelSplitterNode>
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<ChannelSplitterNode> 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<JSObject*> aGivenProt
} // namespace dom
} // namespace mozilla

View File

@ -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<ChannelSplitterNode>
Create(AudioContext& aAudioContext, const ChannelSplitterOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<ChannelSplitterNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const ChannelSplitterOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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

View File

@ -204,8 +204,34 @@ ConvolverNode::ConvolverNode(AudioContext* aContext)
aContext->Graph());
}
ConvolverNode::~ConvolverNode()
/* static */ already_AddRefed<ConvolverNode>
ConvolverNode::Create(JSContext* aCx, AudioContext& aAudioContext,
const ConvolverOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<ConvolverNode> 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

View File

@ -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<ConvolverNode>
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<ConvolverNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const ConvolverOptions& aOptions, ErrorResult& aRv)
{
return Create(aGlobal.Context(), aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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<AudioBuffer> mBuffer;
bool mNormalize;
};
@ -75,4 +87,3 @@ private:
} //end namespace mozilla
#endif

View File

@ -206,8 +206,30 @@ DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
aContext->Graph());
}
DelayNode::~DelayNode()
/* static */ already_AddRefed<DelayNode>
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<DelayNode> 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

View File

@ -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<DelayNode>
Create(AudioContext& aAudioContext, const DelayOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DelayNode, AudioNode)
static already_AddRefed<DelayNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const DelayOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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<AudioParam> mDelay;
};
@ -52,4 +61,3 @@ private:
} // namespace mozilla
#endif

View File

@ -205,8 +205,30 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
aContext->Graph());
}
DynamicsCompressorNode::~DynamicsCompressorNode()
/* static */ already_AddRefed<DynamicsCompressorNode>
DynamicsCompressorNode::Create(AudioContext& aAudioContext,
const DynamicsCompressorOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<DynamicsCompressorNode> 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

View File

@ -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<DynamicsCompressorNode>
Create(AudioContext& aAudioContext, const DynamicsCompressorOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DynamicsCompressorNode, AudioNode)
static already_AddRefed<DynamicsCompressorNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const DynamicsCompressorOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
AudioParam* Threshold() const
@ -70,10 +80,10 @@ public:
mReduction = aReduction;
}
protected:
virtual ~DynamicsCompressorNode();
private:
explicit DynamicsCompressorNode(AudioContext* aContext);
~DynamicsCompressorNode() = default;
RefPtr<AudioParam> mThreshold;
RefPtr<AudioParam> mKnee;
RefPtr<AudioParam> mRatio;
@ -86,4 +96,3 @@ private:
} // namespace mozilla
#endif

View File

@ -128,8 +128,24 @@ GainNode::GainNode(AudioContext* aContext)
aContext->Graph());
}
GainNode::~GainNode()
/* static */ already_AddRefed<GainNode>
GainNode::Create(AudioContext& aAudioContext,
const GainOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<GainNode> 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

View File

@ -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<GainNode>
Create(AudioContext& aAudioContext, const GainOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GainNode, AudioNode)
static already_AddRefed<GainNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const GainOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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<AudioParam> mGain;
};
@ -49,4 +59,3 @@ private:
} // namespace mozilla
#endif

View File

@ -133,8 +133,8 @@ private:
};
IIRFilterNode::IIRFilterNode(AudioContext* aContext,
const mozilla::dom::binding_detail::AutoSequence<double>& aFeedforward,
const mozilla::dom::binding_detail::AutoSequence<double>& aFeedback)
const Sequence<double>& aFeedforward,
const Sequence<double>& aFeedback)
: AudioNode(aContext,
2,
ChannelCountMode::Max,
@ -168,8 +168,46 @@ IIRFilterNode::IIRFilterNode(AudioContext* aContext,
aContext->Graph());
}
IIRFilterNode::~IIRFilterNode()
/* static */ already_AddRefed<IIRFilterNode>
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<IIRFilterNode> 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

View File

@ -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<double>& aFeedforward,
const mozilla::dom::binding_detail::AutoSequence<double>& aFeedback);
static already_AddRefed<IIRFilterNode>
Create(AudioContext& aAudioContext, const IIRFilterOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<IIRFilterNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const IIRFilterOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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<double> mFeedback;
nsTArray<double> mFeedforward;
IIRFilterNode(AudioContext* aContext,
const Sequence<double>& aFeedforward,
const Sequence<double>& aFeedback);
~IIRFilterNode() = default;
nsTArray<double> mFeedback;
nsTArray<double> mFeedforward;
};
} // namespace dom
} // namespace mozilla
#endif

View File

@ -16,13 +16,34 @@ MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext* aContext)
}
/* static */ already_AddRefed<MediaElementAudioSourceNode>
MediaElementAudioSourceNode::Create(AudioContext* aContext,
DOMMediaStream* aStream, ErrorResult& aRv)
MediaElementAudioSourceNode::Create(AudioContext& aAudioContext,
const MediaElementAudioSourceOptions& aOptions,
ErrorResult& aRv)
{
RefPtr<MediaElementAudioSourceNode> 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<MediaElementAudioSourceNode> node =
new MediaElementAudioSourceNode(&aAudioContext);
RefPtr<DOMMediaStream> stream =
aOptions.mMediaElement->CaptureAudio(aRv, aAudioContext.Destination()->Stream()->Graph());
if (aRv.Failed()) {
return nullptr;
}
node->Init(stream, aRv);
if (aRv.Failed()) {
return nullptr;
}

View File

@ -12,11 +12,23 @@
namespace mozilla {
namespace dom {
class AudioContext;
struct MediaElementAudioSourceOptions;
class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode
{
public:
static already_AddRefed<MediaElementAudioSourceNode>
Create(AudioContext* aContext, DOMMediaStream* aStream, ErrorResult& aRv);
Create(AudioContext& aAudioContext,
const MediaElementAudioSourceOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<MediaElementAudioSourceNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const MediaElementAudioSourceOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;

View File

@ -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<MediaStreamAudioDestinationNode> mNode;
};
@ -102,8 +102,29 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* a
mPort = outputStream->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK);
}
MediaStreamAudioDestinationNode::~MediaStreamAudioDestinationNode()
/* static */ already_AddRefed<MediaStreamAudioDestinationNode>
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<MediaStreamAudioDestinationNode> audioNode =
new MediaStreamAudioDestinationNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return audioNode.forget();
}
size_t

View File

@ -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<MediaStreamAudioDestinationNode>
Create(AudioContext& aAudioContext, const AudioNodeOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamAudioDestinationNode, AudioNode)
static already_AddRefed<MediaStreamAudioDestinationNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const AudioNodeOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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<DOMMediaStream> mDOMStream;
RefPtr<MediaInputPort> mPort;
};

View File

@ -43,13 +43,23 @@ MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AudioContext* aContext)
}
/* static */ already_AddRefed<MediaStreamAudioSourceNode>
MediaStreamAudioSourceNode::Create(AudioContext* aContext,
DOMMediaStream* aStream, ErrorResult& aRv)
MediaStreamAudioSourceNode::Create(AudioContext& aAudioContext,
const MediaStreamAudioSourceOptions& aOptions,
ErrorResult& aRv)
{
RefPtr<MediaStreamAudioSourceNode> 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<MediaStreamAudioSourceNode> node =
new MediaStreamAudioSourceNode(&aAudioContext);
node->Init(aOptions.mMediaStream, aRv);
if (aRv.Failed()) {
return nullptr;
}

View File

@ -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<MediaStreamAudioSourceNode>
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<MediaStreamAudioSourceNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const MediaStreamAudioSourceOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void DestroyMediaStream() override;

View File

@ -426,8 +426,35 @@ OscillatorNode::OscillatorNode(AudioContext* aContext)
mStream->AddMainThreadListener(this);
}
OscillatorNode::~OscillatorNode()
/* static */ already_AddRefed<OscillatorNode>
OscillatorNode::Create(AudioContext& aAudioContext,
const OscillatorOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<OscillatorNode> 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

View File

@ -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<OscillatorNode>
Create(AudioContext& aAudioContext, const OscillatorOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OscillatorNode, AudioNode)
static already_AddRefed<OscillatorNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const OscillatorOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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<PeriodicWave> mPeriodicWave;
RefPtr<AudioParam> mFrequency;
@ -101,4 +110,3 @@ private:
} // namespace mozilla
#endif

View File

@ -330,6 +330,38 @@ PannerNode::~PannerNode()
}
}
/* static */ already_AddRefed<PannerNode>
PannerNode::Create(AudioContext& aAudioContext,
const PannerOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<PannerNode> 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

View File

@ -20,13 +20,24 @@ namespace dom {
class AudioContext;
class AudioBufferSourceNode;
struct PannerOptions;
class PannerNode final : public AudioNode,
public SupportsWeakPtr<PannerNode>
{
public:
static already_AddRefed<PannerNode>
Create(AudioContext& aAudioContext, const PannerOptions& aOptions,
ErrorResult& aRv);
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PannerNode)
explicit PannerNode(AudioContext* aContext);
static already_AddRefed<PannerNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const PannerOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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

View File

@ -44,6 +44,32 @@ PeriodicWave::PeriodicWave(AudioContext* aContext,
mCoefficients->SetData(1, nullptr, free, buffer+aLength);
}
/* static */ already_AddRefed<PeriodicWave>
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<PeriodicWave> 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<JSObject*> aGivenProto)
} // namespace dom
} // namespace mozilla

View File

@ -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<PeriodicWave>
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<AudioContext> mContext;
RefPtr<ThreadSharedFloatArrayBufferList> mCoefficients;

Some files were not shown because too many files have changed in this diff Show More