mirror of
https://github.com/Basilisk-Development-Team/UXP-mirror.git
synced 2026-11-04 17:00:06 -05:00
Compare commits
79
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 |
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;
|
||||
|
||||
+1132
-1048
File diff suppressed because it is too large.
Load diff
Loaded 100 of 162 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user