Bug 1377025. P1 - dispatch image size changes to the main thread so mImageSizeChanged is for main thread only. draft
authorJW Wang <jwwang@mozilla.com>
Wed, 28 Jun 2017 23:04:49 +0800
changeset 601804 f864351c23fb0dcbde9ceb1bbaa559ba440a12b4
parent 601703 4cb59963275796e8b211d9b98116a020a2a7429a
child 601805 3fb163074f673edde9db21f0d713f8204b882cdf
push id66221
push userjwwang@mozilla.com
push dateThu, 29 Jun 2017 08:25:32 +0000
bugs1377025
milestone56.0a1
Bug 1377025. P1 - dispatch image size changes to the main thread so mImageSizeChanged is for main thread only. MozReview-Commit-ID: 6rpxjSVAY2h
dom/media/VideoFrameContainer.cpp
dom/media/VideoFrameContainer.h
--- a/dom/media/VideoFrameContainer.cpp
+++ b/dom/media/VideoFrameContainer.cpp
@@ -37,26 +37,28 @@ public:
       Telemetry::Accumulate(ID, diff);
     }
   }
 private:
   const TimeStamp mStart = TimeStamp::Now();
 };
 }
 
-VideoFrameContainer::VideoFrameContainer(dom::HTMLMediaElement* aElement,
-                                         already_AddRefed<ImageContainer> aContainer)
-  : mElement(aElement),
-    mImageContainer(aContainer), mMutex("nsVideoFrameContainer"),
-    mBlackImage(nullptr),
-    mFrameID(0),
-    mIntrinsicSizeChanged(false), mImageSizeChanged(false),
-    mPendingPrincipalHandle(PRINCIPAL_HANDLE_NONE),
-    mFrameIDForPendingPrincipalHandle(0),
-    mMainThread(aElement->AbstractMainThread())
+VideoFrameContainer::VideoFrameContainer(
+  dom::HTMLMediaElement* aElement,
+  already_AddRefed<ImageContainer> aContainer)
+  : mElement(aElement)
+  , mImageContainer(aContainer)
+  , mMutex("nsVideoFrameContainer")
+  , mBlackImage(nullptr)
+  , mFrameID(0)
+  , mIntrinsicSizeChanged(false)
+  , mPendingPrincipalHandle(PRINCIPAL_HANDLE_NONE)
+  , mFrameIDForPendingPrincipalHandle(0)
+  , mMainThread(aElement->AbstractMainThread())
 {
   NS_ASSERTION(aElement, "aElement must not be null");
   NS_ASSERTION(mImageContainer, "aContainer must not be null");
 }
 
 VideoFrameContainer::~VideoFrameContainer()
 {}
 
@@ -250,54 +252,55 @@ void VideoFrameContainer::SetCurrentFram
   //  block on main thread I/O. If we let this happen while holding onto
   //  |mImageContainer|'s lock, then when the main thread then tries to
   //  composite it can then block on |mImageContainer|'s lock, causing a
   //  deadlock. We use this hack to defer the destruction of the current image
   //  until it is safe.
   nsTArray<ImageContainer::OwningImage> oldImages;
   mImageContainer->GetCurrentImages(&oldImages);
 
+  PrincipalHandle principalHandle = PRINCIPAL_HANDLE_NONE;
   ImageContainer::FrameID lastFrameIDForOldPrincipalHandle =
     mFrameIDForPendingPrincipalHandle - 1;
   if (mPendingPrincipalHandle != PRINCIPAL_HANDLE_NONE &&
        ((!oldImages.IsEmpty() &&
           oldImages.LastElement().mFrameID >= lastFrameIDForOldPrincipalHandle) ||
         (!aImages.IsEmpty() &&
           aImages[0].mFrameID > lastFrameIDForOldPrincipalHandle))) {
     // We are releasing the last FrameID prior to `lastFrameIDForOldPrincipalHandle`
     // OR
     // there are no FrameIDs prior to `lastFrameIDForOldPrincipalHandle` in the new
     // set of images.
     // This means that the old principal handle has been flushed out and we can
     // notify our video element about this change.
-    RefPtr<VideoFrameContainer> self = this;
-    PrincipalHandle principalHandle = mPendingPrincipalHandle;
+    principalHandle = mPendingPrincipalHandle;
     mLastPrincipalHandle = mPendingPrincipalHandle;
     mPendingPrincipalHandle = PRINCIPAL_HANDLE_NONE;
     mFrameIDForPendingPrincipalHandle = 0;
-    mMainThread->Dispatch(
-      NS_NewRunnableFunction(
-        "PrincipalHandleChangedForVideoFrameContainer",
-        [self, principalHandle]() {
-          if (self->mElement) {
-            self->mElement->PrincipalHandleChangedForVideoFrameContainer(self, principalHandle);
-          }
-        }
-      )
-    );
   }
 
   if (aImages.IsEmpty()) {
     mImageContainer->ClearAllImages();
   } else {
     mImageContainer->SetCurrentImages(aImages);
   }
   gfx::IntSize newFrameSize = mImageContainer->GetCurrentSize();
