Bug 482885. Ensure media channels are in the document loadgroup. r=bzbarsky,r+sr=roc

--HG--
extra : rebase_source : da14c85f0efd3eda24739161f8195d24117da261
This commit is contained in:
Chris Pearce 2009-04-10 13:28:24 +12:00
parent c7e46876e5
commit ee8c4eae0d
9 changed files with 124 additions and 6 deletions

View File

@ -42,6 +42,7 @@
#include "nsThreadUtils.h"
#include "nsIDOMRange.h"
#include "nsCycleCollectionParticipant.h"
#include "nsILoadGroup.h"
// Define to output information on decoding and painting framerate
/* #define DEBUG_FRAME_RATE 1 */
@ -228,6 +229,11 @@ public:
*/
PRUint32 GetCurrentLoadID() { return mCurrentLoadID; }
/**
* Returns the load group for this media element's owner document.
* XXX XBL2 issue.
*/
already_AddRefed<nsILoadGroup> GetDocumentLoadGroup();
protected:
class MediaLoadListener;
@ -307,6 +313,10 @@ protected:
nsRefPtr<nsMediaDecoder> mDecoder;
// Holds a reference to the first channel we open to the media resource.
// Once the decoder is created, control over the channel passes to the
// decoder, and we null out this reference. We must store this in case
// we need to cancel the channel before control of it passes to the decoder.
nsCOMPtr<nsIChannel> mChannel;
// Error attribute

View File

@ -498,10 +498,11 @@ nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI)
NS_ENSURE_SUCCESS(rv,rv);
if (NS_CP_REJECTED(shouldLoad)) return NS_ERROR_FAILURE;
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
rv = NS_NewChannel(getter_AddRefs(mChannel),
aURI,
nsnull,
nsnull,
loadGroup,
nsnull,
nsIRequest::LOAD_NORMAL);
NS_ENSURE_SUCCESS(rv,rv);
@ -1118,6 +1119,10 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
if (NS_FAILED(rv))
return rv;
// Decoder successfully created, its nsMediaStream now has responsibility
// for the channel, and the owning reference.
mChannel = nsnull;
mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
if (!mPaused) {
@ -1577,8 +1582,17 @@ void nsHTMLMediaElement::ChangeDelayLoadStatus(PRBool aDelay) {
mLoadBlockedDoc = GetOwnerDoc();
mLoadBlockedDoc->BlockOnload();
} else {
if (mDecoder) {
mDecoder->MoveLoadsToBackground();
}
NS_ASSERTION(mLoadBlockedDoc, "Need a doc to block on");
mLoadBlockedDoc->UnblockOnload(PR_FALSE);
mLoadBlockedDoc = nsnull;
}
}
already_AddRefed<nsILoadGroup> nsHTMLMediaElement::GetDocumentLoadGroup()
{
nsIDocument* doc = GetOwnerDoc();
return doc ? doc->GetDocumentLoadGroup() : nsnull;
}

View File

@ -223,6 +223,13 @@ class nsMediaDecoder : public nsIObserver
// if it's available.
nsHTMLMediaElement* GetMediaElement();
// Moves any existing channel loads into the background, so that they don't
// block the load event. This is called when we stop delaying the load
// event. Any new loads initiated (for example to seek) will also be in the
// background. Implementations of this must call MoveLoadsToBackground() on
// their nsMediaStream.
virtual void MoveLoadsToBackground()=0;
protected:
// Start timer to update download progress information.

View File

