Compare commits

...
Author SHA1 Message Date
Moonchild ab88527fe6 Issue #3011 - Part 3: Handle edge case for spellchecking.
Make spellchecking work in Shadow DOM after anchor navigates away from it.
2026-03-20 17:07:55 +01:00
Moonchild 6c0ff1881a Issue #3011 - Part 2: Switch spellchecker root to Shadow DOM.
Set the root for spelling checker to shadow root if the contenteditable
nodes are in the shadow DOM. Bail if the position can't be set properly.
2026-03-20 14:45:11 +01:00
Moonchild 1e7f4c8474 Issue #3011 - Part 1: Add As{Text|Html}Editor() and AsEditorBase()
This adds helper functions to get specific types of content editors (if
possible) through the nsIEditor interface, as opposed to doing manual
casting and the ad hoc `GetHTMLEditor()` function.

Helper functions are spread out over multiple headers due to the
circular dependency issues that would be triggered otherwise.
2026-03-20 13:26:18 +01:00
Moonchild 542eaca577 Merge pull request 'LoongArch Support Followup - Do not hardcode jemalloc page size on LoongArch' (#3006) from Basilisk-Dev/UXP-contrib:loongarchpagesize into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3006
2026-03-18 23:02:13 +00:00
Basilisk-Dev 1cb6f56418 Issue #2897 followup - Do not hardcode jemalloc page size on LoongArch
Loongarch can run on either a 4k or 16k page size
2026-03-18 18:14:27 -04:00
Moonchild a503e883d9 Merge pull request 'Don't attempt on-stack replacement for TLA modules when interpreter loop encounters JSOP_LOOPENTRY' (#3002) from jobbautista9/UXP:2229-jsop_loopentry into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3002
2026-03-18 15:21:31 +00:00
Moonchild 347681c219 Merge pull request 'Implement array.prototype.toSpliced and array.prototype.with' (#3005) from Basilisk-Dev/UXP-contrib:arraybycopy into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3005
2026-03-17 20:31:34 +00:00
Basilisk-Dev 2984237f4f Issue #2551 - implement array.prototype.toSpliced 2026-03-16 14:33:50 -04:00
Basilisk-Dev 1c4a73de71 Issue #2551 - implement array.prototype.with 2026-03-16 14:27:02 -04:00
Job Bautista d27df4d88f Issue #2229 - Follow-up: Don't attempt on-stack replacement for TLA modules
When interpreter loop encounters JSOP_LOOPENTRY, we should not let TLA modules
enter baseline JIT.
2026-03-16 11:28:25 +08:00
Moonchild 9562888e77 Merge pull request 'Flatten nested CSS to standard CSS before parsing (fix sites using nested CSS)' (#2999) from Basilisk-Dev/UXP-contrib:nested-css into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2999
Reviewed-by: Moonchild <moonchild@palemoon.org>
2026-03-14 18:24:58 +00:00
Moonchild 5536b38401 Merge pull request 'Add AudioNode constructors' (#2988) from audionode-constructors-pr into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2988
2026-03-14 18:19:08 +00:00
Moonchild c011b271a1 Issue #3001 - Restore table reference frame call.
While the result value was only used for debug purposes, the function
`FindReferenceFrameFor` also updates the reference frame for use
outside of debug builds. The opaque double use of this function
was not clear from code inspection and it was erroneously removed.

Resolves #3001
2026-03-14 19:16:41 +01:00
Basilisk-Dev c21fb81d3e Issue #2862 - css nesting pref true by default 2026-03-14 13:23:54 -04:00
Basilisk-Dev 5a3dcf5939 Issue #2862 - Remove unused vars in CSS flattener 2026-03-14 13:22:59 -04:00
Moonchild 1d709fe942 Merge pull request 'Update expat source to 2.7.4 and apply local patches' (#2998) from jobbautista9/UXP:expat-2.7.4 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2998
2026-03-13 17:06:21 +00:00
Moonchild e55c16146f Issue #2993 - Follow-up: Clobber. 2026-03-13 16:19:56 +01:00
Basilisk-Dev 997a9a3e13 Issue #2862 - Change tests from lowering to flattening 2026-03-13 09:01:56 -04:00
Basilisk-Dev 008f38579c Issue #2862 - Change code references from CSS lowering to CSS flattening 2026-03-13 08:58:18 -04:00
Basilisk-Dev d943e86b28 Issue #2862 - handle more edge cases in css lowering 2026-03-12 08:44:03 -04:00
Basilisk-Dev 3f2d707a83 Issue #2862 - more tests files for nested css 2026-03-12 08:43:58 -04:00
Basilisk-Dev b145a93ad6 Issue #2862 - Split the css lowering functionality out to a separate file for easier maintenance 2026-03-12 08:43:53 -04:00
Basilisk-Dev 3056028db4 Issue #2862 - Fix a few nested selectors 2026-03-12 08:43:48 -04:00
Basilisk-Dev b4dac14720 Issue #2862 - Modify the css lowerer so that the lowering pass now recognizes bare type-selector nested rules and combinator-led cases 2026-03-12 08:43:42 -04:00
Basilisk-Dev 76694b956f Issue #2862 - add initial nested css test file 2026-03-12 08:43:33 -04:00
Basilisk-Dev 9fab5b3e3c Issue #2862 - Initial attempt at a css lowering 2026-03-12 08:43:23 -04:00
Job Bautista d54491fdd0 Issue #2997 - Update expat source to 2.7.4 and apply local patches. 2026-03-12 13:50:10 +08:00
Moonchild 00c3c3a546 Merge pull request 'Only use SVE instructions on Apple Silicon (disable on aarch64 Linux)' (#2994) from Basilisk-Dev/UXP-contrib:vpx-sve into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2994
2026-03-11 20:50:08 +00:00
Moonchild 1da5c344be Merge pull request 'Implement TypedArray.prototype.toReversed()' (#2996) from Basilisk-Dev/UXP-contrib:typed-toReversed into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2996
2026-03-11 20:28:21 +00:00
Moonchild 76d66b5dad Merge pull request 'Work around macOS WebGL crash on unconsumed vertex attrib arrays' (#2995) from Basilisk-Dev/UXP-contrib:webgl-crash into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2995
2026-03-11 20:23:20 +00:00
Basilisk-Dev e502735eb2 Issue #2993 - only use SVE instructions on Apple Silicon (disable on aarch64 Linux) 2026-03-11 15:07:09 -04:00
Basilisk-Dev edfebe1b99 Issue #2551 - Implement TypedArray.prototype.toReversed() 2026-03-11 15:04:16 -04:00
Moonchild 250e4f75da Merge pull request 'Avoid empty replacements in macro expansion.' (#2986) from 2978 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2986
2026-03-11 19:03:59 +00:00
Basilisk-Dev 53f1bdd9c2 Issue #2978 - Work around macOS WebGL crash on unconsumed vertex attrib arrays 2026-03-11 14:25:20 -04:00
Moonchild ade298d0a7 Merge pull request 'Issue #2990 - implement object.GroupBy' (#2991) from Basilisk-Dev/UXP-contrib:objectgroupby into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2991
2026-03-10 15:24:08 +00:00
Basilisk-Dev 387b01ce14 Issue #2990 - implement object.GroupBy 2026-03-10 10:45:54 -04:00
Moonchild 47d2094329 Merge pull request 'Issue #2926 - Tweak mimalloc performance tunables' (#2989) from Basilisk-Dev/UXP-contrib:mimalloc-tweaks into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2989
2026-03-10 13:48:48 +00:00
Basilisk-Dev 43f9a8e1f0 Issue #2926 - Tweak mimalloc performance tunables:
MI_DEFAULT_PURGE_DECOMMITS=0 - fewer costly kernel operations and fewer immediate recommit/zero-fill penalties on reuse.

MI_DEFAULT_PURGE_DELAY=500 - short-lived allocation bursts can reuse pages directly, avoiding purge/reclaim ping-pong.

MI_DEFAULT_GENERIC_COLLECT=50000 - lower background allocator housekeeping overhead on hot allocation paths.
2026-03-10 09:08:14 -04:00
Moonchild 30e287371f Issue #2987 - Part 19: Add MediaStreamAudioDestinationNode constructor. 2026-03-10 11:19:11 +01:00
Moonchild a9246d7b28 Issue #2987 - Part 18: Add MediaStreamAudioSourceNode constructor. 2026-03-10 11:19:05 +01:00
Moonchild db1d73f05d Issue #2987 - Part 17: Add MediaElementAudioSourceNode constructor. 2026-03-10 11:18:39 +01:00
Moonchild 72b14ea177 Issue #2987 - Part 16: Add AudioBuffer constructor. 2026-03-10 11:18:02 +01:00
Moonchild 430c4a3f79 Issue #2987 - Part 15: Add PeriodicWave constructor. 2026-03-10 11:17:57 +01:00
Moonchild 93ed92f63b Issue #2987 - Part 14: Add OscillatorNode constructor. 2026-03-10 11:17:53 +01:00
Moonchild 4a1312c060 Issue #2987 - Part 13: Add DynamicsCompressorNode constructor. 2026-03-10 11:17:47 +01:00
Moonchild 303e1ecf34 Issue #2987 - Part 12: Add ChannelMergerNode constructor. 2026-03-10 11:17:42 +01:00
Moonchild 57b0e4a65b Issue #2987 - Part 11: Add ChannelSplitterNode constructor. 2026-03-10 11:17:38 +01:00
Moonchild 804a301068 Issue #2987 - Part 10: Add ConvolverNode constructor. 2026-03-10 11:17:32 +01:00
Moonchild aedb8a4d08 Issue #2987 - Part 9: Add StereoPannerNode constructor. 2026-03-10 11:17:27 +01:00
Moonchild 93072ab51e Issue #2987 - Part 8: Add PannerNode constructor. 2026-03-10 11:17:22 +01:00
Moonchild ca11a325bd Issue #2987 - Part 7: Add WaveShaperNode constructor. 2026-03-10 11:17:17 +01:00
Moonchild 3b088af0b1 Issue #2987 - Part 6: Add IIRFilterNode constructor. 2026-03-10 11:17:12 +01:00
Moonchild 09e52646e9 Issue #2987 - Part 5: Add BiQuadFilterNode constructor. 2026-03-10 11:17:07 +01:00
Moonchild 26ca6f4fcc Issue #2987 - Part 4: Add DelayNode constructor. 2026-03-10 11:17:02 +01:00
Moonchild b467d710ac Issue #2987 - Part 3: Add GainNode constructor. 2026-03-10 11:16:56 +01:00
Moonchild f4f11fada8 Issue #2987 - Part 2: Add AudioBufferSourceNode constructor. 2026-03-10 11:16:49 +01:00
Moonchild 43b3b47426 Issue #2987 - Part 1: Add AnalyserNode constructor. 2026-03-10 11:16:43 +01:00
132 changed files with 4892 additions and 1768 deletions

No files matched your search

+1 -1
View File
@@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Clobber for ICU 78.1
Clobber for libvpx changes
+1
View File
@@ -16,6 +16,7 @@
#include "mozilla/CORSMode.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h"
+76 -14
View File
@@ -9,6 +9,7 @@
#include "mozilla/CheckedInt.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsPrintfCString.h"
#include "WebGLActiveInfo.h"
#include "WebGLBuffer.h"
#include "WebGLContextUtils.h"
#include "WebGLFramebuffer.h"
@@ -27,6 +28,30 @@ namespace mozilla {
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
static uint8_t
NumUsedLocationsByElemTypeForDraw(GLenum elemType)
{
switch (elemType) {
case LOCAL_GL_FLOAT_MAT2:
case LOCAL_GL_FLOAT_MAT2x3:
case LOCAL_GL_FLOAT_MAT2x4:
return 2;
case LOCAL_GL_FLOAT_MAT3x2:
case LOCAL_GL_FLOAT_MAT3:
case LOCAL_GL_FLOAT_MAT3x4:
return 3;
case LOCAL_GL_FLOAT_MAT4x2:
case LOCAL_GL_FLOAT_MAT4x3:
case LOCAL_GL_FLOAT_MAT4:
return 4;
default:
return 1;
}
}
////////////////////////////////////////
class ScopedResolveTexturesForDraw
@@ -331,6 +356,7 @@ class ScopedDrawHelper final
{
WebGLContext* const mWebGL;
bool mDidFake;
std::vector<GLuint> mDisabledUnusedAttribs;
public:
ScopedDrawHelper(WebGLContext* webgl, const char* funcName, uint32_t firstVertex,
@@ -367,11 +393,43 @@ public:
}
mDidFake = true;
const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
#ifdef XP_MACOSX
if (mWebGL->gl->WorkAroundDriverBugs()) {
std::vector<bool> isActiveAttrib(mWebGL->mBoundVertexArray->mAttribs.Length(),
false);
for (const auto& progAttrib : linkInfo->attribs) {
const auto loc = progAttrib.mLoc;
if (loc < 0) {
continue;
}
const auto usedLocs =
NumUsedLocationsByElemTypeForDraw(progAttrib.mActiveInfo->mElemType);
for (uint32_t i = 0; i < usedLocs; ++i) {
const auto usedLoc = static_cast<uint32_t>(loc) + i;
if (usedLoc < isActiveAttrib.size()) {
isActiveAttrib[usedLoc] = true;
}
}
}
for (uint32_t i = 0; i < mWebGL->mBoundVertexArray->mAttribs.Length(); ++i) {
const auto& attrib = mWebGL->mBoundVertexArray->mAttribs[i];
if (!attrib.mEnabled || isActiveAttrib[i]) {
continue;
}
mWebGL->gl->fDisableVertexAttribArray(i);
mDisabledUnusedAttribs.push_back(i);
}
}
#endif
////
// Check UBO sizes.
const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
for (const auto& cur : linkInfo->uniformBlocks) {
const auto& dataSize = cur->mDataSize;
const auto& binding = cur->mBinding;
@@ -477,6 +535,10 @@ public:
if (mDidFake) {
mWebGL->UndoFakeVertexAttrib0();
}
for (const auto loc : mDisabledUnusedAttribs) {
mWebGL->gl->fEnableVertexAttribArray(loc);
}
}
};
@@ -607,12 +669,12 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
return;
MakeContextCurrent();
if (vertCount > mMaxVertIdsPerDraw) {
ErrorOutOfMemory(
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
return;
}
if (vertCount > mMaxVertIdsPerDraw) {
ErrorOutOfMemory(
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
return;
}
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
@@ -855,12 +917,12 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
return;
MakeContextCurrent();
if (vertCount > mMaxVertIdsPerDraw) {
ErrorOutOfMemory(
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
return;
}
if (vertCount > mMaxVertIdsPerDraw) {
ErrorOutOfMemory(
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
return;
}
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
+39
View File
@@ -100,6 +100,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 -4
View File
@@ -14,16 +14,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);
@@ -61,10 +71,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();
@@ -73,6 +82,8 @@ private:
void GetTimeDomainData(float* aData, size_t aLength);
private:
explicit AnalyserNode(AudioContext* aContext);
FFTBlock mAnalysisBlock;
nsTArray<AudioChunk> mChunks;
double mMinDecibels;
+18
View File
@@ -178,6 +178,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()
{
+5 -1
View File
@@ -24,6 +24,7 @@ class ThreadSharedFloatArrayBufferList;
namespace dom {
struct AudioBufferOptions;
class AudioContext;
/**
@@ -56,6 +57,10 @@ public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioBuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioBuffer)
static already_AddRefed<AudioBuffer>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const AudioBufferOptions& aOptions, ErrorResult& aRv);
nsPIDOMWindowInner* GetParentObject() const
{
nsCOMPtr<nsPIDOMWindowInner> parentObject = do_QueryReferent(mOwnerWindow);
@@ -134,4 +139,3 @@ protected:
} // namespace mozilla
#endif
+22 -2
View File
@@ -607,10 +607,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()
{
+16 -8
View File
@@ -12,13 +12,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;
@@ -33,6 +36,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,
@@ -98,10 +108,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().
@@ -129,7 +139,6 @@ private:
void SendBufferParameterToStream(JSContext* aCx);
void SendOffsetAndDurationParametersToStream(AudioNodeStream* aStream);
private:
double mLoopStart;
double mLoopEnd;
double mOffset;
@@ -145,4 +154,3 @@ private:
} // namespace mozilla
#endif
+49 -166
View File
@@ -11,10 +11,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"
@@ -245,13 +261,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>
@@ -303,18 +315,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>
@@ -344,181 +346,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 (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>
@@ -526,47 +440,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>
+2 -2
View File
@@ -316,6 +316,8 @@ public:
IMPL_EVENT_HANDLER(mozinterruptbegin)
IMPL_EVENT_HANDLER(mozinterruptend)
bool CheckClosed(ErrorResult& aRv);
private:
void DisconnectFromWindow();
void RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob);
@@ -326,8 +328,6 @@ private:
friend struct ::mozilla::WebAudioDecodeJob;
bool CheckClosed(ErrorResult& aRv);
nsTArray<MediaStream*> GetAllStreams() const;
private:
+22
View File
@@ -71,6 +71,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
{
+3
View File
@@ -250,6 +250,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);
+22 -1
View File
@@ -262,8 +262,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
+14 -5
View File
@@ -14,15 +14,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
@@ -63,10 +73,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;
@@ -78,4 +88,3 @@ private:
} // namespace mozilla
#endif
+23 -2
View File
@@ -74,8 +74,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*
@@ -86,4 +108,3 @@ ChannelMergerNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
} // namespace dom
} // namespace mozilla
+15 -6
View File
@@ -12,15 +12,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; }
@@ -35,10 +44,11 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
virtual ~ChannelMergerNode();
private:
ChannelMergerNode(AudioContext* aContext,
uint16_t aInputCount);
~ChannelMergerNode() = default;
const uint16_t mInputCount;
};
@@ -46,4 +56,3 @@ private:
} // namespace mozilla
#endif
+23 -2
View File
@@ -65,8 +65,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*
@@ -77,4 +99,3 @@ ChannelSplitterNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProt
} // namespace dom
} // namespace mozilla
+15 -6
View File
@@ -12,15 +12,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; }
@@ -35,10 +44,11 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
virtual ~ChannelSplitterNode();
private:
ChannelSplitterNode(AudioContext* aContext,
uint16_t aOutputCount);
~ChannelSplitterNode() = default;
const uint16_t mOutputCount;
};
@@ -46,4 +56,3 @@ private:
} // namespace mozilla
#endif
+27 -2
View File
@@ -203,8 +203,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
@@ -291,4 +317,3 @@ ConvolverNode::SetNormalize(bool aNormalize)
} // namespace dom
} // namespace mozilla
+17 -6
View File
@@ -12,14 +12,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
@@ -27,7 +39,7 @@ public:
return mBuffer;
}
void SetBuffer(JSContext* aCx, AudioBuffer* aBufferi, ErrorResult& aRv);
void SetBuffer(JSContext* aCx, AudioBuffer* aBuffer, ErrorResult& aRv);
bool Normalize() const
{
@@ -61,10 +73,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;
};
@@ -74,4 +86,3 @@ private:
} //end namespace mozilla
#endif
+23 -1
View File
@@ -205,8 +205,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 -6
View File
@@ -13,15 +13,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
@@ -37,13 +47,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;
};
@@ -51,4 +60,3 @@ private:
} // namespace mozilla
#endif
+23 -1
View File
@@ -204,8 +204,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 -5
View File
@@ -13,15 +13,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
@@ -69,10 +79,10 @@ public:
mReduction = aReduction;
}
protected:
virtual ~DynamicsCompressorNode();
private:
explicit DynamicsCompressorNode(AudioContext* aContext);
~DynamicsCompressorNode() = default;
RefPtr<AudioParam> mThreshold;
RefPtr<AudioParam> mKnee;
RefPtr<AudioParam> mRatio;
@@ -85,4 +95,3 @@ private:
} // namespace mozilla
#endif
+17 -1
View File
@@ -128,8 +128,24 @@ GainNode::GainNode(AudioContext* aContext)
aContext->Graph());
}
GainNode::~GainNode()
/* static */ already_AddRefed<GainNode>
GainNode::Create(AudioContext& aAudioContext,
const GainOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<GainNode> audioNode = new GainNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->Gain()->SetValue(aOptions.mGain);
return audioNode.forget();
}
size_t
+14 -5
View File
@@ -13,15 +13,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
@@ -37,10 +47,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;
};
@@ -48,4 +58,3 @@ private:
} // namespace mozilla
#endif
+41 -3
View File
@@ -138,8 +138,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,
@@ -173,8 +173,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
+18 -10
View File
@@ -14,18 +14,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,
@@ -39,16 +46,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
@@ -15,13 +15,29 @@ 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 (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;
}
@@ -11,11 +11,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;
@@ -15,7 +15,7 @@
namespace mozilla {
namespace dom {
class AudioDestinationTrackSource :
class AudioDestinationTrackSource final :
public MediaStreamTrackSource
{
public:
@@ -49,7 +49,7 @@ public:
}
private:
virtual ~AudioDestinationTrackSource() {}
~AudioDestinationTrackSource() = default;
RefPtr<MediaStreamAudioDestinationNode> mNode;
};
@@ -101,8 +101,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
@@ -11,14 +11,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
@@ -41,10 +53,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;
};
@@ -44,13 +44,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;
}
@@ -14,6 +14,9 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct MediaStreamAudioSourceOptions;
class MediaStreamAudioSourceNodeEngine final : public AudioNodeEngine
{
public:
@@ -45,11 +48,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;
+28 -1
View File
@@ -425,8 +425,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
+14 -6
View File
@@ -15,16 +15,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;
@@ -81,14 +91,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;
@@ -100,4 +109,3 @@ private:
} // namespace mozilla
#endif
+32 -1
View File
@@ -329,6 +329,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;
@@ -784,4 +816,3 @@ PannerNode::SendDopplerToSourcesIfNeeded()
} // namespace dom
} // namespace mozilla
+15 -5
View File
@@ -19,13 +19,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;
@@ -229,10 +240,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 {
@@ -292,4 +303,3 @@ private:
} // namespace mozilla
#endif
+26 -1
View File
@@ -43,6 +43,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
{
@@ -70,4 +96,3 @@ PeriodicWave::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
} // namespace dom
} // namespace mozilla
+8 -1
View File
@@ -16,6 +16,9 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct PeriodicWaveOptions;
class PeriodicWave final : public nsWrapperCache
{
public:
@@ -29,6 +32,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;
@@ -55,7 +62,7 @@ public:
size_t SizeOfIncludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const;
private:
~PeriodicWave() {}
~PeriodicWave() = default;
RefPtr<AudioContext> mContext;
RefPtr<ThreadSharedFloatArrayBufferList> mCoefficients;
+17 -1
View File
@@ -182,8 +182,24 @@ StereoPannerNode::StereoPannerNode(AudioContext* aContext)
aContext->Graph());
}
StereoPannerNode::~StereoPannerNode()
/* static */ already_AddRefed<StereoPannerNode>
StereoPannerNode::Create(AudioContext& aAudioContext,
const StereoPannerOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<StereoPannerNode> audioNode = new StereoPannerNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->Pan()->SetValue(aOptions.mPan);
return audioNode.forget();
}
size_t
+15 -5
View File
@@ -13,12 +13,23 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct StereoPannerOptions;
class StereoPannerNode final : public AudioNode
{
public:
static already_AddRefed<StereoPannerNode>
Create(AudioContext& aAudioContext, const StereoPannerOptions& aOptions,
ErrorResult& aRv);
MOZ_DECLARE_REFCOUNTED_TYPENAME(StereoPannerNode)
explicit StereoPannerNode(AudioContext* aContext);
static already_AddRefed<StereoPannerNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const StereoPannerOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -55,10 +66,10 @@ public:
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~StereoPannerNode();
private:
explicit StereoPannerNode(AudioContext* aContext);
~StereoPannerNode() = default;
RefPtr<AudioParam> mPan;
};
@@ -66,4 +77,3 @@ private:
} // namespace mozilla
#endif
+91 -41
View File
@@ -18,7 +18,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(WaveShaperNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WaveShaperNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
tmp->ClearCurve();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WaveShaperNode, AudioNode)
@@ -26,7 +25,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WaveShaperNode)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCurve)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WaveShaperNode)
@@ -313,27 +311,39 @@ WaveShaperNode::WaveShaperNode(AudioContext* aContext)
2,
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mCurve(nullptr)
, mType(OverSampleType::None)
{
mozilla::HoldJSObjects(this);
WaveShaperNodeEngine* engine = new WaveShaperNodeEngine(this);
mStream = AudioNodeStream::Create(aContext, engine,
AudioNodeStream::NO_STREAM_FLAGS,
aContext->Graph());
}
WaveShaperNode::~WaveShaperNode()
/* static */ already_AddRefed<WaveShaperNode>
WaveShaperNode::Create(AudioContext& aAudioContext,
const WaveShaperOptions& aOptions,
ErrorResult& aRv)
{
ClearCurve();
}
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
void
WaveShaperNode::ClearCurve()
{
mCurve = nullptr;
mozilla::DropJSObjects(this);
RefPtr<WaveShaperNode> audioNode = new WaveShaperNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (aOptions.mCurve.WasPassed()) {
audioNode->SetCurveInternal(aOptions.mCurve.Value(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}
audioNode->SetOversample(aOptions.mOversample);
return audioNode.forget();
}
JSObject*
@@ -345,45 +355,85 @@ WaveShaperNode::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
void
WaveShaperNode::SetCurve(const Nullable<Float32Array>& aCurve, ErrorResult& aRv)
{
nsTArray<float> curve;
if (!aCurve.IsNull()) {
const Float32Array& floats = aCurve.Value();
// Let's purge the cached value for the curve attribute.
WaveShaperNodeBinding::ClearCachedCurveValue(this);
floats.ComputeLengthAndData();
if (floats.IsShared()) {
// Throw if the object is mapping shared memory (must opt in).
aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of WaveShaperNode.setCurve"));
return;
}
uint32_t argLength = floats.Length();
if (argLength < 2) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (!curve.SetLength(argLength, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
PodCopy(curve.Elements(), floats.Data(), floats.Length());
mCurve = floats.Obj();
} else {
mCurve = nullptr;
if (aCurve.IsNull()) {
CleanCurveInternal();
return;
}
const Float32Array& floats = aCurve.Value();
floats.ComputeLengthAndData();
if (floats.IsShared()) {
// Throw if the object is mapping shared memory (must opt in).
aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of WaveShaperNode.setCurve"));
return;
}
nsTArray<float> curve;
uint32_t argLength = floats.Length();
if (!curve.SetLength(argLength, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
PodCopy(curve.Elements(), floats.Data(), argLength);
SetCurveInternal(curve, aRv);
}
void
WaveShaperNode::SetCurveInternal(const nsTArray<float>& aCurve,
ErrorResult& aRv)
{
if (aCurve.Length() < 2) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
mCurve = aCurve;
SendCurveToStream();
}
void
WaveShaperNode::CleanCurveInternal()
{
mCurve.Clear();
SendCurveToStream();
}
void
WaveShaperNode::SendCurveToStream()
{
AudioNodeStream* ns = mStream;
MOZ_ASSERT(ns, "Why don't we have a stream here?");
ns->SetRawArrayData(curve);
nsTArray<float> copyCurve(mCurve);
ns->SetRawArrayData(copyCurve);
}
void
WaveShaperNode::GetCurve(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval)
{
// Let's return a null value if the list is empty.
if (mCurve.IsEmpty()) {
aRetval.set(nullptr);
return;
}
MOZ_ASSERT(mCurve.Length() >= 2);
aRetval.set(Float32Array::Create(aCx, this, mCurve.Length(),
mCurve.Elements()));
}
void
WaveShaperNode::SetOversample(OverSampleType aType)
{
mType = aType;
SendInt32ParameterToStream(WaveShaperNodeEngine::TYPE, static_cast<int32_t>(aType));
SendInt32ParameterToStream(WaveShaperNodeEngine::TYPE,
static_cast<int32_t>(aType));
}
} // namespace dom
+21 -11
View File
@@ -14,21 +14,28 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct WaveShaperOptions;
class WaveShaperNode final : public AudioNode
{
public:
explicit WaveShaperNode(AudioContext *aContext);
static already_AddRefed<WaveShaperNode>
Create(AudioContext& aAudioContext, const WaveShaperOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WaveShaperNode, AudioNode)
static already_AddRefed<WaveShaperNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const WaveShaperOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
void GetCurve(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval) const
{
aRetval.set(mCurve);
}
void GetCurve(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval);
void SetCurve(const Nullable<Float32Array>& aData, ErrorResult& aRv);
OverSampleType Oversample() const
@@ -54,14 +61,17 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
virtual ~WaveShaperNode();
private:
void ClearCurve();
explicit WaveShaperNode(AudioContext *aContext);
~WaveShaperNode() = default;
private:
JS::Heap<JSObject*> mCurve;
void SetCurveInternal(const nsTArray<float>& aCurve,
ErrorResult& aRv);
void CleanCurveInternal();
void SendCurveToStream();
nsTArray<float> mCurve;
OverSampleType mType;
};
+79 -4
View File
@@ -10,9 +10,7 @@
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
function testNode() {
var context = new AudioContext();
var buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
@@ -84,7 +82,7 @@ addLoadEvent(function() {
analyser.maxDecibels = -101;
}, DOMException.INDEX_SIZE_ERR);
is(analyser.smoothingTimeConstant, 0.8, "Correct default value for smoothingTimeConstant");
ok(Math.abs(analyser.smoothingTimeConstant - 0.8) < 0.001, "Correct default value for smoothingTimeConstant");
expectException(function() {
analyser.smoothingTimeConstant = -0.1;
}, DOMException.INDEX_SIZE_ERR);
@@ -93,6 +91,83 @@ addLoadEvent(function() {
}, DOMException.INDEX_SIZE_ERR);
analyser.smoothingTimeConstant = 0;
analyser.smoothingTimeConstant = 1;
}
function testConstructor() {
var context = new AudioContext();
var analyser = new AnalyserNode(context);
is(analyser.channelCount, 1, "analyser node has 1 input channels by default");
is(analyser.channelCountMode, "max", "Correct channelCountMode for the analyser node");
is(analyser.channelInterpretation, "speakers", "Correct channelCountInterpretation for the analyser node");
is(analyser.fftSize, 2048, "Correct default value for fftSize");
is(analyser.frequencyBinCount, 1024, "Correct default value for frequencyBinCount");
is(analyser.minDecibels, -100, "Correct default value for minDecibels");
is(analyser.maxDecibels, -30, "Correct default value for maxDecibels");
ok(Math.abs(analyser.smoothingTimeConstant - 0.8) < 0.001, "Correct default value for smoothingTimeConstant");
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 0 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 1 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 8 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 100 }); // non-power of two
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 2049 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 4097 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 8193 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 16385 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 32769 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 65536 });
}, DOMException.INDEX_SIZE_ERR);
analyser = new AnalyserNode(context, { fftSize: 1024 });
is(analyser.frequencyBinCount, 512, "Correct new value for frequencyBinCount");
expectException(function() {
analyser = new AnalyserNode(context, { minDecibels: -30 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { minDecibels: -29 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { maxDecibels: -100 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { maxDecibels: -101 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { smoothingTimeConstant: -0.1 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { smoothingTimeConstant: -1.1 });
}, DOMException.INDEX_SIZE_ERR);
analyser = new AnalyserNode(context, { smoothingTimeConstant: 0 });
analyser = new AnalyserNode(context, { smoothingTimeConstant: 1 });
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
testNode();
testConstructor();
SimpleTest.finish();
});
@@ -19,12 +19,8 @@ var gTest = {
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
var source = context.createBufferSource();
source.buffer = buffer;
var source = new AudioBufferSourceNode(context, {buffer: buffer, loop: true, loopStart: buffer.duration * 0.25, loopEnd: buffer.duration * 0.75 });
source.start(0);
source.loop = true;
source.loopStart = buffer.duration * 0.25;
source.loopEnd = buffer.duration * 0.75;
return source;
},
createExpectedBuffers: function(context) {
@@ -24,7 +24,7 @@ var gTest = {
buffers.push(buffer);
}
var merger = context.createChannelMerger();
var merger = new ChannelMergerNode(context);
is(merger.channelCount, 1, "merger node has 1 input channels");
is(merger.channelCountMode, "explicit", "Correct channelCountMode for the merger node");
is(merger.channelInterpretation, "speakers", "Correct channelCountInterpretation for the merger node");
@@ -29,7 +29,7 @@ addLoadEvent(function() {
var source = context.createBufferSource();
var splitter = context.createChannelSplitter();
var splitter = new ChannelSplitterNode(context);
is(splitter.channelCount, 2, "splitter node has 2 input channels by default");
is(splitter.channelCountMode, "max", "Correct channelCountMode for the splitter node");
is(splitter.channelInterpretation, "speakers", "Correct channelCountInterpretation for the splitter node");
@@ -13,7 +13,7 @@
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var context = new AudioContext();
var conv = context.createConvolver();
var conv = new ConvolverNode(context);
is(conv.channelCount, 2, "Convolver node has 2 input channels by default");
is(conv.channelCountMode, "clamped-max", "Correct channelCountMode for the Convolver node");
+28 -1
View File
@@ -14,6 +14,19 @@ var gTest = {
length: 4096,
numberOfChannels: 1,
createGraph: function(context) {
var delay = new DelayNode(context);
ok(delay.delayTime, "The audioparam member must exist");
is(delay.delayTime.value, 0, "Correct initial value");
is(delay.delayTime.defaultValue, 0, "Correct default value");
delay.delayTime.value = 0.5;
is(delay.delayTime.value, 0.5, "Correct initial value");
is(delay.delayTime.defaultValue, 0, "Correct default value");
delay = new DelayNode(context, { delayTime: 0.5 });
ok(delay.delayTime, "The audioparam member must exist");
is(delay.delayTime.value, 0.5, "Correct initial value");
is(delay.delayTime.defaultValue, 0, "Correct default value");
var buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
@@ -21,7 +34,7 @@ var gTest = {
var source = context.createBufferSource();
var delay = context.createDelay();
delay = context.createDelay();
source.buffer = buffer;
@@ -49,6 +62,20 @@ var gTest = {
expectException(function() {
context.createDelay(-1);
}, DOMException.NOT_SUPPORTED_ERR);
expectException(function() {
new DelayNode(context, { maxDelayTime: 0 });
}, DOMException.NOT_SUPPORTED_ERR);
expectException(function() {
new DelayNode(context, { maxDelayTime: 180 });
}, DOMException.NOT_SUPPORTED_ERR);
expectTypeError(function() {
new DelayNode(context, { maxDelayTime: NaN });
}, DOMException.NOT_SUPPORTED_ERR);
expectException(function() {
new DelayNode(context, { maxDelayTime: -1 });
}, DOMException.NOT_SUPPORTED_ERR);
context.createDelay(1); // should not throw
// Delay the source stream by 2048 frames
@@ -20,7 +20,7 @@ addLoadEvent(function() {
var osc = context.createOscillator();
var sp = context.createScriptProcessor();
var compressor = context.createDynamicsCompressor();
var compressor = new DynamicsCompressorNode(context);
osc.connect(compressor);
osc.connect(sp);
+18 -3
View File
@@ -14,17 +14,32 @@ var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var gain = new GainNode(context);
ok(gain.gain, "The audioparam member must exist");
is(gain.gain.value, 1.0, "Correct initial value");
is(gain.gain.defaultValue, 1.0, "Correct default value");
gain.gain.value = 0.5;
is(gain.gain.value, 0.5, "Correct initial value");
is(gain.gain.defaultValue, 1.0, "Correct default value");
gain = new GainNode(context, { gain: 0.5 });
ok(gain.gain, "The audioparam member must exist");
is(gain.gain.value, 0.5, "Correct initial value");
is(gain.gain.defaultValue, 1.0, "Correct default value");
gain.gain.value = 0.5;
is(gain.gain.value, 0.5, "Correct initial value");
is(gain.gain.defaultValue, 1.0, "Correct default value");
var buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
var source = context.createBufferSource();
var gain = context.createGain();
source.buffer = buffer;
gain = context.createGain();
source.connect(gain);
ok(gain.gain, "The audioparam member must exist");
@@ -56,7 +56,7 @@ function test() {
}
audio.onloadedmetadata = function() {
var node = context.createMediaElementSource(audio);
var node = new MediaElementAudioSourceNode(context, { mediaElement: audio });
var sp = context.createScriptProcessor(2048, 1);
node.connect(sp);
// Use a fuzz factor of 100 to account for samples that just happen to be zero
@@ -23,7 +23,7 @@ addLoadEvent(function() {
var source = context.createBufferSource();
source.buffer = buffer;
var dest = context.createMediaStreamDestination();
var dest = new MediaStreamAudioDestinationNode(context);
source.connect(dest);
var elem = document.getElementById('audioelem');
@@ -31,7 +31,7 @@ var gTest = {
source.connect(dest);
source.start(0);
var mediaStreamSource = context.createMediaStreamSource(dest.stream);
var mediaStreamSource = new MediaStreamAudioSourceNode(context, { mediaStream: dest.stream });
// channelCount and channelCountMode should have no effect
mediaStreamSource.channelCount = 1;
mediaStreamSource.channelCountMode = "explicit";
@@ -14,7 +14,7 @@ SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var context = new AudioContext();
var osc = context.createOscillator();
var osc = new OscillatorNode(context);
is(osc.channelCount, 2, "Oscillator node has 2 input channels by default");
is(osc.channelCountMode, "max", "Correct channelCountMode for the Oscillator node");
+1 -1
View File
@@ -25,7 +25,7 @@ addLoadEvent(function() {
var source = context.createBufferSource();
var panner = context.createPanner();
var panner = new PannerNode(context);
source.buffer = buffer;
@@ -49,7 +49,7 @@ function applyMonoToStereoPanning(c, panning) {
// Test the DOM interface
var context = new OfflineAudioContext(1, 1, SR);
var stereoPanner = context.createStereoPanner();
var stereoPanner = new StereoPannerNode(context);
ok(stereoPanner.pan, "The AudioParam member must exist");
is(stereoPanner.pan.value, 0.0, "Correct initial value");
is(stereoPanner.pan.defaultValue, 0.0, "Correct default value");
@@ -70,8 +70,11 @@ function sine(t) {
// A couple mono and stereo buffers: the StereoPannerNode equation is different
// if the input is mono or stereo
var stereoBuffer = context.createBuffer(2, BUF_SIZE, context.sampleRate);
var monoBuffer = context.createBuffer(1, BUF_SIZE, context.sampleRate);
var stereoBuffer = new AudioBuffer(context, { numberOfChannels: 2,
length: BUF_SIZE });
var monoBuffer = new AudioBuffer(context, { numberOfChannels: 1,
length: BUF_SIZE,
sampleRate: context.sampleRate });
for (var i = 0; i < BUF_SIZE; ++i) {
monoBuffer.getChannelData(0)[i] =
stereoBuffer.getChannelData(0)[i] =
@@ -81,7 +84,9 @@ for (var i = 0; i < BUF_SIZE; ++i) {
// Expected test vectors
function expectedBufferNoop(gain) {
gain = gain || 1.0;
var expectedBuffer = context.createBuffer(2, BUF_SIZE, SR);
var expectedBuffer = new AudioBuffer(context, { numberOfChannels: 2,
length: BUF_SIZE,
sampleRate: SR });
for (var i = 0; i < BUF_SIZE; i++) {
expectedBuffer.getChannelData(0)[i] = gain * sine(i);
expectedBuffer.getChannelData(1)[i] = gain * sine(i);
@@ -91,7 +96,9 @@ function expectedBufferNoop(gain) {
function expectedBufferForStereo(gain) {
gain = gain || 1.0;
var expectedBuffer = context.createBuffer(2, BUF_SIZE, SR);
var expectedBuffer = new AudioBuffer(context, { numberOfChannels: 2,
length: BUF_SIZE,
sampleRate: SR });
var gainPanning = gainForPanningStereoToStereo(PANNING);
gainPanning[0] *= gain;
gainPanning[1] *= gain;
@@ -106,7 +113,9 @@ function expectedBufferForStereo(gain) {
function expectedBufferForMono(gain) {
gain = gain || 1.0;
var expectedBuffer = context.createBuffer(2, BUF_SIZE, SR);
var expectedBuffer = new AudioBuffer(context, { numberOfChannels: 2,
length: BUF_SIZE,
sampleRate: SR });
var gainPanning = gainForPanningMonoToStereo(PANNING);
gainPanning[0] *= gain;
gainPanning[1] *= gain;
+1 -1
View File
@@ -17,7 +17,7 @@ var gTest = {
var source = context.createBufferSource();
source.buffer = this.buffer;
var shaper = context.createWaveShaper();
var shaper = new WaveShaperNode(context);
shaper.curve = this.curve;
source.connect(shaper);
+9 -2
View File
@@ -10,7 +10,15 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary AnalyserOptions : AudioNodeOptions {
unsigned long fftSize = 2048;
float maxDecibels = -30;
float minDecibels = -100;
float smoothingTimeConstant = 0.8;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional AnalyserOptions options)]
interface AnalyserNode : AudioNode {
// Real-time frequency-domain data
@@ -38,4 +46,3 @@ interface AnalyserNode : AudioNode {
// Mozilla extension
AnalyserNode implements AudioNodePassThrough;
+8 -2
View File
@@ -10,7 +10,14 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary AudioBufferOptions {
unsigned long numberOfChannels = 1;
required unsigned long length;
float sampleRate;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, AudioBufferOptions options)]
interface AudioBuffer {
readonly attribute float sampleRate;
@@ -29,4 +36,3 @@ interface AudioBuffer {
[Throws]
void copyToChannel(Float32Array source, long channelNumber, optional unsigned long startInChannel = 0);
};
+11 -1
View File
@@ -10,7 +10,17 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary AudioBufferSourceOptions {
AudioBuffer? buffer;
float detune = 0;
boolean loop = false;
double loopEnd = 0;
double loopStart = 0;
float playbackRate = 1;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional AudioBufferSourceOptions options)]
interface AudioBufferSourceNode : AudioNode {
attribute AudioBuffer? buffer;
+6
View File
@@ -21,6 +21,12 @@ enum ChannelInterpretation {
"discrete"
};
dictionary AudioNodeOptions {
unsigned long channelCount;
ChannelCountMode channelCountMode;
ChannelInterpretation channelInterpretation;
};
[Pref="dom.webaudio.enabled"]
interface AudioNode : EventTarget {
+10 -1
View File
@@ -21,7 +21,16 @@ enum BiquadFilterType {
"allpass"
};
[Pref="dom.webaudio.enabled"]
dictionary BiquadFilterOptions : AudioNodeOptions {
BiquadFilterType type = "lowpass";
float Q = 1;
float detune = 0;
float frequency = 350;
float gain = 0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional BiquadFilterOptions options)]
interface BiquadFilterNode : AudioNode {
attribute BiquadFilterType type;
+6 -3
View File
@@ -10,8 +10,11 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
interface ChannelMergerNode : AudioNode {
dictionary ChannelMergerOptions : AudioNodeOptions {
unsigned long numberOfInputs = 6;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional ChannelMergerOptions options)]
interface ChannelMergerNode : AudioNode {
};
+6 -1
View File
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary ChannelSplitterOptions : AudioNodeOptions {
unsigned long numberOfOutputs = 6;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional ChannelSplitterOptions options)]
interface ChannelSplitterNode : AudioNode {
};
+7 -1
View File
@@ -10,7 +10,13 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary ConvolverOptions : AudioNodeOptions {
AudioBuffer? buffer;
boolean disableNormalization = false;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional ConvolverOptions options)]
interface ConvolverNode : AudioNode {
[SetterThrows]
+7 -1
View File
@@ -10,7 +10,13 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary DelayOptions : AudioNodeOptions {
double maxDelayTime = 1;
double delayTime = 0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional DelayOptions options)]
interface DelayNode : AudioNode {
readonly attribute AudioParam delayTime;
+10 -1
View File
@@ -10,7 +10,16 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary DynamicsCompressorOptions : AudioNodeOptions {
float attack = 0.003;
float knee = 30;
float ratio = 12;
float release = 0.25;
float threshold = -24;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional DynamicsCompressorOptions options)]
interface DynamicsCompressorNode : AudioNode {
readonly attribute AudioParam threshold; // in Decibels
+6 -1
View File
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary GainOptions : AudioNodeOptions {
float gain = 1.0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional GainOptions options)]
interface GainNode : AudioNode {
readonly attribute AudioParam gain;
+7 -1
View File
@@ -9,7 +9,13 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary IIRFilterOptions : AudioNodeOptions {
required sequence<double> feedforward;
required sequence<double> feedback;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, IIRFilterOptions options)]
interface IIRFilterNode : AudioNode {
void getFrequencyResponse(Float32Array frequencyHz, Float32Array magResponse, Float32Array phaseResponse);
};
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary MediaElementAudioSourceOptions {
required HTMLMediaElement mediaElement;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, MediaElementAudioSourceOptions options)]
interface MediaElementAudioSourceNode : AudioNode {
};
@@ -10,9 +10,8 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional AudioNodeOptions options)]
interface MediaStreamAudioDestinationNode : AudioNode {
readonly attribute MediaStream stream;
};
+6 -1
View File
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary MediaStreamAudioSourceOptions {
required MediaStream mediaStream;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, MediaStreamAudioSourceOptions options)]
interface MediaStreamAudioSourceNode : AudioNode {
};
+9 -2
View File
@@ -18,7 +18,15 @@ enum OscillatorType {
"custom"
};
[Pref="dom.webaudio.enabled"]
dictionary OscillatorOptions : AudioNodeOptions {
OscillatorType type = "sine";
float frequency = 440;
float detune = 0;
PeriodicWave periodicWave;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional OscillatorOptions options)]
interface OscillatorNode : AudioNode {
[SetterThrows]
@@ -39,4 +47,3 @@ interface OscillatorNode : AudioNode {
// Mozilla extensions
OscillatorNode implements AudioNodePassThrough;
+19 -1
View File
@@ -21,7 +21,25 @@ enum DistanceModelType {
"exponential"
};
[Pref="dom.webaudio.enabled"]
dictionary PannerOptions : AudioNodeOptions {
PanningModelType panningModel = "equalpower";
DistanceModelType distanceModel = "inverse";
float positionX = 0;
float positionY = 0;
float positionZ = 0;
float orientationX = 1;
float orientationY = 0;
float orientationZ = 0;
double refDistance = 1;
double maxDistance = 10000;
double rolloffFactor = 1;
double coneInnerAngle = 360;
double coneOuterAngle = 360;
double coneOuterGain = 0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional PannerOptions options)]
interface PannerNode : AudioNode {
// Default for stereo is equalpower
+7 -3
View File
@@ -10,8 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
interface PeriodicWave {
dictionary PeriodicWaveOptions : PeriodicWaveConstraints {
sequence<float> real;
sequence<float> imag;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, PeriodicWaveOptions options)]
interface PeriodicWave {
};
+6 -1
View File
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary StereoPannerOptions : AudioNodeOptions {
float pan = 0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional StereoPannerOptions options)]
interface StereoPannerNode : AudioNode {
readonly attribute AudioParam pan;
};
+8 -2
View File
@@ -16,10 +16,16 @@ enum OverSampleType {
"4x"
};
[Pref="dom.webaudio.enabled"]
dictionary WaveShaperOptions : AudioNodeOptions {
sequence<float> curve;
OverSampleType oversample = "none";
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional WaveShaperOptions options)]
interface WaveShaperNode : AudioNode {
[SetterThrows]
[Cached, Pure, SetterThrows]
attribute Float32Array? curve;
attribute OverSampleType oversample;
+1
View File
@@ -142,6 +142,7 @@ EditorBase::EditorBase()
, mDispatchInputEvent(true)
, mIsInEditAction(false)
, mHidingCaret(false)
, mIsHTMLEditorClass(false)
{
}
+20
View File
@@ -114,6 +114,7 @@ class DeleteNodeTransaction;
class DeleteTextTransaction;
class EditAggregateTransaction;
class ErrorResult;
class HTMLEditor;
class InsertNodeTransaction;
class InsertTextTransaction;
class JoinNodeTransaction;
@@ -121,6 +122,7 @@ class PlaceholderTransaction;
class RemoveStyleSheetTransaction;
class SplitNodeTransaction;
class TextComposition;
class TextEditor;
struct EditorDOMPoint;
namespace dom {
@@ -1113,14 +1115,32 @@ protected:
bool mIsInEditAction;
// Whether caret is hidden forcibly.
bool mHidingCaret;
// Whether we are an HTML editor class.
bool mIsHTMLEditorClass;
friend bool NSCanUnload(nsISupports* serviceMgr);
friend class AutoRules;
friend class AutoSelectionRestorer;
friend class AutoTransactionsConserveSelection;
friend class RangeUpdater;
friend class nsIEditor;
};
} // namespace mozilla
// nsIEditor helper functions.
// Here because of code context.
mozilla::EditorBase*
nsIEditor::AsEditorBase()
{
return static_cast<mozilla::EditorBase*>(this);
}
const mozilla::EditorBase*
nsIEditor::AsEditorBase() const
{
return static_cast<const mozilla::EditorBase*>(this);
}
#endif // #ifndef mozilla_EditorBase_h
+8 -1
View File
@@ -233,9 +233,16 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLEditRules, TextEditRules,
NS_IMETHODIMP
HTMLEditRules::Init(TextEditor* aTextEditor)
{
if (NS_WARN_IF(!aTextEditor)) {
return NS_ERROR_INVALID_ARG;
}
InitFields();
mHTMLEditor = static_cast<HTMLEditor*>(aTextEditor);
mHTMLEditor = aTextEditor->AsHTMLEditor();
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_INVALID_ARG;
}
// call through to base class Init
nsresult rv = TextEditRules::Init(aTextEditor);
+2 -1
View File
@@ -132,6 +132,7 @@ HTMLEditor::HTMLEditor()
, mPositionedObjectBorderTop(0)
, mGridSize(0)
{
mIsHTMLEditorClass = true;
}
HTMLEditor::~HTMLEditor()
@@ -501,7 +502,7 @@ HTMLEditor::InitRules()
// instantiate the rules for the html editor
mRules = new HTMLEditRules();
}
return mRules->Init(static_cast<TextEditor*>(this));
return mRules->Init(this);
}
NS_IMETHODIMP
+16
View File
@@ -1108,4 +1108,20 @@ private:
} // namespace mozilla
// nsIEditor helper functions.
// Here because of code context.
mozilla::HTMLEditor*
nsIEditor::AsHTMLEditor()
{
return static_cast<mozilla::EditorBase*>(this)->mIsHTMLEditorClass ?
static_cast<mozilla::HTMLEditor*>(this) : nullptr;
}
const mozilla::HTMLEditor*
nsIEditor::AsHTMLEditor() const
{
return static_cast<const mozilla::EditorBase*>(this)->mIsHTMLEditorClass ?
static_cast<const mozilla::HTMLEditor*>(this) : nullptr;
}
#endif // #ifndef mozilla_HTMLEditor_h
+21 -18
View File
@@ -30,24 +30,18 @@ namespace mozilla {
using namespace dom;
#ifdef DEBUG
nsresult
HTMLEditorEventListener::Connect(EditorBase* aEditorBase)
{
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryObject(aEditorBase);
nsCOMPtr<nsIHTMLInlineTableEditor> htmlInlineTableEditor =
do_QueryObject(aEditorBase);
NS_PRECONDITION(htmlEditor && htmlInlineTableEditor,
"Set HTMLEditor or its sub class");
return EditorEventListener::Connect(aEditorBase);
}
#endif
HTMLEditor*
HTMLEditorEventListener::GetHTMLEditor()
{
// mEditor must be HTMLEditor or its subclass.
return static_cast<HTMLEditor*>(mEditorBase);
if (NS_WARN_IF(!aEditorBase)) {
return NS_ERROR_INVALID_ARG;
}
// Guarantee that mEditorBase is always HTMLEditor.
HTMLEditor* htmlEditor = aEditorBase->AsHTMLEditor();
if (NS_WARN_IF(!htmlEditor)) {
return NS_ERROR_INVALID_ARG;
}
return EditorEventListener::Connect(htmlEditor);
}
nsresult
@@ -59,7 +53,8 @@ HTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
// FYI: We need to notify HTML editor of mouseup even if it's consumed
// because HTML editor always needs to release grabbing resizer.
HTMLEditor* htmlEditor = GetHTMLEditor();
HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor();
MOZ_ASSERT(htmlEditor);
nsCOMPtr<nsIDOMEventTarget> target;
nsresult rv = aMouseEvent->AsEvent()->GetTarget(getter_AddRefs(target));
@@ -85,7 +80,9 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
WidgetMouseEvent* mousedownEvent =
aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
HTMLEditor* htmlEditor = GetHTMLEditor();
HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor();
MOZ_ASSERT(htmlEditor);
// Contenteditable should disregard mousedowns outside it.
// IsAcceptableInputEvent() checks it for a mouse event.
if (!htmlEditor->IsAcceptableInputEvent(mousedownEvent)) {
@@ -221,13 +218,19 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
nsresult
HTMLEditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
{
if (NS_WARN_IF(DetachedFromEditor())) {
return NS_OK;
}
nsCOMPtr<nsIDOMEventTarget> target;
nsresult rv = aMouseEvent->AsEvent()->GetTarget(getter_AddRefs(target));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
GetHTMLEditor()->DoInlineTableEditingAction(element);
HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor();
MOZ_ASSERT(htmlEditor);
htmlEditor->DoInlineTableEditingAction(element);
return EditorEventListener::MouseClick(aMouseEvent);
}
+1 -5
View File
@@ -25,17 +25,13 @@ public:
{
}
#ifdef DEBUG
// WARNING: You must be use HTMLEditor or its sub class for this class.
// Connect() fails if aEditorBase isn't an HTMLEditor instance.
virtual nsresult Connect(EditorBase* aEditorBase) override;
#endif
protected:
virtual nsresult MouseDown(nsIDOMMouseEvent* aMouseEvent) override;
virtual nsresult MouseUp(nsIDOMMouseEvent* aMouseEvent) override;
virtual nsresult MouseClick(nsIDOMMouseEvent* aMouseEvent) override;
inline HTMLEditor* GetHTMLEditor();
};
} // namespace mozilla
+1
View File
@@ -10,6 +10,7 @@
#include "gfxFontUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/EditorUtils.h" // AutoEditBatch, AutoRules
#include "mozilla/HTMLEditor.h"
#include "mozilla/mozalloc.h"
#include "mozilla/Preferences.h"
#include "mozilla/TextEditRules.h"
+14
View File
@@ -247,4 +247,18 @@ protected:
} // namespace mozilla
// nsIEditor helper functions.
// Here because of code context.
mozilla::TextEditor*
nsIEditor::AsTextEditor()
{
return static_cast<mozilla::TextEditor*>(this);
}
const mozilla::TextEditor*
nsIEditor::AsTextEditor() const
{
return static_cast<const mozilla::TextEditor*>(this);
}
#endif // #ifndef mozilla_TextEditor_h
+38
View File
@@ -21,6 +21,14 @@ interface nsIEditActionListener;
interface nsIInlineSpellChecker;
interface nsITransferable;
%{C++
namespace mozilla {
class EditorBase;
class HTMLEditor;
class TextEditor;
} // namespace mozilla
%}
[scriptable, uuid(094be624-f0bf-400f-89e2-6a84baab9474)]
interface nsIEditor : nsISupports
{
@@ -564,4 +572,34 @@ interface nsIEditor : nsISupports
* or nsIEditorObserver::CancelEditAction(). Otherwise, false.
*/
[noscript] readonly attribute boolean isInEditAction;
%{C++
/**
* AsEditorBase() returns a pointer to EditorBase class.
*
* In order to avoid circular dependency issues, this method is defined
* in mozilla/EditorBase.h. Consumers need to #include that header.
*/
inline mozilla::EditorBase* AsEditorBase();
inline const mozilla::EditorBase* AsEditorBase() const;
/**
* AsTextEditor() returns a pointer to TextEditor class.
*
* In order to avoid circular dependency issues, this method is defined
* in mozilla/TextEditor.h. Consumers need to #include that header.
*/
inline mozilla::TextEditor* AsTextEditor();
inline const mozilla::TextEditor* AsTextEditor() const;
/**
* AsHTMLEditor() returns a pointer to HTMLEditor class.
*
* In order to avoid circular dependency issues, this method is defined
* in mozilla/HTMLEditor.h. Consumers need to #include that header.
*/
inline mozilla::HTMLEditor* AsHTMLEditor();
inline const mozilla::HTMLEditor* AsHTMLEditor() const;
%}
};
@@ -97,9 +97,6 @@ using namespace mozilla::dom;
#define INLINESPELL_STARTED_TOPIC "inlineSpellChecker-spellCheck-started"
#define INLINESPELL_ENDED_TOPIC "inlineSpellChecker-spellCheck-ended"
static bool ContentIsDescendantOf(nsINode* aPossibleDescendant,
nsINode* aPossibleAncestor);
static const char kMaxSpellCheckSelectionSize[] = "extensions.spellcheck.inline.max-misspellings";
mozInlineSpellStatus::mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker)
@@ -238,7 +235,7 @@ mozInlineSpellStatus::InitForNavigation(
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> currentAnchor = do_QueryInterface(aOldAnchorNode, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (root && currentAnchor && ! ContentIsDescendantOf(currentAnchor, root)) {
if (root && currentAnchor && !nsContentUtils::ContentIsShadowIncludingDescendantOf(currentAnchor, root)) {
*aContinue = false;
return NS_OK;
}
@@ -1490,8 +1487,11 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
return NS_OK;
}
aWordUtil.SetEnd(endNode, endOffset);
aWordUtil.SetPosition(beginNode, beginOffset);
nsresult rv = aWordUtil.SetPositionAndEnd(beginNode, beginOffset, endNode, endOffset);
if (NS_FAILED(rv)) {
// Just bail out and don't try to spell-check this
return NS_OK;
}
}
// aWordUtil.SetPosition flushes pending notifications, check editor again.
@@ -1840,24 +1840,6 @@ nsresult mozInlineSpellChecker::SaveCurrentSelectionPosition()
return NS_OK;
}
// This is a copy of nsContentUtils::ContentIsDescendantOf. Another crime
// for XPCOM's rap sheet
bool // static
ContentIsDescendantOf(nsINode* aPossibleDescendant,
nsINode* aPossibleAncestor)
{
NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
do {
if (aPossibleDescendant == aPossibleAncestor)
return true;
aPossibleDescendant = aPossibleDescendant->GetParentNode();
} while (aPossibleDescendant);
return false;
}
// mozInlineSpellChecker::HandleNavigationEvent
//
// Acts upon mouse clicks and keyboard navigation changes, spell checking
@@ -23,6 +23,8 @@
#include "nsIFrame.h"
#include <algorithm>
#include "mozilla/BinarySearch.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/dom/ShadowRoot.h"
using namespace mozilla;
@@ -69,8 +71,10 @@ mozInlineSpellWordUtil::Init(nsWeakPtr aWeakEditor)
mDOMDocument = domDoc;
mDocument = do_QueryInterface(domDoc);
// Find the root node for the editor. For contenteditable we'll need something
// cleverer here.
mIsContentEditableOrDesignMode = !!editor->AsHTMLEditor();
// Find the root node for the editor. For contenteditable the mRootNode could
// change to shadow root if the begin and end are inside the shadowDOM.
nsCOMPtr<nsIDOMElement> rootElt;
rv = editor->GetRootElement(getter_AddRefs(rootElt));
NS_ENSURE_SUCCESS(rv, rv);
@@ -154,7 +158,7 @@ FindNextTextNode(nsINode* aNode, int32_t aOffset, nsINode* aRoot)
return checkNode;
}
// mozInlineSpellWordUtil::SetEnd
// mozInlineSpellWordUtil::SetPositionAndEnd
//
// We have two ranges "hard" and "soft". The hard boundary is simply
// the scope of the root node. The soft boundary is that which is set
@@ -172,34 +176,44 @@ FindNextTextNode(nsINode* aNode, int32_t aOffset, nsINode* aRoot)
// position.
nsresult
mozInlineSpellWordUtil::SetEnd(nsINode* aEndNode, int32_t aEndOffset)
mozInlineSpellWordUtil::SetPositionAndEnd(nsINode* aPositionNode,
int32_t aPositionOffset,
nsINode* aEndNode,
int32_t aEndOffset)
{
MOZ_ASSERT(aPositionNode, "Null begin node?");
NS_PRECONDITION(aEndNode, "Null end node?");
NS_ASSERTION(mRootNode, "Not initialized");
// Find a appropriate root if we are dealing with contenteditable nodes which
// are in the shadow DOM. See UXP Issue #3011
if (mIsContentEditableOrDesignMode) {
nsINode* rootNode = aPositionNode->SubtreeRoot();
if (rootNode != aEndNode->SubtreeRoot()) {
return NS_ERROR_FAILURE;
}
if (mozilla::dom::ShadowRoot::FromNode(rootNode)) {
mRootNode = rootNode;
}
}
InvalidateWords();
if (!IsTextNode(aPositionNode)) {
// Start at the start of the first text node after aNode/aOffset.
aPositionNode = FindNextTextNode(aPositionNode, aPositionOffset, mRootNode);
aPositionOffset = 0;
}
mSoftBegin = NodeOffset(aPositionNode, aPositionOffset);
if (!IsTextNode(aEndNode)) {
// End at the start of the first text node after aEndNode/aEndOffset.
aEndNode = FindNextTextNode(aEndNode, aEndOffset, mRootNode);
aEndOffset = 0;
}
mSoftEnd = NodeOffset(aEndNode, aEndOffset);
return NS_OK;
}
nsresult
mozInlineSpellWordUtil::SetPosition(nsINode* aNode, int32_t aOffset)
{
InvalidateWords();
if (!IsTextNode(aNode)) {
// Start at the start of the first text node after aNode/aOffset.
aNode = FindNextTextNode(aNode, aOffset, mRootNode);
aOffset = 0;
}
mSoftBegin = NodeOffset(aNode, aOffset);
nsresult rv = EnsureWords();
if (NS_FAILED(rv)) {
@@ -207,8 +221,10 @@ mozInlineSpellWordUtil::SetPosition(nsINode* aNode, int32_t aOffset)
}
int32_t textOffset = MapDOMPositionToSoftTextOffset(mSoftBegin);
if (textOffset < 0)
if (textOffset < 0) {
return NS_OK;
}
mNextWordIndex = FindRealWordContaining(textOffset, HINT_END, true);
return NS_OK;
}
@@ -29,12 +29,11 @@ class nsINode;
* The basic operation is:
*
* 1. Call Init with the weak pointer to the editor that you're using.
* 2. Call SetEnd to set where you want to stop spellchecking. We'll stop
* at the word boundary after that. If SetEnd is not called, we'll stop
* at the end of the document's root element.
* 3. Call SetPosition to initialize the current position inside the
* previously given range.
* 4. Call GetNextWord over and over until it returns false.
* 2. Call SetPositionAndEnd to to initialize the current position inside the
* previously given range and set where you want to stop spellchecking.
* We'll stop at the word boundary after that. If SetEnd is not called,
* we'll stop at the end of the root element.
* 3. Call GetNextWord over and over until it returns false.
*/
class mozInlineSpellWordUtil
@@ -57,17 +56,22 @@ public:
};
mozInlineSpellWordUtil()
: mRootNode(nullptr),
mSoftBegin(nullptr, 0), mSoftEnd(nullptr, 0),
mNextWordIndex(-1), mSoftTextValid(false) {}
: mIsContentEditableOrDesignMode(false)
, mRootNode(nullptr)
, mSoftBegin(nullptr, 0)
, mSoftEnd(nullptr, 0)
, mNextWordIndex(-1)
, mSoftTextValid(false)
{}
nsresult Init(nsWeakPtr aWeakEditor);
nsresult SetEnd(nsINode* aEndNode, int32_t aEndOffset);
// sets the current position, this should be inside the range. If we are in
// the middle of a word, we'll move to its start.
nsresult SetPosition(nsINode* aNode, int32_t aOffset);
// Sets the current position and end. This should be inside the range.
// If we are in the middle of a word, we'll move to its start.
nsresult SetPositionAndEnd(nsINode* aPositionNode,
int32_t aPositionOffset,
nsINode* aEndNode,
int32_t aEndOffset);
// Given a point inside or immediately following a word, this returns the
// DOM range that exactly encloses that word's characters. The current
@@ -100,7 +104,8 @@ private:
// cached stuff for the editor, set by Init
nsCOMPtr<nsIDOMDocument> mDOMDocument;
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsIDocument> mDocument;
bool mIsContentEditableOrDesignMode;
// range to check, see SetPosition and SetEnd
nsINode* mRootNode;
+1132 -1048
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -1247,6 +1247,7 @@ static const JSFunctionSpec object_static_methods[] = {
JS_FN("seal", obj_seal, 1, 0),
JS_FN("isSealed", obj_isSealed, 1, 0),
JS_SELF_HOSTED_FN("fromEntries", "ObjectFromEntries", 1, 0),
JS_SELF_HOSTED_FN("groupBy", "ObjectGroupBy", 2, 0),
JS_SELF_HOSTED_FN("hasOwn", "ObjectHasOwn", 2, 0),
JS_FS_END
};
+178 -138
View File
@@ -4,228 +4,268 @@
// ES6 draft rev36 2015-03-17 19.1.2.1
function ObjectStaticAssign(target, firstSource) {
// Steps 1-2.
var to = ToObject(target);
// Steps 1-2.
var to = ToObject(target);
// Step 3.
if (arguments.length < 2)
return to;
// Step 3.
if (arguments.length < 2) return to;
// Steps 4-5.
for (var i = 1; i < arguments.length; i++) {
// Step 5.a.
var nextSource = arguments[i];
if (nextSource === null || nextSource === undefined)
continue;
// Steps 4-5.
for (var i = 1; i < arguments.length; i++) {
// Step 5.a.
var nextSource = arguments[i];
if (nextSource === null || nextSource === undefined) continue;
// Steps 5.b.i-ii.
var from = ToObject(nextSource);
// Steps 5.b.i-ii.
var from = ToObject(nextSource);
// Steps 5.b.iii-iv.
var keys = OwnPropertyKeys(from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
// Steps 5.b.iii-iv.
var keys = OwnPropertyKeys(
from,
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
);
// Step 5.c.
for (var nextIndex = 0, len = keys.length; nextIndex < len; nextIndex++) {
var nextKey = keys[nextIndex];
// Step 5.c.
for (var nextIndex = 0, len = keys.length; nextIndex < len; nextIndex++) {
var nextKey = keys[nextIndex];
// Steps 5.c.i-iii. We abbreviate this by calling propertyIsEnumerable
// which is faster and returns false for not defined properties.
if (callFunction(std_Object_propertyIsEnumerable, from, nextKey)) {
// Steps 5.c.iii.1-4.
to[nextKey] = from[nextKey];
}
}
// Steps 5.c.i-iii. We abbreviate this by calling propertyIsEnumerable
// which is faster and returns false for not defined properties.
if (callFunction(std_Object_propertyIsEnumerable, from, nextKey)) {
// Steps 5.c.iii.1-4.
to[nextKey] = from[nextKey];
}
}
}
// Step 6.
return to;
// Step 6.
return to;
}
// ES stage 4 proposal
function ObjectGetOwnPropertyDescriptors(O) {
// Step 1.
var obj = ToObject(O);
// Step 1.
var obj = ToObject(O);
// Step 2.
var keys = OwnPropertyKeys(obj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
// Step 2.
var keys = OwnPropertyKeys(
obj,
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
);
// Step 3.
var descriptors = {};
// Step 3.
var descriptors = {};
// Step 4.
for (var index = 0, len = keys.length; index < len; index++) {
var key = keys[index];
// Step 4.
for (var index = 0, len = keys.length; index < len; index++) {
var key = keys[index];
// Steps 4.a-b.
var desc = std_Object_getOwnPropertyDescriptor(obj, key);
// Steps 4.a-b.
var desc = std_Object_getOwnPropertyDescriptor(obj, key);
// Step 4.c.
if (typeof desc !== "undefined")
_DefineDataProperty(descriptors, key, desc);
}
// Step 4.c.
if (typeof desc !== "undefined")
_DefineDataProperty(descriptors, key, desc);
}
// Step 5.
return descriptors;
// Step 5.
return descriptors;
}
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.9. */
function ObjectGetPrototypeOf(obj) {
return std_Reflect_getPrototypeOf(ToObject(obj));
return std_Reflect_getPrototypeOf(ToObject(obj));
}
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.11. */
function ObjectIsExtensible(obj) {
return IsObject(obj) && std_Reflect_isExtensible(obj);
return IsObject(obj) && std_Reflect_isExtensible(obj);
}
/* ES2015 19.1.3.5 Object.prototype.toLocaleString */
function Object_toLocaleString() {
// Step 1.
var O = this;
// Step 1.
var O = this;
// Step 2.
return callContentFunction(O.toString, O);
// Step 2.
return callContentFunction(O.toString, O);
}
// ES 2017 draft bb96899bb0d9ef9be08164a26efae2ee5f25e875 19.1.3.7
function Object_valueOf() {
// Step 1.
return ToObject(this);
// Step 1.
return ToObject(this);
}
// ES7 draft (2016 March 8) B.2.2.3
function ObjectDefineSetter(name, setter) {
// Step 1.
var object = ToObject(this);
// Step 1.
var object = ToObject(this);
// Step 2.
if (!IsCallable(setter))
ThrowTypeError(JSMSG_BAD_GETTER_OR_SETTER, "setter");
// Step 2.
if (!IsCallable(setter)) ThrowTypeError(JSMSG_BAD_GETTER_OR_SETTER, "setter");
// Step 3.
var desc = {
__proto__: null,
enumerable: true,
configurable: true,
set: setter
};
// Step 3.
var desc = {
__proto__: null,
enumerable: true,
configurable: true,
set: setter,
};
// Step 4.
var key = ToPropertyKey(name);
// Step 4.
var key = ToPropertyKey(name);
// Step 5.
std_Object_defineProperty(object, key, desc);
// Step 5.
std_Object_defineProperty(object, key, desc);
// Step 6. (implicit)
// Step 6. (implicit)
}
// ES7 draft (2016 March 8) B.2.2.2
function ObjectDefineGetter(name, getter) {
// Step 1.
var object = ToObject(this);
// Step 1.
var object = ToObject(this);
// Step 2.
if (!IsCallable(getter))
ThrowTypeError(JSMSG_BAD_GETTER_OR_SETTER, "getter");
// Step 2.
if (!IsCallable(getter)) ThrowTypeError(JSMSG_BAD_GETTER_OR_SETTER, "getter");
// Step 3.
var desc = {
__proto__: null,
enumerable: true,
configurable: true,
get: getter
};
// Step 3.
var desc = {
__proto__: null,
enumerable: true,
configurable: true,
get: getter,
};
// Step 4.
var key = ToPropertyKey(name);
// Step 4.
var key = ToPropertyKey(name);
// Step 5.
std_Object_defineProperty(object, key, desc);
// Step 5.
std_Object_defineProperty(object, key, desc);
// Step 6. (implicit)
// Step 6. (implicit)
}
// ES7 draft (2016 March 8) B.2.2.5
function ObjectLookupSetter(name) {
// Step 1.
var object = ToObject(this);
// Step 1.
var object = ToObject(this);
// Step 2.
var key = ToPropertyKey(name)
// Step 2.
var key = ToPropertyKey(name);
do {
// Step 3.a.
var desc = std_Object_getOwnPropertyDescriptor(object, key);
do {
// Step 3.a.
var desc = std_Object_getOwnPropertyDescriptor(object, key);
// Step 3.b.
if (desc) {
// Step.b.i.
if (callFunction(std_Object_hasOwnProperty, desc, "set"))
return desc.set;
// Step 3.b.
if (desc) {
// Step.b.i.
if (callFunction(std_Object_hasOwnProperty, desc, "set")) return desc.set;
// Step.b.ii.
return undefined;
}
// Step.b.ii.
return undefined;
}
// Step 3.c.
object = std_Reflect_getPrototypeOf(object);
} while (object !== null);
// Step 3.c.
object = std_Reflect_getPrototypeOf(object);
} while (object !== null);
// Step 3.d. (implicit)
// Step 3.d. (implicit)
}
// ES7 draft (2016 March 8) B.2.2.4
function ObjectLookupGetter(name) {
// Step 1.
var object = ToObject(this);
// Step 1.
var object = ToObject(this);
// Step 2.
var key = ToPropertyKey(name)
// Step 2.
var key = ToPropertyKey(name);
do {
// Step 3.a.
var desc = std_Object_getOwnPropertyDescriptor(object, key);
do {
// Step 3.a.
var desc = std_Object_getOwnPropertyDescriptor(object, key);
// Step 3.b.
if (desc) {
// Step.b.i.
if (callFunction(std_Object_hasOwnProperty, desc, "get"))
return desc.get;
// Step 3.b.
if (desc) {
// Step.b.i.
if (callFunction(std_Object_hasOwnProperty, desc, "get")) return desc.get;
// Step.b.ii.
return undefined;
}
// Step.b.ii.
return undefined;
}
// Step 3.c.
object = std_Reflect_getPrototypeOf(object);
} while (object !== null);
// Step 3.c.
object = std_Reflect_getPrototypeOf(object);
} while (object !== null);
// Step 3.d. (implicit)
// Step 3.d. (implicit)
}
// Stage 4 draft 2020-09-06 https://tc39.github.io/proposal-object-from-entries/
// Object.fromEntries (iterable)
function ObjectFromEntries(iter) {
// We omit the usual step number comments here because they don't help.
// This implementation inlines AddEntriesFromIterator and
// CreateDataPropertyOnObject, so it looks more like the polyfill
// than the step-by-step spec algorithm.
const obj = {};
// We omit the usual step number comments here because they don't help.
// This implementation inlines AddEntriesFromIterator and
// CreateDataPropertyOnObject, so it looks more like the polyfill
// than the step-by-step spec algorithm.
const obj = {};
for (const pair of allowContentIter(iter)) {
if (!IsObject(pair))
ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "Object.fromEntries");
_DefineDataProperty(obj, pair[0], pair[1]);
for (const pair of allowContentIter(iter)) {
if (!IsObject(pair))
ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "Object.fromEntries");
_DefineDataProperty(obj, pair[0], pair[1]);
}
return obj;
}
// ES2024
// Object.groupBy ( items, callbackfn )
function ObjectGroupBy(items, callbackfn) {
// Step 1.
RequireObjectCoercible(items);
// Step 2.
if (!IsCallable(callbackfn))
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
// Step 3.
var groups = std_Object_create(null);
// Step 4.
var k = 0;
// Steps 5-8.
for (var value of allowContentIter(items)) {
// Step 6.a.
var key = callContentFunction(callbackfn, undefined, value, k);
// Step 6.b.
key = ToPropertyKey(key);
// Steps 6.c-d.
var elements = groups[key];
if (elements === undefined) {
_DefineDataProperty(groups, key, [value]);
} else {
callFunction(std_Array_push, elements, value);
}
return obj;
// Step 6.e.
k++;
}
// Step 9.
return groups;
}
// Proposal https://github.com/tc39/proposal-accessible-object-hasownproperty
// Object.hasOwn (Object, Property)
function ObjectHasOwn(O, P) {
// Step 1.
var obj = ToObject(O);
// Step 2-3.
return callFunction(std_Object_hasOwnProperty, obj, P);
// Step 1.
var obj = ToObject(O);
// Step 2-3.
return callFunction(std_Object_hasOwnProperty, obj, P);
}
+47
View File
@@ -60,6 +60,12 @@ function IsTypedArrayEnsuringArrayBuffer(arg) {
return true;
}
if (IsObject(arg) && IsPossiblyWrappedTypedArray(arg)) {
if (PossiblyWrappedTypedArrayHasDetachedBuffer(arg))
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
return false;
}
callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod");
return false;
}
@@ -157,6 +163,15 @@ function TypedArraySpeciesCreateWithBuffer(exemplar, buffer, byteOffset, length)
return TypedArrayCreateWithBuffer(C, buffer, byteOffset, length);
}
// ES2024 23.2.4.5 TypedArrayCreateSameType ( exemplar, argumentList )
function TypedArrayCreateSameType(exemplar, length) {
// Step 1.
var defaultConstructor = _ConstructorForTypedArray(exemplar);
// Step 2.
return TypedArrayCreateWithLength(defaultConstructor, length);
}
// ES6 draft 20150304 %TypedArray%.prototype.copyWithin
function TypedArrayCopyWithin(target, start, end = undefined) {
// This function is not generic.
@@ -848,6 +863,38 @@ function TypedArrayReverse() {
return O;
}
// ES2023 23.2.3.32 %TypedArray%.prototype.toReversed ( )
function TypedArrayToReversed() {
// Step 1.
var O = this;
// Step 2.
// This function is not generic.
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
// If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 4.
var A = TypedArrayCreateSameType(O, len);
// Steps 5-6.
for (var k = 0; k < len; k++) {
var from = len - k - 1;
A[k] = O[from];
}
// Step 7.
return A;
}
// ES6 draft 20150220 22.2.3.22.1 %TypedArray%.prototype.set(array [, offset])
function SetFromNonTypedArray(target, array, targetOffset, targetLength, targetBuffer) {
assert(!IsPossiblyWrappedTypedArray(array),
+5 -1
View File
@@ -3209,7 +3209,9 @@ static const JSFunctionSpec array_methods[] = {
JS_SELF_HOSTED_FN("findLast", "ArrayFindLast", 1,0),
JS_SELF_HOSTED_FN("findLastIndex", "ArrayFindLastIndex", 1,0),
JS_SELF_HOSTED_FN("toReversed", "ArrayToReversed", 0,0),
JS_SELF_HOSTED_FN("toSpliced", "ArrayToSpliced", 2,0),
JS_SELF_HOSTED_FN("toSorted", "ArrayToSorted", 1,0),
JS_SELF_HOSTED_FN("with", "ArrayWith", 2,0),
JS_FS_END
};
@@ -3382,8 +3384,10 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
!DefineProperty(cx, unscopables, cx->names().includes, value) ||
!DefineProperty(cx, unscopables, cx->names().keys, value) ||
!DefineProperty(cx, unscopables, cx->names().toReversed, value) ||
!DefineProperty(cx, unscopables, cx->names().toSpliced, value) ||
!DefineProperty(cx, unscopables, cx->names().values, value) ||
!DefineProperty(cx, unscopables, cx->names().toSorted, value))
!DefineProperty(cx, unscopables, cx->names().toSorted, value) ||
!DefineProperty(cx, unscopables, cx->names().with, value))
{
return false;
}
+59
View File
@@ -0,0 +1,59 @@
<!doctype html>
<meta charset="utf-8">
<title>Array.prototype.toSpliced test</title>
<style>
body { font: 14px/1.4 sans-serif; padding: 16px; }
.pass { color: #0a0; }
.fail { color: #c00; }
pre { white-space: pre-wrap; }
</style>
<pre id="log"></pre>
<script>
(function() {
const log = document.getElementById("log");
function write(msg, cls) {
const line = document.createElement("div");
if (cls) line.className = cls;
line.textContent = msg;
log.appendChild(line);
}
window.assertEq = function(actual, expected, msg) {
if (actual !== expected) {
throw new Error((msg ? msg + ": " : "") +
"expected " + expected + ", got " + actual);
}
};
window.assertThrowsInstanceOf = function(fn, ctor, msg) {
let threw = false;
try {
fn();
} catch (e) {
if (e instanceof ctor) {
threw = true;
} else {
throw new Error((msg ? msg + ": " : "") +
"threw " + e + ", expected " + ctor.name);
}
}
if (!threw) {
throw new Error((msg ? msg + ": " : "") + "did not throw");
}
};
window.reportCompare = function() {};
let hadError = false;
window.addEventListener("error", function(e) {
hadError = true;
write("FAIL: " + e.message, "fail");
});
window.addEventListener("load", function() {
write("PASS: toSpliced.js loaded", "pass");
if (!hadError)
write("PASS: all toSpliced tests passed", "pass");
});
})();
</script>
<script src="toSpliced.js"></script>
+113
View File
@@ -0,0 +1,113 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
assertEq(typeof Array.prototype.toSpliced, "function");
assertEq(Array.prototype.toSpliced.length, 2);
let desc = Object.getOwnPropertyDescriptor(Array.prototype, "toSpliced");
assertEq(desc.writable, true);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
assertThrowsInstanceOf(function () {
Array.prototype.toSpliced.call(null, 0, 0);
}, TypeError);
assertThrowsInstanceOf(function () {
Array.prototype.toSpliced.call(undefined, 0, 0);
}, TypeError);
// Non-mutating behavior.
let original = [1, 2, 3, 4];
let spliced = original.toSpliced(1, 2, "a", "b");
assertEq(original !== spliced, true);
assertEq(original.join(","), "1,2,3,4");
assertEq(spliced.join(","), "1,a,b,4");
assertEq(original.toSpliced().join(","), "1,2,3,4");
// Start index clamping and negatives.
assertEq([1, 2, 3].toSpliced(-1, 1, 9).join(","), "1,2,9");
assertEq([1, 2, 3].toSpliced(-99, 1, 9).join(","), "9,2,3");
assertEq([1, 2, 3].toSpliced(99, 1, 9).join(","), "1,2,3,9");
// deleteCount handling.
assertEq([1, 2, 3].toSpliced(1).join(","), "1");
assertEq([1, 2, 3].toSpliced(1, -3, 9).join(","), "1,9,2,3");
// Holes are materialized as undefined in copied segments.
let sparse = [1, , 3, 4];
let sparseResult = sparse.toSpliced(2, 1, "x");
assertEq(sparseResult.length, 4);
assertEq(sparseResult[0], 1);
assertEq(sparseResult[1], undefined);
assertEq(1 in sparseResult, true);
assertEq(sparseResult[2], "x");
assertEq(sparseResult[3], 4);
// Generic behavior on array-like values.
let arrayLike = { 0: "a", 1: "b", 3: "d", length: 4 };
let arrayLikeResult = Array.prototype.toSpliced.call(arrayLike, 1, 2, "X", "Y");
assertEq(Array.isArray(arrayLikeResult), true);
assertEq(arrayLikeResult.join(","), "a,X,Y,d");
// Element reads are ascending and skipped region is not read.
let accessLog = [];
let getterArr = {
length: 5,
get 0() {
accessLog.push(0);
return "z0";
},
get 1() {
accessLog.push(1);
throw new Error("must not be read");
},
get 2() {
accessLog.push(2);
throw new Error("must not be read");
},
get 3() {
accessLog.push(3);
return "z3";
},
get 4() {
accessLog.push(4);
return "z4";
},
};
let getterResult = Array.prototype.toSpliced.call(getterArr, 1, 2, "X");
assertEq(accessLog.join(","), "0,3,4");
assertEq(getterResult.join(","), "z0,X,z3,z4");
// constructor / Symbol.species is ignored and constructor is not read.
let constructorAccessed = false;
let speciesIgnored = [1, 2, 3];
Object.defineProperty(speciesIgnored, "constructor", {
get: function () {
constructorAccessed = true;
throw new Error("constructor should not be read");
},
configurable: true,
});
let speciesIgnoredResult = speciesIgnored.toSpliced(1, 1, 9);
assertEq(constructorAccessed, false);
assertEq(Array.isArray(speciesIgnoredResult), true);
assertEq(speciesIgnoredResult.join(","), "1,9,3");
// Length limit check happens before indexed reads.
let indexedRead = false;
let tooLong = {
length: 4294967296,
get 0() {
indexedRead = true;
throw new Error("index getter should not run");
},
};
assertThrowsInstanceOf(function () {
Array.prototype.toSpliced.call(tooLong, 0, 0);
}, RangeError);
assertEq(indexedRead, false);
// @@unscopables must include toSpliced.
assertEq(Array.prototype[Symbol.unscopables].toSpliced, true);
if (typeof reportCompare === "function") reportCompare(0, 0);
Loaded 100 of 132 files, more files were not shown because too many files have changed in this diff. Show more