Compare commits
110
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a4dc8de41 | ||
|
|
18595b01b6 | ||
|
|
f7215fc685 | ||
|
|
08521d4651 | ||
|
|
00b177d75f | ||
|
|
a89a071049 | ||
|
|
f9dc8a091a | ||
|
|
944299ed6c | ||
|
|
0e1441155c | ||
|
|
7bf5dfe4e4 | ||
|
|
d4c34fc9f7 | ||
|
|
6811005551 | ||
|
|
464cefa127 | ||
|
|
c94a1ab5d3 | ||
|
|
8aa5b35605 | ||
|
|
25dd1fb31a | ||
|
|
d8cf2c8b44 | ||
|
|
938c5d08d4 | ||
|
|
7fca2b8de3 | ||
|
|
ef19ad3ffd | ||
|
|
ab88527fe6 | ||
|
|
6c0ff1881a | ||
|
|
1e7f4c8474 | ||
|
|
fdf491d4ec | ||
|
|
1f4cceca43 | ||
|
|
542eaca577 | ||
|
|
1cb6f56418 | ||
|
|
a503e883d9 | ||
|
|
347681c219 | ||
|
|
2984237f4f | ||
|
|
1c4a73de71 | ||
|
|
d27df4d88f | ||
|
|
9562888e77 | ||
|
|
5536b38401 | ||
|
|
c011b271a1 | ||
|
|
c21fb81d3e | ||
|
|
5a3dcf5939 | ||
|
|
1d709fe942 | ||
|
|
e55c16146f | ||
|
|
997a9a3e13 | ||
|
|
008f38579c | ||
|
|
d943e86b28 | ||
|
|
3f2d707a83 | ||
|
|
b145a93ad6 | ||
|
|
3056028db4 | ||
|
|
b4dac14720 | ||
|
|
76694b956f | ||
|
|
9fab5b3e3c | ||
|
|
d54491fdd0 | ||
|
|
00c3c3a546 | ||
|
|
1da5c344be | ||
|
|
76d66b5dad | ||
|
|
e502735eb2 | ||
|
|
edfebe1b99 | ||
|
|
250e4f75da | ||
|
|
53f1bdd9c2 | ||
|
|
ade298d0a7 | ||
|
|
387b01ce14 | ||
|
|
47d2094329 | ||
|
|
43f9a8e1f0 | ||
|
|
30e287371f | ||
|
|
a9246d7b28 | ||
|
|
db1d73f05d | ||
|
|
72b14ea177 | ||
|
|
430c4a3f79 | ||
|
|
93ed92f63b | ||
|
|
4a1312c060 | ||
|
|
303e1ecf34 | ||
|
|
57b0e4a65b | ||
|
|
804a301068 | ||
|
|
aedb8a4d08 | ||
|
|
93072ab51e | ||
|
|
ca11a325bd | ||
|
|
3b088af0b1 | ||
|
|
09e52646e9 | ||
|
|
26ca6f4fcc | ||
|
|
b467d710ac | ||
|
|
f4f11fada8 | ||
|
|
43b3b47426 | ||
|
|
77f8cae06e | ||
|
|
daa31cfd59 | ||
|
|
b4ad4b7293 | ||
|
|
a2947909e8 | ||
|
|
bc2d0521e7 | ||
|
|
95ca42dd06 | ||
|
|
0c0dfca015 | ||
|
|
17cd2e4d07 | ||
|
|
f305547835 | ||
|
|
5ee86104a8 | ||
|
|
0ab247bee9 | ||
|
|
5370edc560 | ||
|
|
f27b6cbd21 | ||
|
|
de3485ed67 | ||
|
|
7f8489bc11 | ||
|
|
8c1cf4cc02 | ||
|
|
b8fbac6365 | ||
|
|
c7cc4ef650 | ||
|
|
9d1789b62f | ||
|
|
9a1c99e1a2 | ||
|
|
abc435f18e | ||
|
|
2e6dab8672 | ||
|
|
e0b95b12da | ||
|
|
722ecd0d97 | ||
|
|
e72cc38641 | ||
|
|
ae227b8743 | ||
|
|
a268e57967 | ||
|
|
9f05dad78c | ||
|
|
ba0112d574 | ||
|
|
18096194f5 | ||
|
|
b4e9888d91 |
No files matched your search
@@ -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
|
||||
@@ -127,7 +127,6 @@ def old_configure_options(*options):
|
||||
'--enable-alsa',
|
||||
'--enable-appcompat-guid',
|
||||
'--enable-av1',
|
||||
'--enable-jxl',
|
||||
'--enable-b2g-bt',
|
||||
'--enable-b2g-camera',
|
||||
'--enable-b2g-ril',
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -613,14 +613,6 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||
|
||||
nsresult rv;
|
||||
{
|
||||
// Update our current script.
|
||||
Maybe<AutoCurrentScriptUpdater> masterScriptUpdater;
|
||||
nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
|
||||
if (master != mDocument) {
|
||||
masterScriptUpdater.emplace(master->ScriptLoader(),
|
||||
aRequest->Element());
|
||||
}
|
||||
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> module(cx);
|
||||
|
||||
@@ -2323,8 +2315,14 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Update our current script.
|
||||
// This must be destroyed after destroying nsAutoMicroTask.
|
||||
nsIScriptElement* currentScript =
|
||||
aRequest->IsModuleRequest() ? nullptr : aRequest->Element();
|
||||
AutoCurrentScriptUpdater scriptUpdater(this, currentScript);
|
||||
|
||||
// New script entry point required, due to the "Create a script" sub-step of
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
|
||||
// http://html.spec.whatwg.org/multipage/#execute-the-script-block
|
||||
nsAutoMicroTask mt;
|
||||
AutoEntryScript aes(globalObject, "<script> element", true);
|
||||
JSContext* cx = aes.cx();
|
||||
@@ -2382,9 +2380,6 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||
FinishDynamicImport(cx, request, rv);
|
||||
}
|
||||
} else {
|
||||
// Update our current script.
|
||||
AutoCurrentScriptUpdater scriptUpdater(this, aRequest->Element());
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
|
||||
|
||||
|
||||
@@ -324,7 +324,9 @@ class ScriptLoader final : public nsISupports
|
||||
: mOldScript(aScriptLoader->mCurrentScript)
|
||||
, mScriptLoader(aScriptLoader)
|
||||
{
|
||||
mScriptLoader->mCurrentScript = aCurrentScript;
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentScript);
|
||||
mScriptLoader->mCurrentScript =
|
||||
node && !node->IsInShadowTree() ? aCurrentScript : nullptr;
|
||||
}
|
||||
~AutoCurrentScriptUpdater()
|
||||
{
|
||||
|
||||
+85
-23
@@ -57,7 +57,84 @@ CreateObjectURLInternal(const GlobalObject& aGlobal, T aObject,
|
||||
CopyASCIItoUTF16(url, aResult);
|
||||
}
|
||||
|
||||
// The URL implementation for the main-thread
|
||||
bool
|
||||
IsRootRelativePathInput(const nsAString& aURL)
|
||||
{
|
||||
return !aURL.IsEmpty() && aURL.CharAt(0) == '/' &&
|
||||
(aURL.Length() == 1 || aURL.CharAt(1) != '/');
|
||||
}
|
||||
|
||||
bool
|
||||
BuildRootRelativeFallbackSpec(const nsAString& aURL, nsIURI* aBase,
|
||||
nsACString& aFallbackSpec)
|
||||
{
|
||||
MOZ_ASSERT(aBase);
|
||||
MOZ_ASSERT(IsRootRelativePathInput(aURL));
|
||||
|
||||
nsAutoCString baseSpec;
|
||||
if (NS_FAILED(aBase->GetSpec(baseSpec)) || baseSpec.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t colon = baseSpec.FindChar(':');
|
||||
if (colon <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t afterColon = static_cast<uint32_t>(colon + 1);
|
||||
if (afterColon >= baseSpec.Length() || baseSpec.CharAt(afterColon) != '/') {
|
||||
// Opaque paths (for example mailto:test@example.com) are not valid bases
|
||||
// for root-relative URL input.
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString input;
|
||||
if (!AppendUTF16toUTF8(aURL, input, fallible)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preserve authority when present (scheme://authority/path -> scheme://authority/input)
|
||||
if (afterColon + 1 < baseSpec.Length() && baseSpec.CharAt(afterColon + 1) == '/') {
|
||||
uint32_t authorityEnd = afterColon + 2;
|
||||
while (authorityEnd < baseSpec.Length()) {
|
||||
char c = baseSpec.CharAt(authorityEnd);
|
||||
if (c == '/' || c == '?' || c == '#') {
|
||||
break;
|
||||
}
|
||||
++authorityEnd;
|
||||
}
|
||||
|
||||
aFallbackSpec.Assign(Substring(baseSpec, 0, authorityEnd));
|
||||
aFallbackSpec.Append(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Single-slash hierarchical base (scheme:/path -> scheme:/input)
|
||||
aFallbackSpec.Assign(Substring(baseSpec, 0, afterColon));
|
||||
aFallbackSpec.Append(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TryResolveRootRelativeAgainstBase(const nsAString& aURL, nsIURI* aBase,
|
||||
nsIURI** aOutURI)
|
||||
{
|
||||
MOZ_ASSERT(aOutURI);
|
||||
|
||||
if (!aBase || !IsRootRelativePathInput(aURL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString fallbackSpec;
|
||||
if (!BuildRootRelativeFallbackSpec(aURL, aBase, fallbackSpec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = NS_NewURI(aOutURI, fallbackSpec, nullptr, nullptr,
|
||||
nsContentUtils::GetIOService());
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
class URLMainThread final : public URL
|
||||
{
|
||||
public:
|
||||
@@ -229,7 +306,8 @@ URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL,
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase,
|
||||
nsContentUtils::GetIOService());
|
||||
if (NS_FAILED(rv)) {
|
||||
if (NS_FAILED(rv) &&
|
||||
!TryResolveRootRelativeAgainstBase(aURL, aBase, getter_AddRefs(uri))) {
|
||||
// No need to warn in this case. It's common to use the URL constructor
|
||||
// to determine if a URL is valid and an exception will be propagated.
|
||||
aRv.ThrowTypeError<MSG_INVALID_URL>(aURL);
|
||||
@@ -1714,30 +1792,14 @@ URL::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
|
||||
bool
|
||||
URL::CanParse(const GlobalObject& aGlobal, const nsAString& aURL,
|
||||
const Optional<nsAString>& aBase) {
|
||||
nsCOMPtr<nsIURI> baseUri;
|
||||
if (aBase.WasPassed()) {
|
||||
// Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
|
||||
nsAutoCString base;
|
||||
if (!AppendUTF16toUTF8(aBase.Value(), base, fallible)) {
|
||||
// Just return false with OOM errors as no ErrorResult.
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(baseUri), base);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Invalid base URL, return false.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCString urlStr;
|
||||
if (!AppendUTF16toUTF8(aURL, urlStr, fallible)) {
|
||||
// Just return false with OOM errors as no ErrorResult.
|
||||
ErrorResult rv;
|
||||
RefPtr<URL> parsed = URL::Constructor(aGlobal, aURL, aBase, rv);
|
||||
if (rv.Failed() || !parsed) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
return NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), urlStr, nullptr, baseUri));
|
||||
return true;
|
||||
}
|
||||
|
||||
URLSearchParams*
|
||||
|
||||
+414
-412
@@ -1,460 +1,462 @@
|
||||
<!DOCTYPE HTML>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test URL API</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887364">Mozilla Bug 887364</a>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=991471">Mozilla Bug 991471</a>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=996055">Mozilla Bug 996055</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe name="x" id="x"></iframe>
|
||||
<iframe name="y" id="y"></iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<script type="application/javascript">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Test URL API</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887364">Mozilla Bug 887364</a>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=991471">Mozilla Bug 991471</a>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=996055">Mozilla Bug 996055</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe name="x" id="x"></iframe>
|
||||
<iframe name="y" id="y"></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script type="application/javascript">
|
||||
/** Test for Bug 887364 **/
|
||||
ok("URL" in window, "window.URL exists");
|
||||
|
||||
/** Test for Bug 887364 **/
|
||||
ok("URL" in window, "window.URL exists");
|
||||
var tests = [
|
||||
{
|
||||
url: "http://www.abc.com",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: "http://www.abc.com/",
|
||||
origin: "http://www.abc.com",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "www.abc.com",
|
||||
hostname: "www.abc.com",
|
||||
port: "",
|
||||
pathname: "/",
|
||||
search: "",
|
||||
hash: "",
|
||||
},
|
||||
{
|
||||
url: "ftp://auser:apw@www.abc.com",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: "ftp://auser:apw@www.abc.com/",
|
||||
origin: "ftp://www.abc.com",
|
||||
protocol: "ftp:",
|
||||
username: "auser",
|
||||
password: "apw",
|
||||
host: "www.abc.com",
|
||||
hostname: "www.abc.com",
|
||||
port: "",
|
||||
pathname: "/",
|
||||
search: "",
|
||||
hash: "",
|
||||
},
|
||||
{
|
||||
url: "http://www.abc.com:90/apath/",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: "http://www.abc.com:90/apath/",
|
||||
origin: "http://www.abc.com:90",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "www.abc.com:90",
|
||||
hostname: "www.abc.com",
|
||||
port: "90",
|
||||
pathname: "/apath/",
|
||||
search: "",
|
||||
hash: "",
|
||||
},
|
||||
{
|
||||
url: "http://www.abc.com/apath/afile.txt#ahash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: "http://www.abc.com/apath/afile.txt#ahash",
|
||||
origin: "http://www.abc.com",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "www.abc.com",
|
||||
hostname: "www.abc.com",
|
||||
port: "",
|
||||
pathname: "/apath/afile.txt",
|
||||
search: "",
|
||||
hash: "#ahash",
|
||||
},
|
||||
{
|
||||
url: "http://example.com/?test#hash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: "http://example.com/?test#hash",
|
||||
origin: "http://example.com",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "example.com",
|
||||
hostname: "example.com",
|
||||
port: "",
|
||||
pathname: "/",
|
||||
search: "?test",
|
||||
hash: "#hash",
|
||||
},
|
||||
{
|
||||
url: "http://example.com/?test",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: "http://example.com/?test",
|
||||
origin: "http://example.com",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "example.com",
|
||||
hostname: "example.com",
|
||||
port: "",
|
||||
pathname: "/",
|
||||
search: "?test",
|
||||
hash: "",
|
||||
},
|
||||
{ url: "http://example.com/carrot#question%3f", base: undefined, error: false, hash: "#question%3f" },
|
||||
{
|
||||
url: "https://example.com:4443?",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: "https:",
|
||||
port: "4443",
|
||||
pathname: "/",
|
||||
hash: "",
|
||||
search: "",
|
||||
},
|
||||
{
|
||||
url: "http://www.abc.com/apath/afile.txt#ahash?asearch",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: "http://www.abc.com/apath/afile.txt#ahash?asearch",
|
||||
protocol: "http:",
|
||||
pathname: "/apath/afile.txt",
|
||||
hash: "#ahash?asearch",
|
||||
search: "",
|
||||
},
|
||||
{
|
||||
url: "http://www.abc.com/apath/afile.txt?asearch#ahash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: "http://www.abc.com/apath/afile.txt?asearch#ahash",
|
||||
protocol: "http:",
|
||||
pathname: "/apath/afile.txt",
|
||||
hash: "#ahash",
|
||||
search: "?asearch",
|
||||
},
|
||||
{
|
||||
url: "http://abc.com/apath/afile.txt?#ahash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
pathname: "/apath/afile.txt",
|
||||
hash: "#ahash",
|
||||
search: "",
|
||||
},
|
||||
{
|
||||
url: "http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: "http:",
|
||||
username: "auser",
|
||||
password: "apassword",
|
||||
host: "www.abc.com:90",
|
||||
hostname: "www.abc.com",
|
||||
port: "90",
|
||||
pathname: "/apath/afile.txt",
|
||||
hash: "#ahash",
|
||||
search: "?asearch",
|
||||
origin: "http://www.abc.com:90",
|
||||
},
|
||||
|
||||
var tests = [
|
||||
{ url: 'http://www.abc.com',
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com/',
|
||||
origin: 'http://www.abc.com',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'www.abc.com',
|
||||
hostname: 'www.abc.com',
|
||||
port: '',
|
||||
pathname: '/',
|
||||
search: '',
|
||||
hash: ''
|
||||
},
|
||||
{ url: 'ftp://auser:apw@www.abc.com',
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'ftp://auser:apw@www.abc.com/',
|
||||
origin: 'ftp://www.abc.com',
|
||||
protocol: 'ftp:',
|
||||
username: 'auser',
|
||||
password: 'apw',
|
||||
host: 'www.abc.com',
|
||||
hostname: 'www.abc.com',
|
||||
port: '',
|
||||
pathname: '/',
|
||||
search: '',
|
||||
hash: ''
|
||||
},
|
||||
{ url: 'http://www.abc.com:90/apath/',
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com:90/apath/',
|
||||
origin: 'http://www.abc.com:90',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'www.abc.com:90',
|
||||
hostname: 'www.abc.com',
|
||||
port: '90',
|
||||
pathname: '/apath/',
|
||||
search: '',
|
||||
hash: ''
|
||||
},
|
||||
{ url: 'http://www.abc.com/apath/afile.txt#ahash',
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com/apath/afile.txt#ahash',
|
||||
origin: 'http://www.abc.com',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'www.abc.com',
|
||||
hostname: 'www.abc.com',
|
||||
port: '',
|
||||
pathname: '/apath/afile.txt',
|
||||
search: '',
|
||||
hash: '#ahash'
|
||||
},
|
||||
{ url: 'http://example.com/?test#hash',
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://example.com/?test#hash',
|
||||
origin: 'http://example.com',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'example.com',
|
||||
hostname: 'example.com',
|
||||
port: '',
|
||||
pathname: '/',
|
||||
search: '?test',
|
||||
hash: '#hash'
|
||||
},
|
||||
{ url: 'http://example.com/?test',
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://example.com/?test',
|
||||
origin: 'http://example.com',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'example.com',
|
||||
hostname: 'example.com',
|
||||
port: '',
|
||||
pathname: '/',
|
||||
search: '?test',
|
||||
hash: ''
|
||||
},
|
||||
{ url: 'http://example.com/carrot#question%3f',
|
||||
base: undefined,
|
||||
error: false,
|
||||
hash: '#question%3f'
|
||||
},
|
||||
{ url: 'https://example.com:4443?',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'https:',
|
||||
port: '4443',
|
||||
pathname: '/',
|
||||
hash: '',
|
||||
search: ''
|
||||
},
|
||||
{ url: 'http://www.abc.com/apath/afile.txt#ahash?asearch',
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com/apath/afile.txt#ahash?asearch',
|
||||
protocol: 'http:',
|
||||
pathname: '/apath/afile.txt',
|
||||
hash: '#ahash?asearch',
|
||||
search: ''
|
||||
},
|
||||
{ url: 'http://www.abc.com/apath/afile.txt?asearch#ahash',
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com/apath/afile.txt?asearch#ahash',
|
||||
protocol: 'http:',
|
||||
pathname: '/apath/afile.txt',
|
||||
hash: '#ahash',
|
||||
search: '?asearch'
|
||||
},
|
||||
{ url: 'http://abc.com/apath/afile.txt?#ahash',
|
||||
base: undefined,
|
||||
error: false,
|
||||
pathname: '/apath/afile.txt',
|
||||
hash: '#ahash',
|
||||
search: ''
|
||||
},
|
||||
{ url: 'http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'http:',
|
||||
username: 'auser',
|
||||
password: 'apassword',
|
||||
host: 'www.abc.com:90',
|
||||
hostname: 'www.abc.com',
|
||||
port: '90',
|
||||
pathname: '/apath/afile.txt',
|
||||
hash: '#ahash',
|
||||
search: '?asearch',
|
||||
origin: 'http://www.abc.com:90'
|
||||
},
|
||||
{ url: "/foo#bar", base: "www.test.org", error: true },
|
||||
{ url: "/foo#bar", base: null, error: true },
|
||||
{ url: "/foo#bar", base: 42, error: true },
|
||||
{ url: "ftp://ftp.something.net", base: undefined, error: false, protocol: "ftp:" },
|
||||
{ url: "file:///tmp/file", base: undefined, error: false, protocol: "file:" },
|
||||
{ url: "gopher://gopher.something.net", base: undefined, error: false, protocol: "gopher:" },
|
||||
{ url: "ws://ws.something.net", base: undefined, error: false, protocol: "ws:" },
|
||||
{ url: "wss://ws.something.net", base: undefined, error: false, protocol: "wss:" },
|
||||
{ url: "foo://foo.something.net", base: undefined, error: false, protocol: "foo:" },
|
||||
|
||||
{ url: '/foo#bar',
|
||||
base: 'www.test.org',
|
||||
error: true,
|
||||
},
|
||||
{ url: '/foo#bar',
|
||||
base: null,
|
||||
error: true,
|
||||
},
|
||||
{ url: '/foo#bar',
|
||||
base: 42,
|
||||
error: true,
|
||||
},
|
||||
{ url: 'ftp://ftp.something.net',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'ftp:',
|
||||
},
|
||||
{ url: 'file:///tmp/file',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'file:',
|
||||
},
|
||||
{ url: 'gopher://gopher.something.net',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'gopher:',
|
||||
},
|
||||
{ url: 'ws://ws.something.net',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'ws:',
|
||||
},
|
||||
{ url: 'wss://ws.something.net',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'wss:',
|
||||
},
|
||||
{ url: 'foo://foo.something.net',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'foo:',
|
||||
},
|
||||
{
|
||||
url: "about:blank",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: "about:",
|
||||
pathname: "blank",
|
||||
skip_setters: false,
|
||||
},
|
||||
|
||||
{ url: 'about:blank',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'about:',
|
||||
pathname: 'blank',
|
||||
skip_setters: false,
|
||||
},
|
||||
{
|
||||
url: "foo:bar?what#yeah",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: "foo:",
|
||||
pathname: "bar",
|
||||
search: "?what",
|
||||
hash: "#yeah",
|
||||
skip_setters: false,
|
||||
},
|
||||
];
|
||||
|
||||
{ url: 'foo:bar?what#yeah',
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'foo:',
|
||||
pathname: 'bar',
|
||||
search: '?what',
|
||||
hash: '#yeah',
|
||||
skip_setters: false,
|
||||
},
|
||||
];
|
||||
while (tests.length) {
|
||||
var test = tests.shift();
|
||||
|
||||
while(tests.length) {
|
||||
var test = tests.shift();
|
||||
var error = false;
|
||||
var url;
|
||||
try {
|
||||
if (test.base) {
|
||||
url = new URL(test.url, test.base);
|
||||
} else {
|
||||
url = new URL(test.url);
|
||||
}
|
||||
} catch (e) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
var error = false;
|
||||
var url;
|
||||
try {
|
||||
if (test.base) {
|
||||
url = new URL(test.url, test.base);
|
||||
} else {
|
||||
url = new URL(test.url);
|
||||
}
|
||||
} catch(e) {
|
||||
error = true;
|
||||
}
|
||||
is(test.error, error, "Error creating URL");
|
||||
if (test.error) {
|
||||
continue;
|
||||
}
|
||||
|
||||
is(test.error, error, "Error creating URL");
|
||||
if (test.error) {
|
||||
continue;
|
||||
}
|
||||
if ("href" in test) is(url.href, test.href, "href");
|
||||
if ("origin" in test) is(url.origin, test.origin, "origin");
|
||||
if ("protocol" in test) is(url.protocol, test.protocol, "protocol");
|
||||
if ("username" in test) is(url.username, test.username, "username");
|
||||
if ("password" in test) is(url.password, test.password, "password");
|
||||
if ("host" in test) is(url.host, test.host, "host");
|
||||
if ("hostname" in test) is(url.hostname, test.hostname, "hostname");
|
||||
if ("port" in test) is(url.port, test.port, "port");
|
||||
if ("pathname" in test) is(url.pathname, test.pathname, "pathname");
|
||||
if ("search" in test) is(url.search, test.search, "search");
|
||||
if ("hash" in test) is(url.hash, test.hash, "hash");
|
||||
|
||||
if ('href' in test) is(url.href, test.href, "href");
|
||||
if ('origin' in test) is(url.origin, test.origin, "origin");
|
||||
if ('protocol' in test) is(url.protocol, test.protocol, "protocol");
|
||||
if ('username' in test) is(url.username, test.username, "username");
|
||||
if ('password' in test) is(url.password, test.password, "password");
|
||||
if ('host' in test) is(url.host, test.host, "host");
|
||||
if ('hostname' in test) is(url.hostname, test.hostname, "hostname");
|
||||
if ('port' in test) is(url.port, test.port, "port");
|
||||
if ('pathname' in test) is(url.pathname, test.pathname, "pathname");
|
||||
if ('search' in test) is(url.search, test.search, "search");
|
||||
if ('hash' in test) is(url.hash, test.hash, "hash");
|
||||
if ("skip_setters" in test && test.skip_setters == false) {
|
||||
info("Skip setter methods for URL: " + test);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('skip_setters' in test && test.skip_setters == false) {
|
||||
info("Skip setter methods for URL: " + test);
|
||||
continue;
|
||||
}
|
||||
url = new URL("https://www.example.net/what#foo?bar");
|
||||
ok(url, "Url exists!");
|
||||
|
||||
url = new URL('https://www.example.net/what#foo?bar');
|
||||
ok(url, "Url exists!");
|
||||
if ("href" in test) url.href = test.href;
|
||||
if ("protocol" in test) url.protocol = test.protocol;
|
||||
if ("username" in test && test.username) url.username = test.username;
|
||||
if ("password" in test && test.password) url.password = test.password;
|
||||
if ("host" in test) url.host = test.host;
|
||||
if ("hostname" in test) url.hostname = test.hostname;
|
||||
if ("port" in test) url.port = test.port;
|
||||
if ("pathname" in test) url.pathname = test.pathname;
|
||||
if ("search" in test) url.search = test.search;
|
||||
if ("hash" in test) url.hash = test.hash;
|
||||
|
||||
if ('href' in test) url.href = test.href;
|
||||
if ('protocol' in test) url.protocol = test.protocol;
|
||||
if ('username' in test && test.username) url.username = test.username;
|
||||
if ('password' in test && test.password) url.password = test.password;
|
||||
if ('host' in test) url.host = test.host;
|
||||
if ('hostname' in test) url.hostname = test.hostname;
|
||||
if ('port' in test) url.port = test.port;
|
||||
if ('pathname' in test) url.pathname = test.pathname;
|
||||
if ('search' in test) url.search = test.search;
|
||||
if ('hash' in test) url.hash = test.hash;
|
||||
if ("href" in test) is(url.href, test.href, "href");
|
||||
if ("origin" in test) is(url.origin, test.origin, "origin");
|
||||
if ("protocol" in test) is(url.protocol, test.protocol, "protocol");
|
||||
if ("username" in test) is(url.username, test.username, "username");
|
||||
if ("password" in test) is(url.password, test.password, "password");
|
||||
if ("host" in test) is(url.host, test.host, "host");
|
||||
if ("hostname" in test) is(test.hostname, url.hostname, "hostname");
|
||||
if ("port" in test) is(test.port, url.port, "port");
|
||||
if ("pathname" in test) is(test.pathname, url.pathname, "pathname");
|
||||
if ("search" in test) is(test.search, url.search, "search");
|
||||
if ("hash" in test) is(test.hash, url.hash, "hash");
|
||||
|
||||
if ('href' in test) is(url.href, test.href, "href");
|
||||
if ('origin' in test) is(url.origin, test.origin, "origin");
|
||||
if ('protocol' in test) is(url.protocol, test.protocol, "protocol");
|
||||
if ('username' in test) is(url.username, test.username, "username");
|
||||
if ('password' in test) is(url.password, test.password, "password");
|
||||
if ('host' in test) is(url.host, test.host, "host");
|
||||
if ('hostname' in test) is(test.hostname, url.hostname, "hostname");
|
||||
if ('port' in test) is(test.port, url.port, "port");
|
||||
if ('pathname' in test) is(test.pathname, url.pathname, "pathname");
|
||||
if ('search' in test) is(test.search, url.search, "search");
|
||||
if ('hash' in test) is(test.hash, url.hash, "hash");
|
||||
if ("href" in test) is(test.href, url + "", "stringify works");
|
||||
}
|
||||
</script>
|
||||
|
||||
if ('href' in test) is (test.href, url + '', 'stringify works');
|
||||
}
|
||||
<script>
|
||||
/** Test for Bug 991471 **/
|
||||
var url = new URL("http://localhost/");
|
||||
url.hostname = "";
|
||||
url.username = "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt";
|
||||
url.hostname = "www.mozilla.org";
|
||||
url.username = "";
|
||||
url.hostname = "www.mozilla.org";
|
||||
is(url.href, "http://www.mozilla.org/", "No parsing error with empty host");
|
||||
</script>
|
||||
|
||||
</script>
|
||||
<script>
|
||||
/** Test for Bug 996055 **/
|
||||
var url = new URL("http://localhost/");
|
||||
url.hostname = "";
|
||||
is(url.href, "http://localhost/", "Empty hostname is ignored");
|
||||
</script>
|
||||
|
||||
<script>
|
||||
/** Test for Bug 991471 **/
|
||||
var url = new URL("http://localhost/");
|
||||
url.hostname = "";
|
||||
url.username = "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt";
|
||||
url.hostname = "www.mozilla.org";
|
||||
url.username = "";
|
||||
url.hostname = "www.mozilla.org";
|
||||
is(url.href, "http://www.mozilla.org/", "No parsing error with empty host");
|
||||
</script>
|
||||
<script>
|
||||
/** Test for Bug 960014 **/
|
||||
var url = new URL("http://localhost/");
|
||||
url.hostname = "[2001::1]";
|
||||
is(url.hostname, "[2001::1]", "IPv6 hostname");
|
||||
is(url.href, "http://[2001::1]/");
|
||||
|
||||
<script>
|
||||
/** Test for Bug 996055 **/
|
||||
var url = new URL("http://localhost/");
|
||||
url.hostname = "";
|
||||
is(url.href, "http://localhost/", "Empty hostname is ignored");
|
||||
</script>
|
||||
url.hostname = "[::192.9.5.5]";
|
||||
is(url.hostname, "[::192.9.5.5]", "IPv6 hostname");
|
||||
is(url.href, "http://[::192.9.5.5]/");
|
||||
|
||||
<script>
|
||||
/** Test for Bug 960014 **/
|
||||
var url = new URL("http://localhost/");
|
||||
url.hostname = "[2001::1]";
|
||||
is(url.hostname, "[2001::1]", "IPv6 hostname");
|
||||
is(url.href, "http://[2001::1]/");
|
||||
url = new URL("http://localhost/");
|
||||
url.hostname = "[::]";
|
||||
is(url.hostname, "[::]", "IPv6 hostname");
|
||||
|
||||
url.hostname = "[::192.9.5.5]";
|
||||
is(url.hostname, "[::192.9.5.5]", "IPv6 hostname");
|
||||
is(url.href, "http://[::192.9.5.5]/");
|
||||
url = new URL("http://localhost/");
|
||||
url.host = "[2001::1]:30";
|
||||
is(url.hostname, "[2001::1]", "IPv6 hostname");
|
||||
is(url.port, "30", "Port");
|
||||
is(url.host, "[2001::1]:30", "IPv6 host");
|
||||
|
||||
url = new URL("http://localhost/");
|
||||
url.hostname = "[::]";
|
||||
is(url.hostname, "[::]", "IPv6 hostname");
|
||||
url = new URL("http://localhost/");
|
||||
// This should silently fail since it's missing the brackets
|
||||
url.hostname = "2001::1";
|
||||
is(url.hostname, "localhost", "Setting bad hostname fails");
|
||||
</script>
|
||||
|
||||
url = new URL("http://localhost/");
|
||||
url.host = "[2001::1]:30";
|
||||
is(url.hostname, "[2001::1]", "IPv6 hostname");
|
||||
is(url.port, "30", "Port");
|
||||
is(url.host, "[2001::1]:30", "IPv6 host");
|
||||
<script>
|
||||
var blob = new Blob(["a"]);
|
||||
var url = URL.createObjectURL(blob);
|
||||
|
||||
url = new URL("http://localhost/");
|
||||
// This should silently fail since it's missing the brackets
|
||||
url.hostname = "2001::1";
|
||||
is(url.hostname, "localhost", "Setting bad hostname fails");
|
||||
</script>
|
||||
var u = new URL(url);
|
||||
ok(u.origin, "http://mochi.test:8888", "The URL generated from a blob URI has an origin");
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var blob = new Blob(['a']);
|
||||
var url = URL.createObjectURL(blob);
|
||||
<script>
|
||||
var blob = new Blob(["a"]);
|
||||
var url = URL.createObjectURL(blob);
|
||||
|
||||
var u = new URL(url);
|
||||
ok(u.origin, 'http://mochi.test:8888', "The URL generated from a blob URI has an origin");
|
||||
</script>
|
||||
var a = document.createElement("A");
|
||||
a.href = url;
|
||||
ok(a.origin, "http://mochi.test:8888", "The 'a' element has the correct origin");
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var blob = new Blob(['a']);
|
||||
var url = URL.createObjectURL(blob);
|
||||
<script>
|
||||
var blob = new Blob(["a"]);
|
||||
var url = URL.createObjectURL(blob);
|
||||
URL.revokeObjectURL(url);
|
||||
URL.revokeObjectURL(url);
|
||||
ok(true, "Calling revokeObjectURL twice should be ok");
|
||||
</script>
|
||||
|
||||
var a = document.createElement('A');
|
||||
a.href = url;
|
||||
ok(a.origin, 'http://mochi.test:8888', "The 'a' element has the correct origin");
|
||||
</script>
|
||||
<script>
|
||||
URL.revokeObjectURL("blob:something");
|
||||
ok(true, "This should not throw.");
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var blob = new Blob(['a']);
|
||||
var url = URL.createObjectURL(blob);
|
||||
URL.revokeObjectURL(url);
|
||||
URL.revokeObjectURL(url);
|
||||
ok(true, "Calling revokeObjectURL twice should be ok");
|
||||
</script>
|
||||
<script>
|
||||
var base = new URL("http:\\\\test.com\\path/to\\file?query\\backslash#hash\\");
|
||||
is(base.href, "http://test.com/path/to/file?query\\backslash#hash\\");
|
||||
|
||||
<script>
|
||||
URL.revokeObjectURL('blob:something');
|
||||
ok(true, "This should not throw.");
|
||||
</script>
|
||||
var url = new URL("..\\", base);
|
||||
is(url.href, "http://test.com/path/");
|
||||
|
||||
<script>
|
||||
var base = new URL("http:\\\\test.com\\path/to\\file?query\\backslash#hash\\");
|
||||
is(base.href, "http://test.com/path/to/file?query\\backslash#hash\\");
|
||||
url = new URL("\\test", base);
|
||||
is(url.href, "http://test.com/test");
|
||||
|
||||
var url = new URL("..\\", base);
|
||||
is(url.href, "http://test.com/path/");
|
||||
url = new URL("\\test\\", base);
|
||||
is(url.href, "http://test.com/test/");
|
||||
|
||||
url = new URL("\\test", base);
|
||||
is(url.href, "http://test.com/test");
|
||||
url = new URL("http://example.org/test", base);
|
||||
is(url.href, "http://example.org/test");
|
||||
|
||||
url = new URL("\\test\\", base);
|
||||
is(url.href, "http://test.com/test/");
|
||||
url = new URL("ftp://tmp/test", base);
|
||||
is(url.href, "ftp://tmp/test");
|
||||
|
||||
url = new URL("http://example.org/test", base);
|
||||
is(url.href, "http://example.org/test");
|
||||
url = new URL("ftp:\\\\tmp\\test", base);
|
||||
is(url.href, "ftp://tmp/test");
|
||||
|
||||
url = new URL("ftp://tmp/test", base);
|
||||
is(url.href, "ftp://tmp/test");
|
||||
url = new URL("scheme://tmp\\test", base);
|
||||
is(url.href, "scheme://tmp\\test");
|
||||
</script>
|
||||
|
||||
url = new URL("ftp:\\\\tmp\\test", base);
|
||||
is(url.href, "ftp://tmp/test");
|
||||
<script>
|
||||
/** Test for Bug 1275746 **/
|
||||
SimpleTest.doesThrow(() => {
|
||||
var url = new URL("http:");
|
||||
}, "http: is not a valid URL");
|
||||
SimpleTest.doesThrow(() => {
|
||||
var url = new URL("http:///");
|
||||
}, "http: is not a valid URL");
|
||||
|
||||
url = new URL("scheme://tmp\\test", base);
|
||||
is(url.href, "scheme://tmp\\test");
|
||||
</script>
|
||||
var url = new URL("file:");
|
||||
is(url.href, "file:///", "Parsing file: should work.");
|
||||
|
||||
<script>
|
||||
/** Test for Bug 1275746 **/
|
||||
SimpleTest.doesThrow(() => { var url = new URL("http:"); }, "http: is not a valid URL");
|
||||
SimpleTest.doesThrow(() => { var url = new URL("http:///"); }, "http: is not a valid URL");
|
||||
url = new URL("file:///");
|
||||
is(url.href, "file:///", "Parsing file:/// should work.");
|
||||
</script>
|
||||
|
||||
var url = new URL("file:");
|
||||
is(url.href, "file:///", "Parsing file: should work.");
|
||||
<script>
|
||||
var url = new URL("scheme:path/to/file?query#hash");
|
||||
is(url.href, "scheme:path/to/file?query#hash");
|
||||
is(url.pathname, "path/to/file");
|
||||
is(url.search, "?query");
|
||||
is(url.hash, "#hash");
|
||||
|
||||
url = new URL("file:///");
|
||||
is(url.href, "file:///", "Parsing file:/// should work.");
|
||||
</script>
|
||||
// pathname cannot be overwritten.
|
||||
url.pathname = "new/path?newquery#newhash";
|
||||
is(url.href, "scheme:path/to/file?query#hash");
|
||||
|
||||
<script>
|
||||
var url = new URL("scheme:path/to/file?query#hash");
|
||||
is(url.href, "scheme:path/to/file?query#hash");
|
||||
is(url.pathname, "path/to/file");
|
||||
is(url.search, "?query");
|
||||
is(url.hash, "#hash");
|
||||
// don't escape '#' until we implement a spec-compliant parser.
|
||||
url.search = "?newquery#newhash";
|
||||
is(url.href, "scheme:path/to/file?newquery#newhash#hash");
|
||||
|
||||
// pathname cannot be overwritten.
|
||||
url.pathname = "new/path?newquery#newhash";
|
||||
is(url.href, "scheme:path/to/file?query#hash");
|
||||
// nulls get encoded, whitespace gets stripped
|
||||
url = new URL("scheme:pa\0\nth/to/fi\0\nle?qu\0\nery#ha\0\nsh");
|
||||
is(url.href, "scheme:pa%00th/to/fi%00le?qu%00ery#ha%00sh");
|
||||
|
||||
// don't escape '#' until we implement a spec-compliant parser.
|
||||
url.search = "?newquery#newhash";
|
||||
is(url.href, "scheme:path/to/file?newquery#newhash#hash");
|
||||
url.search = "new\0\nquery";
|
||||
is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#ha%00sh");
|
||||
url.hash = "new\0\nhash";
|
||||
is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#new%00%0Ahash");
|
||||
|
||||
// nulls get encoded, whitespace gets stripped
|
||||
url = new URL("scheme:pa\0\nth/to/fi\0\nle?qu\0\nery#ha\0\nsh");
|
||||
is(url.href, "scheme:pa%00th/to/fi%00le?qu%00ery#ha%00sh");
|
||||
url = new URL("scheme:path#hash");
|
||||
is(url.href, "scheme:path#hash");
|
||||
url.search = "query";
|
||||
is(url.href, "scheme:path?query#hash");
|
||||
url.hash = "";
|
||||
is(url.href, "scheme:path?query");
|
||||
url.hash = "newhash";
|
||||
is(url.href, "scheme:path?query#newhash");
|
||||
url.search = "";
|
||||
is(url.href, "scheme:path#newhash");
|
||||
|
||||
url.search = "new\0\nquery";
|
||||
is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#ha%00sh");
|
||||
url.hash = "new\0\nhash";
|
||||
is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#new%00%0Ahash");
|
||||
// we don't implement a spec-compliant parser yet.
|
||||
// make sure we are bug compatible with existing implementations.
|
||||
url = new URL('data:text/html,<a href="http://example.org/?q">Link</a>');
|
||||
is(url.href, 'data:text/html,<a%20href="http://example.org/?q">Link</a>');
|
||||
</script>
|
||||
|
||||
url = new URL("scheme:path#hash");
|
||||
is(url.href, "scheme:path#hash");
|
||||
url.search = "query";
|
||||
is(url.href, "scheme:path?query#hash");
|
||||
url.hash = "";
|
||||
is(url.href, "scheme:path?query");
|
||||
url.hash = "newhash";
|
||||
is(url.href, "scheme:path?query#newhash");
|
||||
url.search = "";
|
||||
is(url.href, "scheme:path#newhash");
|
||||
<script>
|
||||
is(
|
||||
new URL("/static/client/runtime.js", "x:/").href,
|
||||
"x:/static/client/runtime.js",
|
||||
"URL constructor accepts root-relative input with x:/ base",
|
||||
);
|
||||
ok("canParse" in URL, "URL.canParse exists");
|
||||
ok(
|
||||
URL.canParse("/static/client/runtime.js", "x:/"),
|
||||
"URL.canParse accepts root-relative input with x:/ base",
|
||||
);
|
||||
ok(
|
||||
URL.canParse("/static/client/runtime.js", document.baseURI),
|
||||
"URL.canParse accepts root-relative input with document base",
|
||||
);
|
||||
ok(!URL.canParse("/static/client/runtime.js"), "URL.canParse rejects root-relative input without base");
|
||||
ok(
|
||||
!URL.canParse("/static/client/runtime.js", "mailto:test@example.com"),
|
||||
"URL.canParse rejects root-relative input against opaque mailto: base",
|
||||
);
|
||||
SimpleTest.doesThrow(() => {
|
||||
new URL("/static/client/runtime.js", "mailto:test@example.com");
|
||||
}, "constructor rejects root-relative input against opaque mailto: base");
|
||||
</script>
|
||||
|
||||
// we don't implement a spec-compliant parser yet.
|
||||
// make sure we are bug compatible with existing implementations.
|
||||
url = new URL("data:text/html,<a href=\"http://example.org/?q\">Link</a>");
|
||||
is(url.href, "data:text/html,<a%20href=\"http://example.org/?q\">Link</a>");
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var u = new URL('http://www.example.org');
|
||||
ok(u.toJSON(), 'http://www.example.org', "URL.toJSON()");
|
||||
is(JSON.stringify(u), "\"http://www.example.org/\"", "JSON.stringify(u) works");
|
||||
</script>
|
||||
</body>
|
||||
<script>
|
||||
var u = new URL("http://www.example.org");
|
||||
ok(u.toJSON(), "http://www.example.org", "URL.toJSON()");
|
||||
is(JSON.stringify(u), '"http://www.example.org/"', "JSON.stringify(u) works");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+220
-176
@@ -1,212 +1,224 @@
|
||||
function ok(a, msg) {
|
||||
dump("OK: " + !!a + " => " + a + " " + msg + "\n");
|
||||
postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
|
||||
postMessage({ type: "status", status: !!a, msg: a + ": " + msg });
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
dump("IS: " + (a===b) + " => " + a + " | " + b + " " + msg + "\n");
|
||||
postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
|
||||
dump("IS: " + (a === b) + " => " + a + " | " + b + " " + msg + "\n");
|
||||
postMessage({
|
||||
type: "status",
|
||||
status: a === b,
|
||||
msg: a + " === " + b + ": " + msg,
|
||||
});
|
||||
}
|
||||
|
||||
onmessage = function() {
|
||||
onmessage = function () {
|
||||
status = false;
|
||||
try {
|
||||
if ((URL instanceof Object)) {
|
||||
if (URL instanceof Object) {
|
||||
status = true;
|
||||
}
|
||||
} catch(e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
var tests = [
|
||||
{ url: 'http://www.abc.com',
|
||||
{
|
||||
url: "http://www.abc.com",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com/',
|
||||
origin: 'http://www.abc.com',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'www.abc.com',
|
||||
hostname: 'www.abc.com',
|
||||
port: '',
|
||||
pathname: '/',
|
||||
search: '',
|
||||
hash: ''
|
||||
href: "http://www.abc.com/",
|
||||
origin: "http://www.abc.com",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "www.abc.com",
|
||||
hostname: "www.abc.com",
|
||||
port: "",
|
||||
pathname: "/",
|
||||
search: "",
|
||||
hash: "",
|
||||
},
|
||||
{ url: 'ftp://auser:apw@www.abc.com',
|
||||
{
|
||||
url: "ftp://auser:apw@www.abc.com",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'ftp://auser:apw@www.abc.com/',
|
||||
origin: 'ftp://www.abc.com',
|
||||
protocol: 'ftp:',
|
||||
username: 'auser',
|
||||
password: 'apw',
|
||||
host: 'www.abc.com',
|
||||
hostname: 'www.abc.com',
|
||||
port: '',
|
||||
pathname: '/',
|
||||
search: '',
|
||||
hash: ''
|
||||
href: "ftp://auser:apw@www.abc.com/",
|
||||
origin: "ftp://www.abc.com",
|
||||
protocol: "ftp:",
|
||||
username: "auser",
|
||||
password: "apw",
|
||||
host: "www.abc.com",
|
||||
hostname: "www.abc.com",
|
||||
port: "",
|
||||
pathname: "/",
|
||||
search: "",
|
||||
hash: "",
|
||||
},
|
||||
{ url: 'http://www.abc.com:90/apath/',
|
||||
{
|
||||
url: "http://www.abc.com:90/apath/",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com:90/apath/',
|
||||
origin: 'http://www.abc.com:90',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'www.abc.com:90',
|
||||
hostname: 'www.abc.com',
|
||||
port: '90',
|
||||
pathname: '/apath/',
|
||||
search: '',
|
||||
hash: ''
|
||||
href: "http://www.abc.com:90/apath/",
|
||||
origin: "http://www.abc.com:90",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "www.abc.com:90",
|
||||
hostname: "www.abc.com",
|
||||
port: "90",
|
||||
pathname: "/apath/",
|
||||
search: "",
|
||||
hash: "",
|
||||
},
|
||||
{ url: 'http://www.abc.com/apath/afile.txt#ahash',
|
||||
{
|
||||
url: "http://www.abc.com/apath/afile.txt#ahash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com/apath/afile.txt#ahash',
|
||||
origin: 'http://www.abc.com',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'www.abc.com',
|
||||
hostname: 'www.abc.com',
|
||||
port: '',
|
||||
pathname: '/apath/afile.txt',
|
||||
search: '',
|
||||
hash: '#ahash'
|
||||
href: "http://www.abc.com/apath/afile.txt#ahash",
|
||||
origin: "http://www.abc.com",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "www.abc.com",
|
||||
hostname: "www.abc.com",
|
||||
port: "",
|
||||
pathname: "/apath/afile.txt",
|
||||
search: "",
|
||||
hash: "#ahash",
|
||||
},
|
||||
{ url: 'http://example.com/?test#hash',
|
||||
{
|
||||
url: "http://example.com/?test#hash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://example.com/?test#hash',
|
||||
origin: 'http://example.com',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'example.com',
|
||||
hostname: 'example.com',
|
||||
port: '',
|
||||
pathname: '/',
|
||||
search: '?test',
|
||||
hash: '#hash'
|
||||
href: "http://example.com/?test#hash",
|
||||
origin: "http://example.com",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "example.com",
|
||||
hostname: "example.com",
|
||||
port: "",
|
||||
pathname: "/",
|
||||
search: "?test",
|
||||
hash: "#hash",
|
||||
},
|
||||
{ url: 'http://example.com/?test',
|
||||
{
|
||||
url: "http://example.com/?test",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://example.com/?test',
|
||||
origin: 'http://example.com',
|
||||
protocol: 'http:',
|
||||
username: '',
|
||||
password: '',
|
||||
host: 'example.com',
|
||||
hostname: 'example.com',
|
||||
port: '',
|
||||
pathname: '/',
|
||||
search: '?test',
|
||||
hash: ''
|
||||
href: "http://example.com/?test",
|
||||
origin: "http://example.com",
|
||||
protocol: "http:",
|
||||
username: "",
|
||||
password: "",
|
||||
host: "example.com",
|
||||
hostname: "example.com",
|
||||
port: "",
|
||||
pathname: "/",
|
||||
search: "?test",
|
||||
hash: "",
|
||||
},
|
||||
{ url: 'http://example.com/carrot#question%3f',
|
||||
{
|
||||
url: "http://example.com/carrot#question%3f",
|
||||
base: undefined,
|
||||
error: false,
|
||||
hash: '#question%3f'
|
||||
hash: "#question%3f",
|
||||
},
|
||||
{ url: 'https://example.com:4443?',
|
||||
{
|
||||
url: "https://example.com:4443?",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'https:',
|
||||
port: '4443',
|
||||
pathname: '/',
|
||||
hash: '',
|
||||
search: ''
|
||||
protocol: "https:",
|
||||
port: "4443",
|
||||
pathname: "/",
|
||||
hash: "",
|
||||
search: "",
|
||||
},
|
||||
{ url: 'http://www.abc.com/apath/afile.txt#ahash?asearch',
|
||||
{
|
||||
url: "http://www.abc.com/apath/afile.txt#ahash?asearch",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com/apath/afile.txt#ahash?asearch',
|
||||
protocol: 'http:',
|
||||
pathname: '/apath/afile.txt',
|
||||
hash: '#ahash?asearch',
|
||||
search: ''
|
||||
href: "http://www.abc.com/apath/afile.txt#ahash?asearch",
|
||||
protocol: "http:",
|
||||
pathname: "/apath/afile.txt",
|
||||
hash: "#ahash?asearch",
|
||||
search: "",
|
||||
},
|
||||
{ url: 'http://www.abc.com/apath/afile.txt?asearch#ahash',
|
||||
{
|
||||
url: "http://www.abc.com/apath/afile.txt?asearch#ahash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
href: 'http://www.abc.com/apath/afile.txt?asearch#ahash',
|
||||
protocol: 'http:',
|
||||
pathname: '/apath/afile.txt',
|
||||
hash: '#ahash',
|
||||
search: '?asearch'
|
||||
href: "http://www.abc.com/apath/afile.txt?asearch#ahash",
|
||||
protocol: "http:",
|
||||
pathname: "/apath/afile.txt",
|
||||
hash: "#ahash",
|
||||
search: "?asearch",
|
||||
},
|
||||
{ url: 'http://abc.com/apath/afile.txt?#ahash',
|
||||
{
|
||||
url: "http://abc.com/apath/afile.txt?#ahash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
pathname: '/apath/afile.txt',
|
||||
hash: '#ahash',
|
||||
search: ''
|
||||
pathname: "/apath/afile.txt",
|
||||
hash: "#ahash",
|
||||
search: "",
|
||||
},
|
||||
{ url: 'http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash',
|
||||
{
|
||||
url: "http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'http:',
|
||||
username: 'auser',
|
||||
password: 'apassword',
|
||||
host: 'www.abc.com:90',
|
||||
hostname: 'www.abc.com',
|
||||
port: '90',
|
||||
pathname: '/apath/afile.txt',
|
||||
hash: '#ahash',
|
||||
search: '?asearch',
|
||||
origin: 'http://www.abc.com:90'
|
||||
protocol: "http:",
|
||||
username: "auser",
|
||||
password: "apassword",
|
||||
host: "www.abc.com:90",
|
||||
hostname: "www.abc.com",
|
||||
port: "90",
|
||||
pathname: "/apath/afile.txt",
|
||||
hash: "#ahash",
|
||||
search: "?asearch",
|
||||
origin: "http://www.abc.com:90",
|
||||
},
|
||||
|
||||
{ url: '/foo#bar',
|
||||
base: 'www.test.org',
|
||||
error: true,
|
||||
},
|
||||
{ url: '/foo#bar',
|
||||
base: null,
|
||||
error: true,
|
||||
},
|
||||
{ url: '/foo#bar',
|
||||
base: 42,
|
||||
error: true,
|
||||
},
|
||||
{ url: 'ftp://ftp.something.net',
|
||||
{ url: "/foo#bar", base: "www.test.org", error: true },
|
||||
{ url: "/foo#bar", base: null, error: true },
|
||||
{ url: "/foo#bar", base: 42, error: true },
|
||||
{
|
||||
url: "ftp://ftp.something.net",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'ftp:',
|
||||
protocol: "ftp:",
|
||||
},
|
||||
{ url: 'file:///tmp/file',
|
||||
{
|
||||
url: "file:///tmp/file",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'file:',
|
||||
protocol: "file:",
|
||||
},
|
||||
{ url: 'gopher://gopher.something.net',
|
||||
{
|
||||
url: "gopher://gopher.something.net",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'gopher:',
|
||||
protocol: "gopher:",
|
||||
},
|
||||
{ url: 'ws://ws.something.net',
|
||||
{
|
||||
url: "ws://ws.something.net",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'ws:',
|
||||
protocol: "ws:",
|
||||
},
|
||||
{ url: 'wss://ws.something.net',
|
||||
{
|
||||
url: "wss://ws.something.net",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'wss:',
|
||||
protocol: "wss:",
|
||||
},
|
||||
{ url: 'foo://foo.something.net',
|
||||
{
|
||||
url: "foo://foo.something.net",
|
||||
base: undefined,
|
||||
error: false,
|
||||
protocol: 'foo:',
|
||||
protocol: "foo:",
|
||||
},
|
||||
];
|
||||
|
||||
while(tests.length) {
|
||||
while (tests.length) {
|
||||
var test = tests.shift();
|
||||
|
||||
var error = false;
|
||||
@@ -217,7 +229,7 @@ onmessage = function() {
|
||||
} else {
|
||||
url = new URL(test.url);
|
||||
}
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
@@ -226,47 +238,79 @@ onmessage = function() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('href' in test) is(url.href, test.href, "href");
|
||||
if ('origin' in test) is(url.origin, test.origin, "origin");
|
||||
if ('protocol' in test) is(url.protocol, test.protocol, "protocol");
|
||||
if ('username' in test) is(url.username, test.username, "username");
|
||||
if ('password' in test) is(url.password, test.password, "password");
|
||||
if ('host' in test) is(url.host, test.host, "host");
|
||||
if ('hostname' in test) is(url.hostname, test.hostname, "hostname");
|
||||
if ('port' in test) is(url.port, test.port, "port");
|
||||
if ('pathname' in test) is(url.pathname, test.pathname, "pathname");
|
||||
if ('search' in test) is(url.search, test.search, "search");
|
||||
if ('hash' in test) is(url.hash, test.hash, "hash");
|
||||
if ("href" in test) is(url.href, test.href, "href");
|
||||
if ("origin" in test) is(url.origin, test.origin, "origin");
|
||||
if ("protocol" in test) is(url.protocol, test.protocol, "protocol");
|
||||
if ("username" in test) is(url.username, test.username, "username");
|
||||
if ("password" in test) is(url.password, test.password, "password");
|
||||
if ("host" in test) is(url.host, test.host, "host");
|
||||
if ("hostname" in test) is(url.hostname, test.hostname, "hostname");
|
||||
if ("port" in test) is(url.port, test.port, "port");
|
||||
if ("pathname" in test) is(url.pathname, test.pathname, "pathname");
|
||||
if ("search" in test) is(url.search, test.search, "search");
|
||||
if ("hash" in test) is(url.hash, test.hash, "hash");
|
||||
|
||||
url = new URL('https://www.example.net/what#foo?bar');
|
||||
url = new URL("https://www.example.net/what#foo?bar");
|
||||
ok(url, "Url exists!");
|
||||
|
||||
if ('href' in test) url.href = test.href;
|
||||
if ('protocol' in test) url.protocol = test.protocol;
|
||||
if ('username' in test && test.username) url.username = test.username;
|
||||
if ('password' in test && test.password) url.password = test.password;
|
||||
if ('host' in test) url.host = test.host;
|
||||
if ('hostname' in test) url.hostname = test.hostname;
|
||||
if ('port' in test) url.port = test.port;
|
||||
if ('pathname' in test) url.pathname = test.pathname;
|
||||
if ('search' in test) url.search = test.search;
|
||||
if ('hash' in test) url.hash = test.hash;
|
||||
if ("href" in test) url.href = test.href;
|
||||
if ("protocol" in test) url.protocol = test.protocol;
|
||||
if ("username" in test && test.username) url.username = test.username;
|
||||
if ("password" in test && test.password) url.password = test.password;
|
||||
if ("host" in test) url.host = test.host;
|
||||
if ("hostname" in test) url.hostname = test.hostname;
|
||||
if ("port" in test) url.port = test.port;
|
||||
if ("pathname" in test) url.pathname = test.pathname;
|
||||
if ("search" in test) url.search = test.search;
|
||||
if ("hash" in test) url.hash = test.hash;
|
||||
|
||||
if ('href' in test) is(url.href, test.href, "href");
|
||||
if ('origin' in test) is(url.origin, test.origin, "origin");
|
||||
if ('protocol' in test) is(url.protocol, test.protocol, "protocol");
|
||||
if ('username' in test) is(url.username, test.username, "username");
|
||||
if ('password' in test) is(url.password, test.password, "password");
|
||||
if ('host' in test) is(url.host, test.host, "host");
|
||||
if ('hostname' in test) is(test.hostname, url.hostname, "hostname");
|
||||
if ('port' in test) is(test.port, url.port, "port");
|
||||
if ('pathname' in test) is(test.pathname, url.pathname, "pathname");
|
||||
if ('search' in test) is(test.search, url.search, "search");
|
||||
if ('hash' in test) is(test.hash, url.hash, "hash");
|
||||
if ("href" in test) is(url.href, test.href, "href");
|
||||
if ("origin" in test) is(url.origin, test.origin, "origin");
|
||||
if ("protocol" in test) is(url.protocol, test.protocol, "protocol");
|
||||
if ("username" in test) is(url.username, test.username, "username");
|
||||
if ("password" in test) is(url.password, test.password, "password");
|
||||
if ("host" in test) is(url.host, test.host, "host");
|
||||
if ("hostname" in test) is(test.hostname, url.hostname, "hostname");
|
||||
if ("port" in test) is(test.port, url.port, "port");
|
||||
if ("pathname" in test) is(test.pathname, url.pathname, "pathname");
|
||||
if ("search" in test) is(test.search, url.search, "search");
|
||||
if ("hash" in test) is(test.hash, url.hash, "hash");
|
||||
|
||||
if ('href' in test) is (test.href, url + '', 'stringify works');
|
||||
if ("href" in test) is(test.href, url + "", "stringify works");
|
||||
}
|
||||
|
||||
postMessage({type: 'finish' });
|
||||
}
|
||||
is(
|
||||
new URL("/static/client/runtime.js", "x:/").href,
|
||||
"x:/static/client/runtime.js",
|
||||
"URL constructor accepts root-relative input with x:/ base",
|
||||
);
|
||||
ok("canParse" in URL, "URL.canParse exists");
|
||||
ok(
|
||||
URL.canParse("/static/client/runtime.js", "x:/"),
|
||||
"URL.canParse accepts root-relative input with x:/ base",
|
||||
);
|
||||
ok(
|
||||
URL.canParse("/static/client/runtime.js", self.location.href),
|
||||
"URL.canParse accepts root-relative input with worker location base",
|
||||
);
|
||||
ok(
|
||||
!URL.canParse("/static/client/runtime.js"),
|
||||
"URL.canParse rejects root-relative input without base",
|
||||
);
|
||||
ok(
|
||||
!URL.canParse("/static/client/runtime.js", "mailto:test@example.com"),
|
||||
"URL.canParse rejects root-relative input against opaque mailto: base",
|
||||
);
|
||||
let mailtoRelativeFailed = false;
|
||||
try {
|
||||
new URL("/static/client/runtime.js", "mailto:test@example.com");
|
||||
} catch (e) {
|
||||
mailtoRelativeFailed = true;
|
||||
}
|
||||
ok(
|
||||
mailtoRelativeFailed,
|
||||
"constructor rejects root-relative input against opaque mailto: base",
|
||||
);
|
||||
|
||||
postMessage({ type: "finish" });
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -21,6 +21,12 @@ enum ChannelInterpretation {
|
||||
"discrete"
|
||||
};
|
||||
|
||||
dictionary AudioNodeOptions {
|
||||
unsigned long channelCount;
|
||||
ChannelCountMode channelCountMode;
|
||||
ChannelInterpretation channelInterpretation;
|
||||
};
|
||||
|
||||
[Pref="dom.webaudio.enabled"]
|
||||
interface AudioNode : EventTarget {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
};
|
||||
@@ -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 {
|
||||
|
||||
};
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
@@ -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 {
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ EditorBase::EditorBase()
|
||||
, mDispatchInputEvent(true)
|
||||
, mIsInEditAction(false)
|
||||
, mHidingCaret(false)
|
||||
, mIsHTMLEditorClass(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -220,7 +220,8 @@ bool MacroExpander::expandMacro(const Macro ¯o,
|
||||
assert(macro.type == Macro::kTypeFunc);
|
||||
std::vector<MacroArg> args;
|
||||
args.reserve(macro.parameters.size());
|
||||
if (!collectMacroArgs(macro, identifier, &args, &replacementLocation))
|
||||
if (replacements->size() == 0 ||
|
||||
!collectMacroArgs(macro, identifier, &args, &replacementLocation))
|
||||
return false;
|
||||
|
||||
replaceMacroParams(macro, args, replacements);
|
||||
|
||||
Loaded 100 of 192 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user