mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Merge m-c to autoland
This commit is contained in:
commit
082cc32ea9
@ -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()
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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 += [
|
||||
|
@ -77,6 +77,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
ok(anode.is('document', 'focusable'),
|
||||
'correct role and state on an accessible node');
|
||||
|
||||
finish();
|
||||
}
|
||||
</script>
|
||||
|
@ -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", {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
});
|
||||
});
|
41
docshell/test/browser/browser_grouped_shistory_crossproc.js
Normal file
41
docshell/test/browser/browser_grouped_shistory_crossproc.js
Normal 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");
|
||||
});
|
||||
});
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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.")
|
||||
|
@ -1425,6 +1425,12 @@ public:
|
||||
void SetNeedsCallerTypeAttr(bool, CallerType);
|
||||
};
|
||||
|
||||
class TestHTMLConstructorInterface : public nsGenericHTMLElement
|
||||
{
|
||||
public:
|
||||
virtual nsISupports* GetParentObject();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -1262,3 +1262,7 @@ interface TestWorkerExposedInterface {
|
||||
[NeedsCallerType] void needsCallerTypeMethod();
|
||||
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
|
||||
};
|
||||
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorInterface {
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user