Bug 1416663 - Move Gecko/HTMLMediaElement specific stuff out of VideoFrameContainer. r=jwwang draft
authorChris Pearce <cpearce@mozilla.com>
Mon, 13 Nov 2017 16:09:23 +1300
changeset 697073 0f9e33c3704aa3925635d2290a5e18f9eebd2b74
parent 696902 83b4d6cc58b8c65b42108efb1e57c5ddb904ea1f
child 740009 4820555ab1234f90a274b5818aec1b6a4730ed51
push id88882
push userbmo:cpearce@mozilla.com
push dateMon, 13 Nov 2017 09:52:25 +0000
reviewersjwwang
bugs1416663
milestone58.0a1
Bug 1416663 - Move Gecko/HTMLMediaElement specific stuff out of VideoFrameContainer. r=jwwang MozReview-Commit-ID: 4giNMi8qsTZ
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
dom/media/MediaDecoderOwner.h
dom/media/VideoFrameContainer.cpp
dom/media/VideoFrameContainer.h
dom/media/mediasink/VideoSink.cpp
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -95,16 +95,20 @@
 #include "nsIContentPolicy.h"
 #include "mozilla/Telemetry.h"
 #include "DecoderDoctorDiagnostics.h"
 #include "DecoderTraits.h"
 #include "MediaContainerType.h"
 #include "MP4Decoder.h"
 #include "FrameStatistics.h"
 
+#include "nsIFrame.h"
+#include "nsDisplayList.h"
+#include "SVGObserverUtils.h"
+
 #ifdef MOZ_ANDROID_HLS_SUPPORT
 #include "HLSDecoder.h"
 #endif
 
 #include "ImageContainer.h"
 #include "nsRange.h"
 #include <algorithm>
 #include <cmath>
@@ -6398,16 +6402,49 @@ void HTMLMediaElement::AddDecoderPrincip
   mDecoderPrincipalChangeObservers.AppendElement(aObserver);
 }
 
 bool HTMLMediaElement::RemoveDecoderPrincipalChangeObserver(DecoderPrincipalChangeObserver* aObserver)
 {
   return mDecoderPrincipalChangeObservers.RemoveElement(aObserver);
 }
 
+void
+HTMLMediaElement::Invalidate(bool aImageSizeChanged,
+                             Maybe<nsIntSize>& aNewIntrinsicSize,
+                             bool aForceInvalidate)
+{
+  nsIFrame* frame = GetPrimaryFrame();
+  if (aNewIntrinsicSize) {
+    UpdateMediaSize(aNewIntrinsicSize.value());
+    if (frame) {
+      nsPresContext* presContext = frame->PresContext();
+      nsIPresShell* presShell = presContext->PresShell();
+      presShell->FrameNeedsReflow(
+        frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
+    }
+  }
+
+  RefPtr<ImageContainer> imageContainer = GetImageContainer();
+  bool asyncInvalidate =
+    imageContainer && imageContainer->IsAsync() && !aForceInvalidate;
+  if (frame) {
+    if (aImageSizeChanged) {
+      frame->InvalidateFrame();
+    } else {
+      frame->InvalidateLayer(DisplayItemType::TYPE_VIDEO,
+                             nullptr,
+                             nullptr,
+                             asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0);
+    }
+  }
+
+  SVGObserverUtils::InvalidateDirectRenderingObservers(this);
+}
+
 void HTMLMediaElement::UpdateMediaSize(const nsIntSize& aSize)
 {
   if (IsVideo() && mReadyState != HAVE_NOTHING &&
       mMediaInfo.mVideo.mDisplay != aSize) {
     DispatchAsyncEvent(NS_LITERAL_STRING("resize"));
   }
 
   mMediaInfo.mVideo.mDisplay = aSize;
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -238,18 +238,19 @@ public:
 
   // From PrincipalChangeObserver<DOMMediaStream>.
   void PrincipalChanged(DOMMediaStream* aStream) override;
 
   void UpdateSrcStreamVideoPrincipal(const PrincipalHandle& aPrincipalHandle);
 
   // Called after the MediaStream we're playing rendered a frame to aContainer
   // with a different principalHandle than the previous frame.
-  void PrincipalHandleChangedForVideoFrameContainer(VideoFrameContainer* aContainer,
-                                                    const PrincipalHandle& aNewPrincipalHandle);
+  void PrincipalHandleChangedForVideoFrameContainer(
+    VideoFrameContainer* aContainer,
+    const PrincipalHandle& aNewPrincipalHandle) override;
 
   // Dispatch events
   virtual void DispatchAsyncEvent(const nsAString& aName) final override;
 
   // Triggers a recomputation of readyState.
   void UpdateReadyState() override { UpdateReadyStateInternal(); }
 
   // Dispatch events that were raised while in the bfcache
@@ -325,16 +326,20 @@ public:
 
   // Update the visual size of the media. Called from the decoder on the
   // main thread when/if the size changes.
   void UpdateMediaSize(const nsIntSize& aSize);
   // Like UpdateMediaSize, but only updates the size if no size has yet
   // been set.
   void UpdateInitialMediaSize(const nsIntSize& aSize);
 
+  void Invalidate(bool aImageSizeChanged,
+                  Maybe<nsIntSize>& aNewIntrinsicSize,
+                  bool aForceInvalidate) override;
+
   // Returns the CanPlayStatus indicating if we can handle the
   // full MIME type including the optional codecs parameter.
   static CanPlayStatus GetCanPlay(const nsAString& aType,
                                   DecoderDoctorDiagnostics* aDiagnostics);
 
   /**
    * Called when a child source element is added to this media element. This
    * may queue a task to run the select resource algorithm if appropriate.
--- a/dom/media/MediaDecoderOwner.h
+++ b/dom/media/MediaDecoderOwner.h
@@ -3,16 +3,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef MediaDecoderOwner_h_
 #define MediaDecoderOwner_h_
 
 #include "mozilla/UniquePtr.h"
 #include "MediaInfo.h"
+#include "MediaSegment.h"
+#include "nsSize.h"
+
+class nsIDocument;
 
 namespace mozilla {
 
 class AbstractThread;
 class GMPCrashHelper;
 class VideoFrameContainer;
 class MediaInfo;
 class MediaResult;
@@ -169,16 +173,29 @@ public:
   virtual nsIDocument* GetDocument() const { return nullptr; }
 
   // Called by the media decoder to create a GMPCrashHelper.
   virtual already_AddRefed<GMPCrashHelper> CreateGMPCrashHelper()
   {
     return nullptr;
   }
 
+  // Called by the frame container to notify the layout engine that the
+  // size of the image has changed, or the video needs to be be repainted
+  // for some other reason.
+  virtual void Invalidate(bool aImageSizeChanged,
+                          Maybe<nsIntSize>& aNewIntrinsicSize,
+                          bool aForceInvalidate) {}
+
+  // Called after the MediaStream we're playing rendered a frame to aContainer
+  // with a different principalHandle than the previous frame.
+  virtual void PrincipalHandleChangedForVideoFrameContainer(
+    VideoFrameContainer* aContainer,
+    const PrincipalHandle& aNewPrincipalHandle) {}
+
   /*
    * Servo only methods go here. Please provide default implementations so they
    * can build in Gecko without any modification.
    */
 };
 
 } // namespace mozilla
 