@ -198,6 +198,10 @@ public:
virtual nsresult Seek(PRInt32 aWhence, PRInt64 aOffset) = 0;
// Report the current offset in bytes from the start of the stream.
virtual PRInt64 Tell() = 0;
// Moves any existing channel loads into the background, so that they don't
// block the load event. Any new loads initiated (for example to seek)
// will also be in the background.
void MoveLoadsToBackground();
// These can be called on any thread.
// Cached blocks associated with this stream will not be evicted
@ -243,7 +247,8 @@ protected:
nsMediaStream(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
mDecoder(aDecoder),
mChannel(aChannel),
mURI(aURI)
mURI(aURI),
mLoadInBackground(PR_FALSE)
{
MOZ_COUNT_CTOR(nsMediaStream);
}
@ -268,6 +273,10 @@ protected:
// URI in case the stream needs to be re-opened. Access from
// main thread only.
nsCOMPtr<nsIURI> mURI;
// PR_TRUE if MoveLoadsToBackground() has been called, i.e. the load event
// has been fired, and all channel loads will be in the background.
PRPackedBool mLoadInBackground;
};
/**

View File

@ -372,6 +372,9 @@ class nsOggDecoder : public nsMediaDecoder
// main thread only.
virtual void Resume();
// Tells our nsMediaStream to put all loads in the background.
virtual void MoveLoadsToBackground();
protected:
// Returns the monitor for other threads to synchronise access to

View File

@ -220,6 +220,9 @@ class nsWaveDecoder : public nsMediaDecoder
// Change the element's ready state as necessary. Main thread only.
void UpdateReadyStateForData();
// Tells mStream to put all loads in the background.
virtual void MoveLoadsToBackground();
private:
// Notifies the element that seeking has started.
void SeekingStarted();

View File

@ -457,15 +457,27 @@ nsMediaChannelStream::CacheClientSeek(PRInt64 aOffset)
{
NS_ASSERTION(NS_IsMainThread(), "Don't call on main thread");
nsLoadFlags loadFlags =
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
(mLoadInBackground ? nsIRequest::LOAD_BACKGROUND : 0);
CloseChannel();
if (!mDecoder->GetMediaElement()) {
nsHTMLMediaElement* element = mDecoder->GetMediaElement();
if (!element) {
// The decoder is being shut down, so don't bother opening a new channel
return NS_OK;
}
nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
NS_ENSURE_TRUE(loadGroup, NS_ERROR_NULL_POINTER);
nsresult rv =
NS_NewChannel(getter_AddRefs(mChannel), mURI, nsnull, nsnull, nsnull,
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
NS_NewChannel(getter_AddRefs(mChannel),
mURI,
nsnull,
loadGroup,
nsnull,
loadFlags);
if (NS_FAILED(rv))
return rv;
return OpenChannel(nsnull, aOffset);
@ -789,10 +801,13 @@ nsMediaStream::Open(nsMediaDecoder* aDecoder, nsIURI* aURI,
if (aChannel) {
channel = aChannel;
} else {
nsHTMLMediaElement* element = aDecoder->GetMediaElement();
NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
nsresult rv = NS_NewChannel(getter_AddRefs(channel),
aURI,
nsnull,
nsnull,
loadGroup,
nsnull,
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
NS_ENSURE_SUCCESS(rv, rv);
@ -826,3 +841,44 @@ already_AddRefed<nsIPrincipal> nsMediaStream::GetCurrentPrincipal()
secMan->GetChannelPrincipal(mChannel, getter_AddRefs(principal));
return principal.forget();
}
void nsMediaStream::MoveLoadsToBackground() {
NS_ASSERTION(!mLoadInBackground, "Why are you calling this more than once?");
mLoadInBackground = PR_TRUE;
if (!mChannel) {
// No channel, resource is probably already loaded.
return;
}
nsresult rv;
nsHTMLMediaElement* element = mDecoder->GetMediaElement();
if (!element) {
NS_WARNING("Null element in nsMediaStream::MoveLoadsToBackground()");
return;
}
nsCOMPtr<nsILoadGroup> loadGroup;
rv = mChannel->GetLoadGroup(getter_AddRefs(loadGroup));
NS_ASSERTION(NS_SUCCEEDED(rv), "GetLoadGroup() failed!");
nsresult status;
mChannel->GetStatus(&status);
// Note: if (NS_FAILED(status)), the channel won't be in the load group.
PRBool isPending = PR_FALSE;
if (loadGroup &&
NS_SUCCEEDED(status) &&
NS_SUCCEEDED(mChannel->IsPending(&isPending)) &&
isPending) {
rv = loadGroup->RemoveRequest(mChannel, nsnull, status);
NS_ASSERTION(NS_SUCCEEDED(rv), "RemoveRequest() failed!");
nsLoadFlags loadFlags;
rv = mChannel->GetLoadFlags(&loadFlags);
NS_ASSERTION(NS_SUCCEEDED(rv), "GetLoadFlags() failed!");
loadFlags |= nsIRequest::LOAD_BACKGROUND;
rv = mChannel->SetLoadFlags(loadFlags);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetLoadFlags() failed!");
rv = loadGroup->AddRequest(mChannel, nsnull);
NS_ASSERTION(NS_SUCCEEDED(rv), "AddRequest() failed!");
}
}

View File

@ -1991,3 +1991,11 @@ void nsOggDecoder::StartProgressUpdates()
mDecoderPosition = mPlaybackPosition = mReader->Stream()->Tell();
}
}
void nsOggDecoder::MoveLoadsToBackground()
{
if (mReader && mReader->Stream()) {
mReader->Stream()->MoveLoadsToBackground();
}
}

View File

@ -1622,3 +1622,11 @@ nsWaveDecoder::Resume()
mStream->Resume();
}
}
void
nsWaveDecoder::MoveLoadsToBackground()
{
if (mStream) {
mStream->MoveLoadsToBackground();
}
}