Bug 1345403 part 2 - Mark element tainted when DrawImage is used; r?jwwang, mattwoodrow
Mark video element as tainted (stored on the decoder owned by video element) when the video is used as source to drawImage() on canvas.
MozReview-Commit-ID: HdciVwhqPu3
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1522,16 +1522,36 @@ HTMLMediaElement::SetVisible(bool aVisib
{
if (!mDecoder) {
return;
}
mDecoder->SetForcedHidden(!aVisible);
}
+layers::Image*
+HTMLMediaElement::GetCurrentImage()
+{
+ // Mark the decoder owned by the element as tainted so that the
+ // suspend-vide-decoder is suspended.
+ mHasSuspendTaint = true;
+ if (mDecoder) {
+ mDecoder->SetSuspendTaint(true);
+ }
+
+ // TODO: In bug 1345404, handle case when video decoder is already suspended.
+ ImageContainer* container = GetImageContainer();
+ if (!container) {
+ return nullptr;
+ }
+
+ AutoLockImage lockImage(container);
+ return lockImage.GetImage();
+}
+
already_AddRefed<DOMMediaStream>
HTMLMediaElement::GetSrcObject() const
{
NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetPlaybackStream(),
"MediaStream should have been set up properly");
RefPtr<DOMMediaStream> stream = mSrcAttrStream;
return stream.forget();
}
@@ -3687,16 +3707,17 @@ HTMLMediaElement::HTMLMediaElement(alrea
mWaitingForKey(NOT_WAITING_FOR_KEY),
mDownloadSuspendedByCache(false, "HTMLMediaElement::mDownloadSuspendedByCache"),
mAudioChannel(AudioChannelService::GetDefaultAudioChannel()),
mDisableVideo(false),
mHasUserInteraction(false),
mFirstFrameLoaded(false),
mDefaultPlaybackStartPosition(0.0),
mIsAudioTrackAudible(false),
+ mHasSuspendTaint(false),
mVisibilityState(Visibility::APPROXIMATELY_NONVISIBLE),
mErrorSink(new ErrorSink(this)),
mAudioChannelWrapper(new AudioChannelAgentCallback(this, mAudioChannel))
{
ErrorResult rv;
double defaultVolume = Preferences::GetFloat("media.default_volume", 1.0);
SetVolume(defaultVolume, rv);
@@ -4684,16 +4705,18 @@ nsresult HTMLMediaElement::FinishDecoder
mDecoder->SetResource(aStream);
mDecoder->SetAudioChannel(mAudioChannel);
mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
mDecoder->SetPreservesPitch(mPreservesPitch);
mDecoder->SetPlaybackRate(mPlaybackRate);
if (mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
mDecoder->SetMinimizePrerollUntilPlaybackStarts();
}
+ // Notify the decoder of suspend taint.
+ mDecoder->SetSuspendTaint(mHasSuspendTaint);
// Update decoder principal before we start decoding, since it
// can affect how we feed data to MediaStreams
NotifyDecoderPrincipalChanged();
nsresult rv = aDecoder->Load(aListener);
if (NS_FAILED(rv)) {
ShutdownDecoder();
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -614,16 +614,24 @@ public:
// Returns a promise which will be resolved after collecting debugging
// data from decoder/reader/MDSM. Used for debugging purposes.
already_AddRefed<Promise> MozRequestDebugInfo(ErrorResult& aRv);
void MozDumpDebugInfo();
void SetVisible(bool aVisible);
+ // Synchronously, return the next video frame and mark the element unable to
+ // participate in decode suspending.
+ //
+ // This function is synchronous for cases where decoding has been suspended
+ // and JS needs a frame to use in, eg., nsLayoutUtils::SurfaceFromElement()
+ // via drawImage().
+ layers::Image* GetCurrentImage();
+
already_AddRefed<DOMMediaStream> GetSrcObject() const;
void SetSrcObject(DOMMediaStream& aValue);
void SetSrcObject(DOMMediaStream* aValue);
// TODO: remove prefixed versions soon (1183495).
already_AddRefed<DOMMediaStream> GetMozSrcObject() const;
void SetMozSrcObject(DOMMediaStream& aValue);
void SetMozSrcObject(DOMMediaStream* aValue);
@@ -1709,16 +1717,20 @@ private:
// Media elements also have a default playback start position, which must
// initially be set to zero seconds. This time is used to allow the element to
// be seeked even before the media is loaded.
double mDefaultPlaybackStartPosition;
// True if the audio track is not silent.
bool mIsAudioTrackAudible;
+ // True if media element has been marked as 'tainted' and can't
+ // participate in video decoder suspending.
+ bool mHasSuspendTaint;
+
Visibility mVisibilityState;
UniquePtr<ErrorSink> mErrorSink;
// This wrapper will handle all audio channel related stuffs, eg. the operations
// of tab audio indicator, Fennec's media control.
// Note: mAudioChannelWrapper might be null after GC happened.
RefPtr<AudioChannelAgentCallback> mAudioChannelWrapper;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -7332,23 +7332,18 @@ nsLayoutUtils::SurfaceFromElement(HTMLVi
return result;
}
// If it doesn't have a principal, just bail
nsCOMPtr<nsIPrincipal> principal = aElement->GetCurrentVideoPrincipal();
if (!principal)
return result;
- ImageContainer* container = aElement->GetImageContainer();
- if (!container)
- return result;
-
- AutoLockImage lockImage(container);
-
- result.mLayersImage = lockImage.GetImage();
+ result.mLayersImage = aElement->GetCurrentImage();
+
if (!result.mLayersImage)
return result;
if (aTarget) {
// They gave us a DrawTarget to optimize for, so even though we have a layers::Image,
// we should unconditionally grab a SourceSurface and try to optimize it.
result.mSourceSurface = result.mLayersImage->GetAsSourceSurface();
if (!result.mSourceSurface)