--- a/dom/media/VideoFrameContainer.cpp
+++ b/dom/media/VideoFrameContainer.cpp
@@ -1,22 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "VideoFrameContainer.h"
-
-#include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/Telemetry.h"
-
-#include "nsIFrame.h"
-#include "nsDisplayList.h"
-#include "SVGObserverUtils.h"
+#include "MediaDecoderOwner.h"
 
 using namespace mozilla::layers;
 
 namespace mozilla {
 static LazyLogModule gVideoFrameContainerLog("VideoFrameContainer");
 #define CONTAINER_LOG(type, msg) MOZ_LOG(gVideoFrameContainerLog, type, msg)
 
 #define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
@@ -38,28 +33,28 @@ public:
     }
   }
 private:
   const TimeStamp mStart = TimeStamp::Now();
 };
 }
 
 VideoFrameContainer::VideoFrameContainer(
-  dom::HTMLMediaElement* aElement,
+  MediaDecoderOwner* aOwner,
   already_AddRefed<ImageContainer> aContainer)
-  : mElement(aElement)
+  : mOwner(aOwner)
   , mImageContainer(aContainer)
   , mMutex("nsVideoFrameContainer")
   , mBlackImage(nullptr)
   , mFrameID(0)
   , mPendingPrincipalHandle(PRINCIPAL_HANDLE_NONE)
   , mFrameIDForPendingPrincipalHandle(0)
-  , mMainThread(aElement->AbstractMainThread())
+  , mMainThread(aOwner->AbstractMainThread())
 {
-  NS_ASSERTION(aElement, "aElement must not be null");
+  NS_ASSERTION(aOwner, "aOwner must not be null");
   NS_ASSERTION(mImageContainer, "aContainer must not be null");
 }
 
 VideoFrameContainer::~VideoFrameContainer()
 {}
 
 PrincipalHandle VideoFrameContainer::GetLastPrincipalHandle()
 {
@@ -290,19 +285,19 @@ void VideoFrameContainer::SetCurrentFram
   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);
