michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "VideoFrameContainer.h" michael@0: michael@0: #include "mozilla/dom/HTMLMediaElement.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsDisplayList.h" michael@0: #include "nsSVGEffects.h" michael@0: #include "ImageContainer.h" michael@0: michael@0: using namespace mozilla::layers; michael@0: michael@0: namespace mozilla { michael@0: michael@0: VideoFrameContainer::VideoFrameContainer(dom::HTMLMediaElement* aElement, michael@0: already_AddRefed aContainer) michael@0: : mElement(aElement), michael@0: mImageContainer(aContainer), mMutex("nsVideoFrameContainer"), michael@0: mIntrinsicSizeChanged(false), mImageSizeChanged(false) michael@0: { michael@0: NS_ASSERTION(aElement, "aElement must not be null"); michael@0: NS_ASSERTION(mImageContainer, "aContainer must not be null"); michael@0: } michael@0: michael@0: VideoFrameContainer::~VideoFrameContainer() michael@0: {} michael@0: michael@0: void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, michael@0: Image* aImage, michael@0: TimeStamp aTargetTime) michael@0: { michael@0: MutexAutoLock lock(mMutex); michael@0: michael@0: if (aIntrinsicSize != mIntrinsicSize) { michael@0: mIntrinsicSize = aIntrinsicSize; michael@0: mIntrinsicSizeChanged = true; michael@0: } michael@0: michael@0: gfx::IntSize oldFrameSize = mImageContainer->GetCurrentSize(); michael@0: TimeStamp lastPaintTime = mImageContainer->GetPaintTime(); michael@0: if (!lastPaintTime.IsNull() && !mPaintTarget.IsNull()) { michael@0: mPaintDelay = lastPaintTime - mPaintTarget; michael@0: } michael@0: michael@0: // When using the OMX decoder, destruction of the current image can indirectly michael@0: // block on main thread I/O. If we let this happen while holding onto michael@0: // |mImageContainer|'s lock, then when the main thread then tries to michael@0: // composite it can then block on |mImageContainer|'s lock, causing a michael@0: // deadlock. We use this hack to defer the destruction of the current image michael@0: // until it is safe. michael@0: nsRefPtr kungFuDeathGrip; michael@0: kungFuDeathGrip = mImageContainer->LockCurrentImage(); michael@0: mImageContainer->UnlockCurrentImage(); michael@0: michael@0: mImageContainer->SetCurrentImage(aImage); michael@0: gfx::IntSize newFrameSize = mImageContainer->GetCurrentSize(); michael@0: if (oldFrameSize != newFrameSize) { michael@0: mImageSizeChanged = true; michael@0: } michael@0: michael@0: mPaintTarget = aTargetTime; michael@0: } michael@0: michael@0: void VideoFrameContainer::Reset() michael@0: { michael@0: ClearCurrentFrame(true); michael@0: Invalidate(); michael@0: mIntrinsicSize = gfxIntSize(-1, -1); michael@0: mPaintDelay = mozilla::TimeDuration(); michael@0: mPaintTarget = mozilla::TimeStamp(); michael@0: mImageContainer->ResetPaintCount(); michael@0: } michael@0: michael@0: void VideoFrameContainer::ClearCurrentFrame(bool aResetSize) michael@0: { michael@0: MutexAutoLock lock(mMutex); michael@0: michael@0: // See comment in SetCurrentFrame for the reasoning behind michael@0: // using a kungFuDeathGrip here. michael@0: nsRefPtr kungFuDeathGrip; michael@0: kungFuDeathGrip = mImageContainer->LockCurrentImage(); michael@0: mImageContainer->UnlockCurrentImage(); michael@0: michael@0: mImageContainer->ClearAllImages(); michael@0: mImageSizeChanged = aResetSize; michael@0: } michael@0: michael@0: ImageContainer* VideoFrameContainer::GetImageContainer() { michael@0: return mImageContainer; michael@0: } michael@0: michael@0: michael@0: double VideoFrameContainer::GetFrameDelay() michael@0: { michael@0: MutexAutoLock lock(mMutex); michael@0: return mPaintDelay.ToSeconds(); michael@0: } michael@0: michael@0: void VideoFrameContainer::InvalidateWithFlags(uint32_t aFlags) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Must call on main thread"); michael@0: michael@0: if (!mElement) { michael@0: // Element has been destroyed michael@0: return; michael@0: } michael@0: michael@0: nsIFrame* frame = mElement->GetPrimaryFrame(); michael@0: bool invalidateFrame = false; michael@0: michael@0: { michael@0: MutexAutoLock lock(mMutex); michael@0: michael@0: // Get mImageContainerSizeChanged while holding the lock. michael@0: invalidateFrame = mImageSizeChanged; michael@0: mImageSizeChanged = false; michael@0: michael@0: if (mIntrinsicSizeChanged) { michael@0: mElement->UpdateMediaSize(mIntrinsicSize); michael@0: mIntrinsicSizeChanged = false; michael@0: michael@0: if (frame) { michael@0: nsPresContext* presContext = frame->PresContext(); michael@0: nsIPresShell *presShell = presContext->PresShell(); michael@0: presShell->FrameNeedsReflow(frame, michael@0: nsIPresShell::eStyleChange, michael@0: NS_FRAME_IS_DIRTY); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool asyncInvalidate = mImageContainer && michael@0: mImageContainer->IsAsync() && michael@0: !(aFlags & INVALIDATE_FORCE); michael@0: michael@0: if (frame) { michael@0: if (invalidateFrame) { michael@0: frame->InvalidateFrame(); michael@0: } else { michael@0: frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO, nullptr, michael@0: asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0); michael@0: } michael@0: } michael@0: michael@0: nsSVGEffects::InvalidateDirectRenderingObservers(mElement); michael@0: } michael@0: michael@0: }