Bug 1345403 part 2 - Mark element tainted when DrawImage is used; r=jwwang,mattwoodrow
☠☠ backed out by 135488a851a5 ☠ ☠
authorKaku Kuo <kaku@mozilla.com>
Wed, 08 Mar 2017 19:41:08 +0800
changeset 395162 ba072186c91771b8f55bc099d8d0b05cd4d7b2ed
parent 395161 7a7d6e9b8329d2806f985836c201a69503e9b24e
child 395163 a3e4ce12194fd5212e7daf3225c8254845f910ca
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwwang, mattwoodrow
bugs1345403
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
layout/base/nsLayoutUtils.cpp
--- 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)