-  if (oldFrameSize != newFrameSize) {
-    mImageSizeChanged = true;
+  bool imageSizeChanged = (oldFrameSize != newFrameSize);
+
+  if (principalHandle != PRINCIPAL_HANDLE_NONE || imageSizeChanged) {
+    RefPtr<VideoFrameContainer> self = this;
+    mMainThread->Dispatch(NS_NewRunnableFunction(
+      "PrincipalHandleOrImageSizeChanged",
+      [this, self, principalHandle, imageSizeChanged]() {
+        mMainThreadState.mImageSizeChanged = imageSizeChanged;
+        if (mElement && principalHandle != PRINCIPAL_HANDLE_NONE) {
+          mElement->PrincipalHandleChangedForVideoFrameContainer(
+            this, principalHandle);
+        }
+      }));
   }
 }
 
 void VideoFrameContainer::ClearCurrentFrame()
 {
   MutexAutoLock lock(mMutex);
   AutoTimer<Telemetry::VFC_CLEARCURRENTFRAME_LOCK_HOLD_MS> lockHold;
 
@@ -350,31 +353,28 @@ void VideoFrameContainer::InvalidateWith
   NS_ASSERTION(NS_IsMainThread(), "Must call on main thread");
 
   if (!mElement) {
     // Element has been destroyed
     return;
   }
 
   nsIFrame* frame = mElement->GetPrimaryFrame();
-  bool invalidateFrame = false;
+  bool invalidateFrame = mMainThreadState.mImageSizeChanged;
+  mMainThreadState.mImageSizeChanged = false;
 
   {
     Maybe<AutoTimer<Telemetry::VFC_INVALIDATE_LOCK_WAIT_MS>> lockWait;
     lockWait.emplace();
 
     MutexAutoLock lock(mMutex);
 
     lockWait.reset();
     AutoTimer<Telemetry::VFC_INVALIDATE_LOCK_HOLD_MS> lockHold;
 
-    // Get mImageContainerSizeChanged while holding the lock.
-    invalidateFrame = mImageSizeChanged;
-    mImageSizeChanged = false;
-
     if (mIntrinsicSizeChanged) {
       mElement->UpdateMediaSize(mIntrinsicSize);
       mIntrinsicSizeChanged = false;
 
       if (frame) {
         nsPresContext* presContext = frame->PresContext();
         nsIPresShell *presShell = presContext->PresShell();
         presShell->FrameNeedsReflow(frame,
--- a/dom/media/VideoFrameContainer.h
+++ b/dom/media/VideoFrameContainer.h
@@ -100,16 +100,25 @@ protected:
   void SetCurrentFramesLocked(const gfx::IntSize& aIntrinsicSize,
                               const nsTArray<ImageContainer::NonOwningImage>& aImages);
 
   // Non-addreffed pointer to the element. The element calls ForgetElement
   // to clear this reference when the element is destroyed.
   dom::HTMLMediaElement* mElement;
   RefPtr<ImageContainer> mImageContainer;
 
+  struct
+  {
+    // True when the Image size has changed since the last time Invalidate() was
+    // called. When set, the next call to Invalidate() will ensure that the
+    // frame is fully invalidated instead of just invalidating for the image change
+    // in the ImageLayer.
+    bool mImageSizeChanged = false;
+  } mMainThreadState;
+
   // mMutex protects all the fields below.
   Mutex mMutex;
   // Once the frame is forced to black, we initialize mBlackImage for following
   // frames.
   RefPtr<Image> mBlackImage;
   // The intrinsic size is the ideal size which we should render the
   // ImageContainer's current Image at.
   // This can differ from the Image's actual size when the media resource
@@ -123,21 +132,16 @@ protected:
   // with a different frame id.
   VideoFrame mLastPlayedVideoFrame;
   // True when the intrinsic size has been changed by SetCurrentFrame() since
   // the last call to Invalidate().
   // The next call to Invalidate() will recalculate
   // and update the intrinsic size on the element, request a frame reflow and
   // then reset this flag.
   bool mIntrinsicSizeChanged;
-  // True when the Image size has changed since the last time Invalidate() was
-  // called. When set, the next call to Invalidate() will ensure that the
-  // frame is fully invalidated instead of just invalidating for the image change
-  // in the ImageLayer.
-  bool mImageSizeChanged;
   // The last PrincipalHandle we notified mElement about.
   PrincipalHandle mLastPrincipalHandle;
   // The PrincipalHandle the client has notified us is changing with FrameID
   // mFrameIDForPendingPrincipalHandle.
   PrincipalHandle mPendingPrincipalHandle;
   // The FrameID for which mPendingPrincipal is first valid.
   ImageContainer::FrameID mFrameIDForPendingPrincipalHandle;