cherry-picked mozilla upstream changes:

bug1464829, bug1452375, bug1458264, bug1464784, bug1392739, bug1453127, bug1456189, bug1462912
This commit is contained in:
2018-06-23 08:03:47 +08:00
parent 442fafaad5
commit 03a3648e72
20 changed files with 389 additions and 117 deletions
+10 -10
View File
@@ -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;
}
+15 -6
View File
@@ -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());
+42 -5
View File
@@ -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);
}
+11 -1
View File
@@ -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;
};
+13 -1
View File
@@ -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;
}
+5 -1
View File
@@ -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();
+14 -1
View File
@@ -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
{
+4 -1
View File
@@ -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);
+8 -3
View File
@@ -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()
+60 -15
View File
@@ -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.
+26 -9
View File
@@ -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
View File
@@ -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;
}
+3 -1
View File
@@ -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,
+7 -7
View File
@@ -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;
-2
View File
@@ -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;
+1 -3
View File
@@ -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
View File
@@ -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;
}
+42 -3
View File
@@ -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;
}
+3 -1
View File
@@ -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;
}
+16
View File
@@ -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);
}