+        if (mOwner && principalHandle != PRINCIPAL_HANDLE_NONE) {
+          mOwner->PrincipalHandleChangedForVideoFrameContainer(this,
+                                                               principalHandle);
         }
       }));
   }
 }
 
 void VideoFrameContainer::ClearCurrentFrame()
 {
   MutexAutoLock lock(mMutex);
@@ -341,57 +336,38 @@ VideoFrameContainer::ClearCachedResource
 {
   mImageContainer->ClearCachedResources();
 }
 
 ImageContainer* VideoFrameContainer::GetImageContainer() {
   return mImageContainer;
 }
 
-
 double VideoFrameContainer::GetFrameDelay()
 {
   return mImageContainer->GetPaintDelay().ToSeconds();
 }
 
 void VideoFrameContainer::InvalidateWithFlags(uint32_t aFlags)
 {
   NS_ASSERTION(NS_IsMainThread(), "Must call on main thread");
 
-  if (!mElement) {
-    // Element has been destroyed
+  if (!mOwner) {
+    // Owner has been destroyed
     return;
   }
 
-  nsIFrame* frame = mElement->GetPrimaryFrame();
-  bool invalidateFrame = mMainThreadState.mImageSizeChanged;
+  bool imageSizeChanged = mMainThreadState.mImageSizeChanged;
   mMainThreadState.mImageSizeChanged = false;
 
+  Maybe<nsIntSize> intrinsicSize;
   if (mMainThreadState.mIntrinsicSizeChanged) {
-    mElement->UpdateMediaSize(mMainThreadState.mIntrinsicSize);
+    intrinsicSize = Some(mMainThreadState.mIntrinsicSize);
     mMainThreadState.mIntrinsicSizeChanged = false;
-    if (frame) {
-      nsPresContext* presContext = frame->PresContext();
-      nsIPresShell* presShell = presContext->PresShell();
-      presShell->FrameNeedsReflow(
-        frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
-    }
   }
 
-  bool asyncInvalidate = mImageContainer &&
-                         mImageContainer->IsAsync() &&
-                         !(aFlags & INVALIDATE_FORCE);
-
-  if (frame) {
-    if (invalidateFrame) {
-      frame->InvalidateFrame();
-    } else {
-      frame->InvalidateLayer(DisplayItemType::TYPE_VIDEO, nullptr, nullptr,
-                             asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0);
-    }
-  }
-
-  SVGObserverUtils::InvalidateDirectRenderingObservers(mElement);
+  bool forceInvalidate = aFlags & INVALIDATE_FORCE;
+  mOwner->Invalidate(imageSizeChanged, intrinsicSize, forceInvalidate);
 }
 
 } // namespace mozilla
 
 #undef NS_DispatchToMainThread
--- a/dom/media/VideoFrameContainer.h
+++ b/dom/media/VideoFrameContainer.h
@@ -13,19 +13,17 @@
 #include "nsCOMPtr.h"
 #include "ImageContainer.h"
 #include "MediaSegment.h"
 #include "MediaStreamVideoSink.h"
 #include "VideoSegment.h"
 
 namespace mozilla {
 
-namespace dom {
-class HTMLMediaElement;
-} // namespace dom
+class MediaDecoderOwner;
 
 /**
  * This object is used in the decoder backend threads and the main thread
  * to manage the "current video frame" state. This state includes timing data
  * and an intrinsic size (see below).
  * This has to be a thread-safe object since it's accessed by resource decoders
  * and other off-main-thread components. So we can't put this state in the media
  * element itself ... well, maybe we could, but it could be risky and/or
@@ -33,17 +31,17 @@ class HTMLMediaElement;
  */
 class VideoFrameContainer : public MediaStreamVideoSink {
   virtual ~VideoFrameContainer();
 
 public:
   typedef layers::ImageContainer ImageContainer;
   typedef layers::Image Image;
 
-  VideoFrameContainer(dom::HTMLMediaElement* aElement,
+  VideoFrameContainer(MediaDecoderOwner* aOwner,
                       already_AddRefed<ImageContainer> aContainer);
 
   // Call on any thread
   virtual void SetCurrentFrames(const VideoSegment& aSegment) override;
   virtual void ClearFrames() override;
   void SetCurrentFrame(const gfx::IntSize& aIntrinsicSize, Image* aImage,
                        const TimeStamp& aTargetTime);
   // Returns the last principalHandle we notified mElement about.
@@ -87,27 +85,27 @@ public:
   // Call on main thread
   enum {
     INVALIDATE_DEFAULT,
     INVALIDATE_FORCE
   };
   void Invalidate() override { InvalidateWithFlags(INVALIDATE_DEFAULT); }
   void InvalidateWithFlags(uint32_t aFlags);
   ImageContainer* GetImageContainer();
-  void ForgetElement() { mElement = nullptr; }
+  void ForgetElement() { mOwner = nullptr; }
 
   uint32_t GetDroppedImageCount() { return mImageContainer->GetDroppedImageCount(); }
 
 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;
+  // Non-addreffed pointer to the owner. The ownenr calls ForgetElement
+  // to clear this reference when the owner is destroyed.
+  MediaDecoderOwner* mOwner;
   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.
--- a/dom/media/mediasink/VideoSink.cpp
+++ b/dom/media/mediasink/VideoSink.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaQueue.h"
 #include "VideoSink.h"
 #include "MediaPrefs.h"
+#include "VideoUtils.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
 
 namespace mozilla {
 
 extern LazyLogModule gMediaDecoderLog;
 
 #undef FMT