Bug 1377025. P1 - dispatch image size changes to the main thread so mImageSizeChanged is for main thread only.
MozReview-Commit-ID: 6rpxjSVAY2h
--- 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;