mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
cherry-picked mozilla upstream changes:
bug1464829, bug1452375, bug1458264, bug1464784, bug1392739, bug1453127, bug1456189, bug1462912
This commit is contained in:
+10
-10
@@ -1781,8 +1781,8 @@ nsINode::Before(const Sequence<OwningNodeOrString>& aNodes,
|
||||
nsCOMPtr<nsINode> viablePreviousSibling =
|
||||
FindViablePreviousSibling(*this, aNodes);
|
||||
|
||||
nsCOMPtr<nsINode> node =
|
||||
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
|
||||
nsCOMPtr<nsIDocument> doc = OwnerDoc();
|
||||
nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
@@ -1804,8 +1804,8 @@ nsINode::After(const Sequence<OwningNodeOrString>& aNodes,
|
||||
|
||||
nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
|
||||
|
||||
nsCOMPtr<nsINode> node =
|
||||
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
|
||||
nsCOMPtr<nsIDocument> doc = OwnerDoc();
|
||||
nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
@@ -1824,8 +1824,8 @@ nsINode::ReplaceWith(const Sequence<OwningNodeOrString>& aNodes,
|
||||
|
||||
nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
|
||||
|
||||
nsCOMPtr<nsINode> node =
|
||||
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
|
||||
nsCOMPtr<nsIDocument> doc = OwnerDoc();
|
||||
nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
@@ -1884,8 +1884,8 @@ void
|
||||
nsINode::Prepend(const Sequence<OwningNodeOrString>& aNodes,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsINode> node =
|
||||
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
|
||||
nsCOMPtr<nsIDocument> doc = OwnerDoc();
|
||||
nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
@@ -1898,8 +1898,8 @@ void
|
||||
nsINode::Append(const Sequence<OwningNodeOrString>& aNodes,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsINode> node =
|
||||
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
|
||||
nsCOMPtr<nsIDocument> doc = OwnerDoc();
|
||||
nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,21 @@ WebGLContext::BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fa
|
||||
UniquePtr<FakeBlackTexture>& fakeBlackTex = *slot;
|
||||
|
||||
if (!fakeBlackTex) {
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
|
||||
if (IsWebGL2()) {
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, 0);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, 0);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, 0);
|
||||
}
|
||||
|
||||
fakeBlackTex = FakeBlackTexture::Create(gl, target, fakeBlack);
|
||||
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mPixelStore_UnpackAlignment);
|
||||
if (IsWebGL2()) {
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, mPixelStore_UnpackSkipPixels);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, mPixelStore_UnpackSkipRows);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mPixelStore_UnpackSkipImages);
|
||||
}
|
||||
if (!fakeBlackTex) {
|
||||
return false;
|
||||
}
|
||||
@@ -1211,13 +1225,8 @@ WebGLContext::FakeBlackTexture::Create(gl::GLContext* gl, TexTarget target,
|
||||
gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
|
||||
gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
|
||||
|
||||
// We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
|
||||
// minimize the risk of running into a driver bug in texImage2D, as it is a bit
|
||||
// unusual maybe to create 1x1 textures, and the stack may not have the alignment that
|
||||
// TexImage2D expects.
|
||||
|
||||
const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE};
|
||||
UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation.
|
||||
UniqueBuffer zeros = moz_xcalloc(1, 4); // Infallible allocation.
|
||||
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
|
||||
@@ -1382,6 +1382,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mErrorSink->mError)
|
||||
for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mStream);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mPreCreatedTracks)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager)
|
||||
@@ -1591,6 +1592,17 @@ void HTMLMediaElement::ShutdownDecoder()
|
||||
RemoveMediaElementFromURITable();
|
||||
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
|
||||
mWaitingForKeyListener.DisconnectIfExists();
|
||||
for (OutputMediaStream& out : mOutputStreams) {
|
||||
if (!out.mCapturingDecoder) {
|
||||
continue;
|
||||
}
|
||||
if (!out.mStream) {
|
||||
continue;
|
||||
}
|
||||
out.mNextAvailableTrackID = std::max<TrackID>(
|
||||
mDecoder->NextAvailableTrackIDFor(out.mStream->GetInputStream()),
|
||||
out.mNextAvailableTrackID);
|
||||
}
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
@@ -3316,6 +3328,7 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
||||
if (mDecoder) {
|
||||
out->mCapturingDecoder = true;
|
||||
mDecoder->AddOutputStream(out->mStream->GetInputStream()->AsProcessedStream(),
|
||||
out->mNextAvailableTrackID,
|
||||
aFinishWhenEnded);
|
||||
} else if (mSrcStream) {
|
||||
out->mCapturingMediaStream = true;
|
||||
@@ -3329,23 +3342,26 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
||||
|
||||
if (mDecoder) {
|
||||
if (HasAudio()) {
|
||||
TrackID audioTrackId = mMediaInfo.mAudio.mTrackId;
|
||||
TrackID audioTrackId = out->mNextAvailableTrackID++;
|
||||
RefPtr<MediaStreamTrackSource> trackSource =
|
||||
getter->GetMediaStreamTrackSource(audioTrackId);
|
||||
RefPtr<MediaStreamTrack> track =
|
||||
out->mStream->CreateDOMTrack(audioTrackId, MediaSegment::AUDIO,
|
||||
out->mStream->CreateDOMTrack(audioTrackId,
|
||||
MediaSegment::AUDIO,
|
||||
trackSource);
|
||||
out->mPreCreatedTracks.AppendElement(track);
|
||||
out->mStream->AddTrackInternal(track);
|
||||
LOG(LogLevel::Debug,
|
||||
("Created audio track %d for captured decoder", audioTrackId));
|
||||
}
|
||||
if (IsVideo() && HasVideo() && !out->mCapturingAudioOnly) {
|
||||
TrackID videoTrackId = mMediaInfo.mVideo.mTrackId;
|
||||
TrackID videoTrackId = out->mNextAvailableTrackID++;
|
||||
RefPtr<MediaStreamTrackSource> trackSource =
|
||||
getter->GetMediaStreamTrackSource(videoTrackId);
|
||||
RefPtr<MediaStreamTrack> track =
|
||||
out->mStream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
|
||||
trackSource);
|
||||
out->mPreCreatedTracks.AppendElement(track);
|
||||
out->mStream->AddTrackInternal(track);
|
||||
LOG(LogLevel::Debug,
|
||||
("Created video track %d for captured decoder", videoTrackId));
|
||||
@@ -3434,6 +3450,25 @@ NS_IMETHODIMP HTMLMediaElement::GetMozAudioCaptured(bool* aCaptured)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::EndPreCreatedCapturedDecoderTracks()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (OutputMediaStream& ms : mOutputStreams) {
|
||||
if (!ms.mCapturingDecoder) {
|
||||
continue;
|
||||
}
|
||||
for (RefPtr<MediaStreamTrack>& t : ms.mPreCreatedTracks) {
|
||||
if (t->Ended()) {
|
||||
continue;
|
||||
}
|
||||
NS_DispatchToMainThread(NewRunnableMethod(
|
||||
t, &MediaStreamTrack::OverrideEnded));
|
||||
}
|
||||
ms.mPreCreatedTracks.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
class MediaElementSetForURI : public nsURIHashKey {
|
||||
public:
|
||||
explicit MediaElementSetForURI(const nsIURI* aKey) : nsURIHashKey(aKey) {}
|
||||
@@ -4027,11 +4062,12 @@ HTMLMediaElement::WakeLockRelease()
|
||||
}
|
||||
|
||||
HTMLMediaElement::OutputMediaStream::OutputMediaStream()
|
||||
: mFinishWhenEnded(false)
|
||||
: mNextAvailableTrackID(1)
|
||||
, mFinishWhenEnded(false)
|
||||
, mCapturingAudioOnly(false)
|
||||
, mCapturingDecoder(false)
|
||||
, mCapturingMediaStream(false)
|
||||
, mNextAvailableTrackID(1) {}
|
||||
{}
|
||||
|
||||
HTMLMediaElement::OutputMediaStream::~OutputMediaStream()
|
||||
{
|
||||
@@ -4658,6 +4694,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
|
||||
ms.mCapturingDecoder = true;
|
||||
aDecoder->AddOutputStream(ms.mStream->GetInputStream()->AsProcessedStream(),
|
||||
ms.mNextAvailableTrackID,
|
||||
ms.mFinishWhenEnded);
|
||||
}
|
||||
|
||||
|
||||
@@ -669,6 +669,11 @@ public:
|
||||
return mAudioCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures any MediaStreamTracks captured from a MediaDecoder are ended.
|
||||
*/
|
||||
void EndPreCreatedCapturedDecoderTracks();
|
||||
|
||||
void MozGetMetadata(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv);
|
||||
|
||||
@@ -810,13 +815,18 @@ protected:
|
||||
~OutputMediaStream();
|
||||
|
||||
RefPtr<DOMMediaStream> mStream;
|
||||
TrackID mNextAvailableTrackID;
|
||||
bool mFinishWhenEnded;
|
||||
bool mCapturingAudioOnly;
|
||||
bool mCapturingDecoder;
|
||||
bool mCapturingMediaStream;
|
||||
|
||||
// The following members are keeping state for a captured MediaDecoder.
|
||||
// Tracks that were created on main thread before MediaDecoder fed them
|
||||
// to the MediaStreamGraph.
|
||||
nsTArray<RefPtr<MediaStreamTrack>> mPreCreatedTracks;
|
||||
|
||||
// The following members are keeping state for a captured MediaStream.
|
||||
TrackID mNextAvailableTrackID;
|
||||
nsTArray<Pair<nsString, RefPtr<MediaInputPort>>> mTrackPorts;
|
||||
};
|
||||
|
||||
|
||||
@@ -335,11 +335,13 @@ MediaDecoder::SetVolume(double aVolume)
|
||||
|
||||
void
|
||||
MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
||||
mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded);
|
||||
mDecoderStateMachine->AddOutputStream(
|
||||
aStream, aNextAvailableTrackID, aFinishWhenEnded);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -350,6 +352,14 @@ MediaDecoder::RemoveOutputStream(MediaStream* aStream)
|
||||
mDecoderStateMachine->RemoveOutputStream(aStream);
|
||||
}
|
||||
|
||||
TrackID
|
||||
MediaDecoder::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
||||
return mDecoderStateMachine->NextAvailableTrackIDFor(aOutputStream);
|
||||
}
|
||||
|
||||
double
|
||||
MediaDecoder::GetDuration()
|
||||
{
|
||||
@@ -1743,6 +1753,8 @@ MediaDecoder::RemoveMediaTracks()
|
||||
videoList->RemoveTracks();
|
||||
}
|
||||
|
||||
element->EndPreCreatedCapturedDecoderTracks();
|
||||
|
||||
mMediaTracksConstructed = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -212,9 +212,13 @@ public:
|
||||
// Add an output stream. All decoder output will be sent to the stream.
|
||||
// The stream is initially blocked. The decoder is responsible for unblocking
|
||||
// it while it is playing back.
|
||||
virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
virtual void AddOutputStream(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded);
|
||||
// Remove an output stream added with AddOutputStream.
|
||||
virtual void RemoveOutputStream(MediaStream* aStream);
|
||||
// The next TrackID that can be used without risk of a collision.
|
||||
virtual TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
|
||||
|
||||
// Return the duration of the video in seconds.
|
||||
virtual double GetDuration();
|
||||
|
||||
@@ -3323,6 +3323,10 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
||||
RefPtr<ShutdownPromise>
|
||||
MediaDecoderStateMachine::BeginShutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mOutputStreamManager) {
|
||||
mOutputStreamManager->Clear();
|
||||
}
|
||||
return InvokeAsync(OwnerThread(), this, __func__,
|
||||
&MediaDecoderStateMachine::Shutdown);
|
||||
}
|
||||
@@ -3723,11 +3727,12 @@ MediaDecoderStateMachine::DumpDebugInfo()
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
DECODER_LOG("AddOutputStream aStream=%p!", aStream);
|
||||
mOutputStreamManager->Add(aStream, aFinishWhenEnded);
|
||||
mOutputStreamManager->Add(aStream, aNextAvailableTrackID, aFinishWhenEnded);
|
||||
nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
|
||||
this, &MediaDecoderStateMachine::SetAudioCaptured, true);
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
@@ -3742,9 +3747,17 @@ void MediaDecoderStateMachine::RemoveOutputStream(MediaStream* aStream)
|
||||
nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
|
||||
this, &MediaDecoderStateMachine::SetAudioCaptured, false);
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TrackID
|
||||
MediaDecoderStateMachine::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mOutputStreamManager->NextAvailableTrackIDFor(aOutputStream);
|
||||
}
|
||||
|
||||
size_t
|
||||
MediaDecoderStateMachine::SizeOfVideoQueue() const
|
||||
{
|
||||
|
||||
@@ -164,9 +164,12 @@ public:
|
||||
|
||||
void DumpDebugInfo();
|
||||
|
||||
void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
void AddOutputStream(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded);
|
||||
// Remove an output stream added with AddOutputStream.
|
||||
void RemoveOutputStream(MediaStream* aStream);
|
||||
TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
|
||||
|
||||
// Seeks to the decoder to aTarget asynchronously.
|
||||
RefPtr<MediaDecoder::SeekPromise> InvokeSeek(const SeekTarget& aTarget);
|
||||
|
||||
@@ -190,17 +190,22 @@ DecodedStreamData::DecodedStreamData(OutputStreamManager* aOutputStreamManager,
|
||||
, mAbstractMainThread(aMainThread)
|
||||
{
|
||||
mStream->AddListener(mListener);
|
||||
mOutputStreamManager->Connect(mStream);
|
||||
TrackID audioTrack = TRACK_NONE;
|
||||
TrackID videoTrack = TRACK_NONE;
|
||||
|
||||
// Initialize tracks.
|
||||
if (aInit.mInfo.HasAudio()) {
|
||||
mStream->AddAudioTrack(aInit.mInfo.mAudio.mTrackId,
|
||||
audioTrack = aInit.mInfo.mAudio.mTrackId;
|
||||
mStream->AddAudioTrack(audioTrack,
|
||||
aInit.mInfo.mAudio.mRate,
|
||||
0, new AudioSegment());
|
||||
}
|
||||
if (aInit.mInfo.HasVideo()) {
|
||||
mStream->AddTrack(aInit.mInfo.mVideo.mTrackId, 0, new VideoSegment());
|
||||
videoTrack = aInit.mInfo.mVideo.mTrackId;
|
||||
mStream->AddTrack(videoTrack, 0, new VideoSegment());
|
||||
}
|
||||
|
||||
mOutputStreamManager->Connect(mStream, audioTrack, videoTrack);
|
||||
}
|
||||
|
||||
DecodedStreamData::~DecodedStreamData()
|
||||
|
||||
@@ -13,29 +13,41 @@ OutputStreamData::~OutputStreamData()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Break the connection to the input stream if necessary.
|
||||
if (mPort) {
|
||||
mPort->Destroy();
|
||||
for (RefPtr<MediaInputPort>& port : mPorts) {
|
||||
port->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OutputStreamData::Init(OutputStreamManager* aOwner, ProcessedMediaStream* aStream)
|
||||
OutputStreamData::Init(OutputStreamManager* aOwner,
|
||||
ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID)
|
||||
{
|
||||
mOwner = aOwner;
|
||||
mStream = aStream;
|
||||
mNextAvailableTrackID = aNextAvailableTrackID;
|
||||
}
|
||||
|
||||
bool
|
||||
OutputStreamData::Connect(MediaStream* aStream)
|
||||
OutputStreamData::Connect(MediaStream* aStream,
|
||||
TrackID aInputAudioTrackID,
|
||||
TrackID aInputVideoTrackID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mPort, "Already connected?");
|
||||
MOZ_ASSERT(mPorts.IsEmpty(), "Already connected?");
|
||||
|
||||
if (mStream->IsDestroyed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mPort = mStream->AllocateInputPort(aStream);
|
||||
for (TrackID tid : {aInputAudioTrackID, aInputVideoTrackID}) {
|
||||
if (tid == TRACK_NONE) {
|
||||
continue;
|
||||
}
|
||||
MOZ_ASSERT(IsTrackIDExplicit(tid));
|
||||
mPorts.AppendElement(mStream->AllocateInputPort(
|
||||
aStream, tid, mNextAvailableTrackID++));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -51,11 +63,11 @@ OutputStreamData::Disconnect()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disconnect the existing port if necessary.
|
||||
if (mPort) {
|
||||
mPort->Destroy();
|
||||
mPort = nullptr;
|
||||
// Disconnect any existing port.
|
||||
for (RefPtr<MediaInputPort>& port : mPorts) {
|
||||
port->Destroy();
|
||||
}
|
||||
mPorts.Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -71,8 +83,16 @@ OutputStreamData::Graph() const
|
||||
return mStream->Graph();
|
||||
}
|
||||
|
||||
TrackID
|
||||
OutputStreamData::NextAvailableTrackID() const
|
||||
{
|
||||
return mNextAvailableTrackID;
|
||||
}
|
||||
|
||||
void
|
||||
OutputStreamManager::Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
||||
OutputStreamManager::Add(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// All streams must belong to the same graph.
|
||||
@@ -84,12 +104,12 @@ OutputStreamManager::Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
||||
}
|
||||
|
||||
OutputStreamData* p = mStreams.AppendElement();
|
||||
p->Init(this, aStream);
|
||||
p->Init(this, aStream, aNextAvailableTrackID);
|
||||
|
||||
// Connect to the input stream if we have one. Otherwise the output stream
|
||||
// will be connected in Connect().
|
||||
if (mInputStream) {
|
||||
p->Connect(mInputStream);
|
||||
p->Connect(mInputStream, mInputAudioTrackID, mInputVideoTrackID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,12 +126,35 @@ OutputStreamManager::Remove(MediaStream* aStream)
|
||||
}
|
||||
|
||||
void
|
||||
OutputStreamManager::Connect(MediaStream* aStream)
|
||||
OutputStreamManager::Clear()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mStreams.Clear();
|
||||
}
|
||||
|
||||
TrackID
|
||||
OutputStreamManager::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (const OutputStreamData& out : mStreams) {
|
||||
if (out.Equals(aOutputStream)) {
|
||||
return out.NextAvailableTrackID();
|
||||
}
|
||||
}
|
||||
return TRACK_INVALID;
|
||||
}
|
||||
|
||||
void
|
||||
OutputStreamManager::Connect(MediaStream* aStream,
|
||||
TrackID aAudioTrackID,
|
||||
TrackID aVideoTrackID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mInputStream = aStream;
|
||||
mInputAudioTrackID = aAudioTrackID;
|
||||
mInputVideoTrackID = aVideoTrackID;
|
||||
for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
|
||||
if (!mStreams[i].Connect(aStream)) {
|
||||
if (!mStreams[i].Connect(aStream, mInputAudioTrackID, mInputVideoTrackID)) {
|
||||
// Probably the DOMMediaStream was GCed. Clean up.
|
||||
mStreams.RemoveElementAt(i);
|
||||
}
|
||||
@@ -123,6 +166,8 @@ OutputStreamManager::Disconnect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mInputStream = nullptr;
|
||||
mInputAudioTrackID = TRACK_INVALID;
|
||||
mInputVideoTrackID = TRACK_INVALID;
|
||||
for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
|
||||
if (!mStreams[i].Disconnect()) {
|
||||
// Probably the DOMMediaStream was GCed. Clean up.
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "MediaSegment.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -21,11 +22,13 @@ class ProcessedMediaStream;
|
||||
class OutputStreamData {
|
||||
public:
|
||||
~OutputStreamData();
|
||||
void Init(OutputStreamManager* aOwner, ProcessedMediaStream* aStream);
|
||||
void Init(OutputStreamManager* aOwner,
|
||||
ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID);
|
||||
|
||||
// Connect mStream to the input stream.
|
||||
// Connect the given input stream's audio and video tracks to mStream.
|
||||
// Return false is mStream is already destroyed, otherwise true.
|
||||
bool Connect(MediaStream* aStream);
|
||||
bool Connect(MediaStream* aStream, TrackID aAudioTrackID, TrackID aVideoTrackID);
|
||||
// Disconnect mStream from its input stream.
|
||||
// Return false is mStream is already destroyed, otherwise true.
|
||||
bool Disconnect();
|
||||
@@ -34,12 +37,16 @@ public:
|
||||
bool Equals(MediaStream* aStream) const;
|
||||
// Return the graph mStream belongs to.
|
||||
MediaStreamGraph* Graph() const;
|
||||
// The next TrackID that will not cause a collision in mStream.
|
||||
TrackID NextAvailableTrackID() const;
|
||||
|
||||
private:
|
||||
OutputStreamManager* mOwner;
|
||||
RefPtr<ProcessedMediaStream> mStream;
|
||||
// mPort connects our mStream to an input stream.
|
||||
RefPtr<MediaInputPort> mPort;
|
||||
// mPort connects an input stream to our mStream.
|
||||
nsTArray<RefPtr<MediaInputPort>> mPorts;
|
||||
// For guaranteeing TrackID uniqueness in our mStream.
|
||||
TrackID mNextAvailableTrackID = TRACK_INVALID;
|
||||
};
|
||||
|
||||
class OutputStreamManager {
|
||||
@@ -47,18 +54,26 @@ class OutputStreamManager {
|
||||
|
||||
public:
|
||||
// Add the output stream to the collection.
|
||||
void Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
void Add(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded);
|
||||
// Remove the output stream from the collection.
|
||||
void Remove(MediaStream* aStream);
|
||||
// Clear all output streams from the collection.
|
||||
void Clear();
|
||||
// The next TrackID that will not cause a collision in aOutputStream.
|
||||
TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
|
||||
// Return true if the collection empty.
|
||||
bool IsEmpty() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mStreams.IsEmpty();
|
||||
}
|
||||
// Connect all output streams in the collection to the input stream.
|
||||
void Connect(MediaStream* aStream);
|
||||
// Disconnect all output streams from the input stream.
|
||||
// Connect the given input stream's tracks to all output streams.
|
||||
void Connect(MediaStream* aStream,
|
||||
TrackID aAudioTrackID,
|
||||
TrackID aVideoTrackID);
|
||||
// Disconnect the input stream to all output streams.
|
||||
void Disconnect();
|
||||
// Return the graph these streams belong to or null if empty.
|
||||
MediaStreamGraph* Graph() const
|
||||
@@ -72,6 +87,8 @@ private:
|
||||
// Keep the input stream so we can connect the output streams that
|
||||
// are added after Connect().
|
||||
RefPtr<MediaStream> mInputStream;
|
||||
TrackID mInputAudioTrackID = TRACK_INVALID;
|
||||
TrackID mInputVideoTrackID = TRACK_INVALID;
|
||||
nsTArray<OutputStreamData> mStreams;
|
||||
};
|
||||
|
||||
|
||||
+15
-1
@@ -37,6 +37,7 @@
|
||||
#include <tmmintrin.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include "ssse3-scaler.h"
|
||||
|
||||
typedef int32_t pixman_fixed_16_16_t;
|
||||
typedef pixman_fixed_16_16_t pixman_fixed_t;
|
||||
@@ -44,6 +45,8 @@ typedef pixman_fixed_16_16_t pixman_fixed_t;
|
||||
#define pixman_fixed_to_int(f) ((int) ((f) >> 16))
|
||||
#define pixman_int_to_fixed(i) ((pixman_fixed_t) ((i) << 16))
|
||||
#define pixman_double_to_fixed(d) ((pixman_fixed_t) ((d) * 65536.0))
|
||||
#define PIXMAN_FIXED_INT_MAX 32767
|
||||
#define PIXMAN_FIXED_INT_MIN -32768
|
||||
typedef struct pixman_vector pixman_vector_t;
|
||||
|
||||
typedef int pixman_bool_t;
|
||||
@@ -463,6 +466,12 @@ ssse3_bilinear_cover_iter_init (pixman_iter_t *iter)
|
||||
bilinear_info_t *info;
|
||||
pixman_vector_t v;
|
||||
|
||||
if (iter->x > PIXMAN_FIXED_INT_MAX ||
|
||||
iter->x < PIXMAN_FIXED_INT_MIN ||
|
||||
iter->y > PIXMAN_FIXED_INT_MAX ||
|
||||
iter->y < PIXMAN_FIXED_INT_MIN)
|
||||
goto fail;
|
||||
|
||||
/* Reference point is the center of the pixel */
|
||||
v.vector[0] = pixman_int_to_fixed (iter->x) + pixman_fixed_1 / 2;
|
||||
v.vector[1] = pixman_int_to_fixed (iter->y) + pixman_fixed_1 / 2;
|
||||
@@ -505,7 +514,7 @@ fail:
|
||||
/* scale the src from src_width/height to dest_width/height drawn
|
||||
* into the rectangle x,y width,height
|
||||
* src_stride and dst_stride are 4 byte units */
|
||||
void ssse3_scale_data(uint32_t *src, int src_width, int src_height, int src_stride,
|
||||
bool ssse3_scale_data(uint32_t *src, int src_width, int src_height, int src_stride,
|
||||
uint32_t *dest, int dest_width, int dest_height,
|
||||
int dest_stride,
|
||||
int x, int y,
|
||||
@@ -551,6 +560,10 @@ void ssse3_scale_data(uint32_t *src, int src_width, int src_height, int src_stri
|
||||
iter.data = NULL;
|
||||
|
||||
ssse3_bilinear_cover_iter_init(&iter);
|
||||
|
||||
if (!iter.fini)
|
||||
return false;
|
||||
|
||||
if (iter.data) {
|
||||
for (int iy = 0; iy < height; iy++) {
|
||||
ssse3_fetch_bilinear_cover(&iter, NULL);
|
||||
@@ -558,4 +571,5 @@ void ssse3_scale_data(uint32_t *src, int src_width, int src_height, int src_stri
|
||||
}
|
||||
ssse3_bilinear_cover_iter_fini(&iter);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
#ifndef MOZILLA_GFX_2D_SSSE3_SCALER_H_
|
||||
#define MOZILLA_GFX_2D_SSSE3_SCALER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void ssse3_scale_data(uint32_t *src, int src_width, int src_height,
|
||||
bool ssse3_scale_data(uint32_t *src, int src_width, int src_height,
|
||||
int src_stride,
|
||||
uint32_t *dest, int dest_width, int dest_height,
|
||||
int dest_rowstride,
|
||||
|
||||
@@ -556,15 +556,15 @@ AttemptVideoScale(TextureSourceBasic* aSource, const SourceSurface* aSourceMask,
|
||||
RefPtr<DataSourceSurface> srcSource = aSource->GetSurface(aDest)->GetDataSurface();
|
||||
DataSourceSurface::ScopedMap mapSrc(srcSource, DataSourceSurface::READ);
|
||||
|
||||
ssse3_scale_data((uint32_t*)mapSrc.GetData(), srcSource->GetSize().width, srcSource->GetSize().height,
|
||||
mapSrc.GetStride()/4,
|
||||
((uint32_t*)dstData) + fillRect.x + (dstStride / 4) * fillRect.y, dstRect.width, dstRect.height,
|
||||
dstStride / 4,
|
||||
offset.x, offset.y,
|
||||
fillRect.width, fillRect.height);
|
||||
bool success = ssse3_scale_data((uint32_t*)mapSrc.GetData(), srcSource->GetSize().width, srcSource->GetSize().height,
|
||||
mapSrc.GetStride()/4,
|
||||
((uint32_t*)dstData) + fillRect.x + (dstStride / 4) * fillRect.y, dstRect.width, dstRect.height,
|
||||
dstStride / 4,
|
||||
offset.x, offset.y,
|
||||
fillRect.width, fillRect.height);
|
||||
|
||||
aDest->ReleaseBits(dstData);
|
||||
return true;
|
||||
return success;
|
||||
} else
|
||||
#endif // MOZILLA_SSE_HAVE_CPUID_DETECTION
|
||||
return false;
|
||||
|
||||
@@ -322,9 +322,7 @@ class RInstructionResults
|
||||
|
||||
MOZ_MUST_USE bool init(JSContext* cx, uint32_t numResults);
|
||||
bool isInitialized() const;
|
||||
#ifdef DEBUG
|
||||
size_t length() const;
|
||||
#endif
|
||||
|
||||
JitFrameLayout* frame() const;
|
||||
|
||||
|
||||
@@ -1692,13 +1692,11 @@ RInstructionResults::isInitialized() const
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
size_t
|
||||
RInstructionResults::length() const
|
||||
{
|
||||
return results_->length();
|
||||
}
|
||||
#endif
|
||||
|
||||
JitFrameLayout*
|
||||
RInstructionResults::frame() const
|
||||
@@ -2154,7 +2152,7 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback)
|
||||
}
|
||||
|
||||
MOZ_ASSERT(results->isInitialized());
|
||||
MOZ_ASSERT(results->length() == recover_.numInstructions() - 1);
|
||||
MOZ_RELEASE_ASSERT(results->length() == recover_.numInstructions() - 1);
|
||||
instructionResults_ = results;
|
||||
return true;
|
||||
}
|
||||
|
||||
+94
-46
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include "mozilla/AllocPolicy.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Types.h"
|
||||
@@ -456,61 +457,108 @@ BufferList<AllocPolicy>::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess)
|
||||
MOZ_ASSERT(aSize % kSegmentAlignment == 0);
|
||||
MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0);
|
||||
|
||||
IterImpl iter = aIter;
|
||||
size_t size = aSize;
|
||||
size_t toCopy = std::min(size, aIter.RemainingInSegment());
|
||||
MOZ_ASSERT(toCopy % kSegmentAlignment == 0);
|
||||
|
||||
BufferList result(0, toCopy, mStandardCapacity);
|
||||
BufferList error(0, 0, mStandardCapacity);
|
||||
|
||||
// Copy the head
|
||||
if (!result.WriteBytes(aIter.mData, toCopy)) {
|
||||
auto failure = [this, aSuccess]() {
|
||||
*aSuccess = false;
|
||||
return error;
|
||||
}
|
||||
iter.Advance(*this, toCopy);
|
||||
size -= toCopy;
|
||||
return BufferList(0, 0, mStandardCapacity);
|
||||
};
|
||||
|
||||
// Move segments to result
|
||||
auto resultGuard = MakeScopeExit([&] {
|
||||
*aSuccess = false;
|
||||
result.mSegments.erase(result.mSegments.begin()+1, result.mSegments.end());
|
||||
});
|
||||
|
||||
size_t movedSize = 0;
|
||||
uintptr_t toRemoveStart = iter.mSegment;
|
||||
uintptr_t toRemoveEnd = iter.mSegment;
|
||||
while (!iter.Done() &&
|
||||
!iter.HasRoomFor(size)) {
|
||||
if (!result.mSegments.append(Segment(mSegments[iter.mSegment].mData,
|
||||
mSegments[iter.mSegment].mSize,
|
||||
mSegments[iter.mSegment].mCapacity))) {
|
||||
return error;
|
||||
// Number of segments we'll need to copy data from to satisfy the request.
|
||||
size_t segmentsNeeded = 0;
|
||||
// If this is None then the last segment is a full segment, otherwise we need
|
||||
// to copy this many bytes.
|
||||
Maybe<size_t> lastSegmentSize;
|
||||
{
|
||||
// Copy of the iterator to walk the BufferList and see how many segments we
|
||||
// need to copy.
|
||||
IterImpl iter = aIter;
|
||||
size_t remaining = aSize;
|
||||
while (!iter.Done() && remaining &&
|
||||
remaining >= iter.RemainingInSegment()) {
|
||||
remaining -= iter.RemainingInSegment();
|
||||
iter.Advance(*this, iter.RemainingInSegment());
|
||||
segmentsNeeded++;
|
||||
}
|
||||
movedSize += iter.RemainingInSegment();
|
||||
size -= iter.RemainingInSegment();
|
||||
toRemoveEnd++;
|
||||
iter.Advance(*this, iter.RemainingInSegment());
|
||||
}
|
||||
|
||||
if (size) {
|
||||
if (!iter.HasRoomFor(size) ||
|
||||
!result.WriteBytes(iter.Data(), size)) {
|
||||
return error;
|
||||
if (remaining) {
|
||||
if (iter.Done()) {
|
||||
// We reached the end of the BufferList and there wasn't enough data to
|
||||
// satisfy the request.
|
||||
return failure();
|
||||
}
|
||||
lastSegmentSize.emplace(remaining);
|
||||
// The last block also counts as a segment. This makes the conditionals
|
||||
// on segmentsNeeded work in the rest of the function.
|
||||
segmentsNeeded++;
|
||||
}
|
||||
iter.Advance(*this, size);
|
||||
}
|
||||
|
||||
mSegments.erase(mSegments.begin() + toRemoveStart, mSegments.begin() + toRemoveEnd);
|
||||
mSize -= movedSize;
|
||||
aIter.mSegment = iter.mSegment - (toRemoveEnd - toRemoveStart);
|
||||
aIter.mData = iter.mData;
|
||||
aIter.mDataEnd = iter.mDataEnd;
|
||||
MOZ_ASSERT(aIter.mDataEnd == mSegments[aIter.mSegment].End());
|
||||
BufferList result(0, 0, mStandardCapacity);
|
||||
if (!result.mSegments.reserve(segmentsNeeded + lastSegmentSize.isSome())) {
|
||||
return failure();
|
||||
}
|
||||
|
||||
// Copy the first segment, it's special because we can't just steal the
|
||||
// entire Segment struct from this->mSegments.
|
||||
size_t firstSegmentSize = std::min(aSize, aIter.RemainingInSegment());
|
||||
if (!result.WriteBytes(aIter.Data(), firstSegmentSize)) {
|
||||
return failure();
|
||||
}
|
||||
aIter.Advance(*this, firstSegmentSize);
|
||||
segmentsNeeded--;
|
||||
|
||||
// The entirety of the request wasn't in the first segment, now copy the
|
||||
// rest.
|
||||
if (segmentsNeeded) {
|
||||
char* finalSegment = nullptr;
|
||||
// Pre-allocate the final segment so that if this fails, we return before
|
||||
// we delete the elements from |this->mSegments|.
|
||||
if (lastSegmentSize.isSome()) {
|
||||
MOZ_RELEASE_ASSERT(mStandardCapacity >= *lastSegmentSize);
|
||||
finalSegment = this->template pod_malloc<char>(mStandardCapacity);
|
||||
if (!finalSegment) {
|
||||
return failure();
|
||||
}
|
||||
}
|
||||
|
||||
size_t copyStart = aIter.mSegment;
|
||||
// Copy segments from this over to the result and remove them from our
|
||||
// storage. Not needed if the only segment we need to copy is the last
|
||||
// partial one.
|
||||
size_t segmentsToCopy = segmentsNeeded - lastSegmentSize.isSome();
|
||||
for (size_t i = 0; i < segmentsToCopy; ++i) {
|
||||
result.mSegments.infallibleAppend(
|
||||
Segment(mSegments[aIter.mSegment].mData,
|
||||
mSegments[aIter.mSegment].mSize,
|
||||
mSegments[aIter.mSegment].mCapacity));
|
||||
aIter.Advance(*this, aIter.RemainingInSegment());
|
||||
}
|
||||
// Due to the way IterImpl works, there are two cases here: (1) if we've
|
||||
// consumed the entirety of the BufferList, then the iterator is pointed at
|
||||
// the end of the final segment, (2) otherwise it is pointed at the start
|
||||
// of the next segment. We want to verify that we really consumed all
|
||||
// |segmentsToCopy| segments.
|
||||
MOZ_RELEASE_ASSERT(
|
||||
(aIter.mSegment == copyStart + segmentsToCopy) ||
|
||||
(aIter.Done() && aIter.mSegment == copyStart + segmentsToCopy - 1));
|
||||
mSegments.erase(mSegments.begin() + copyStart,
|
||||
mSegments.begin() + copyStart + segmentsToCopy);
|
||||
|
||||
// Reset the iter's position for what we just deleted.
|
||||
aIter.mSegment -= segmentsToCopy;
|
||||
|
||||
if (lastSegmentSize.isSome()) {
|
||||
// We called reserve() on result.mSegments so infallibleAppend is safe.
|
||||
result.mSegments.infallibleAppend(
|
||||
Segment(finalSegment, 0, mStandardCapacity));
|
||||
bool r = result.WriteBytes(aIter.Data(), *lastSegmentSize);
|
||||
MOZ_RELEASE_ASSERT(r);
|
||||
aIter.Advance(*this, *lastSegmentSize);
|
||||
}
|
||||
}
|
||||
|
||||
mSize -= aSize;
|
||||
result.mSize = aSize;
|
||||
|
||||
resultGuard.release();
|
||||
*aSuccess = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -245,12 +245,51 @@ int main(void)
|
||||
BufferList bl3 = bl.Extract(iter, kExtractOverSize, &success);
|
||||
MOZ_RELEASE_ASSERT(!success);
|
||||
|
||||
MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3 - kExtractSize - kExtractStart));
|
||||
MOZ_RELEASE_ASSERT(iter.Done());
|
||||
|
||||
iter = bl2.Iter();
|
||||
MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kExtractSize));
|
||||
MOZ_RELEASE_ASSERT(iter.Done());
|
||||
|
||||
BufferList bl4(8, 8, 8);
|
||||
bl4.WriteBytes("abcd1234", 8);
|
||||
iter = bl4.Iter();
|
||||
iter.Advance(bl4, 8);
|
||||
|
||||
BufferList bl5 = bl4.Extract(iter, kExtractSize, &success);
|
||||
MOZ_RELEASE_ASSERT(!success);
|
||||
|
||||
BufferList bl6(0, 0, 16);
|
||||
bl6.WriteBytes("abcdefgh12345678", 16);
|
||||
bl6.WriteBytes("ijklmnop87654321", 16);
|
||||
iter = bl6.Iter();
|
||||
iter.Advance(bl6, 8);
|
||||
BufferList bl7 = bl6.Extract(iter, 16, &success);
|
||||
MOZ_RELEASE_ASSERT(success);
|
||||
char data[16];
|
||||
MOZ_RELEASE_ASSERT(bl6.ReadBytes(iter, data, 8));
|
||||
MOZ_RELEASE_ASSERT(memcmp(data, "87654321", 8) == 0);
|
||||
iter = bl7.Iter();
|
||||
MOZ_RELEASE_ASSERT(bl7.ReadBytes(iter, data, 16));
|
||||
MOZ_RELEASE_ASSERT(memcmp(data, "12345678ijklmnop", 16) == 0);
|
||||
|
||||
BufferList bl8(0, 0, 16);
|
||||
bl8.WriteBytes("abcdefgh12345678", 16);
|
||||
iter = bl8.Iter();
|
||||
BufferList bl9 = bl8.Extract(iter, 8, &success);
|
||||
MOZ_RELEASE_ASSERT(success);
|
||||
MOZ_RELEASE_ASSERT(bl9.Size() == 8);
|
||||
MOZ_RELEASE_ASSERT(!iter.Done());
|
||||
|
||||
BufferList bl10(0, 0, 8);
|
||||
bl10.WriteBytes("abcdefgh", 8);
|
||||
bl10.WriteBytes("12345678", 8);
|
||||
iter = bl10.Iter();
|
||||
BufferList bl11 = bl10.Extract(iter, 16, &success);
|
||||
MOZ_RELEASE_ASSERT(success);
|
||||
MOZ_RELEASE_ASSERT(bl11.Size() == 16);
|
||||
MOZ_RELEASE_ASSERT(iter.Done());
|
||||
iter = bl11.Iter();
|
||||
MOZ_RELEASE_ASSERT(bl11.ReadBytes(iter, data, 16));
|
||||
MOZ_RELEASE_ASSERT(memcmp(data, "abcdefgh12345678", 16) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3401,8 +3401,10 @@ FromIPCSegment(const nsACString& aSpec, const ipc::StandardURLSegment& aSegment,
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedInt<uint32_t> segmentLen = aSegment.position();
|
||||
segmentLen += aSegment.length();
|
||||
// Make sure the segment does not extend beyond the spec.
|
||||
if (NS_WARN_IF(aSegment.position() + aSegment.length() > aSpec.Length())) {
|
||||
if (NS_WARN_IF(!segmentLen.isValid() || segmentLen.value() > aSpec.Length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIStandardURL.h"
|
||||
#include "nsString.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIIPCSerializableURI.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
|
||||
TEST(TestStandardURL, Simple) {
|
||||
nsCOMPtr<nsIURL> url( do_CreateInstance(NS_STANDARDURL_CONTRACTID) );
|
||||
@@ -67,3 +70,16 @@ MOZ_GTEST_BENCH(TestStandardURL, Perf, [] {
|
||||
url->GetRef(out);
|
||||
}
|
||||
});
|
||||
|
||||
TEST(TestStandardURL, Deserialize_Bug1392739)
|
||||
{
|
||||
mozilla::ipc::StandardURLParams standard_params;
|
||||
standard_params.urlType() = nsIStandardURL::URLTYPE_STANDARD;
|
||||
standard_params.spec() = NS_LITERAL_CSTRING("");
|
||||
standard_params.host() = mozilla::ipc::StandardURLSegment(4294967295, 1);
|
||||
|
||||
mozilla::ipc::URIParams params(standard_params);
|
||||
|
||||
nsCOMPtr<nsIIPCSerializableURI> url = do_CreateInstance(NS_STANDARDURL_CID);
|
||||
ASSERT_EQ(url->Deserialize(params), false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user