Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "VideoFrameContainer.h"
9 #include "mozilla/dom/HTMLMediaElement.h"
10 #include "nsIFrame.h"
11 #include "nsDisplayList.h"
12 #include "nsSVGEffects.h"
13 #include "ImageContainer.h"
15 using namespace mozilla::layers;
17 namespace mozilla {
19 VideoFrameContainer::VideoFrameContainer(dom::HTMLMediaElement* aElement,
20 already_AddRefed<ImageContainer> aContainer)
21 : mElement(aElement),
22 mImageContainer(aContainer), mMutex("nsVideoFrameContainer"),
23 mIntrinsicSizeChanged(false), mImageSizeChanged(false)
24 {
25 NS_ASSERTION(aElement, "aElement must not be null");
26 NS_ASSERTION(mImageContainer, "aContainer must not be null");
27 }
29 VideoFrameContainer::~VideoFrameContainer()
30 {}
32 void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize,
33 Image* aImage,
34 TimeStamp aTargetTime)
35 {
36 MutexAutoLock lock(mMutex);
38 if (aIntrinsicSize != mIntrinsicSize) {
39 mIntrinsicSize = aIntrinsicSize;
40 mIntrinsicSizeChanged = true;
41 }
43 gfx::IntSize oldFrameSize = mImageContainer->GetCurrentSize();
44 TimeStamp lastPaintTime = mImageContainer->GetPaintTime();
45 if (!lastPaintTime.IsNull() && !mPaintTarget.IsNull()) {
46 mPaintDelay = lastPaintTime - mPaintTarget;
47 }
49 // When using the OMX decoder, destruction of the current image can indirectly
50 // block on main thread I/O. If we let this happen while holding onto
51 // |mImageContainer|'s lock, then when the main thread then tries to
52 // composite it can then block on |mImageContainer|'s lock, causing a
53 // deadlock. We use this hack to defer the destruction of the current image
54 // until it is safe.
55 nsRefPtr<Image> kungFuDeathGrip;
56 kungFuDeathGrip = mImageContainer->LockCurrentImage();
57 mImageContainer->UnlockCurrentImage();
59 mImageContainer->SetCurrentImage(aImage);
60 gfx::IntSize newFrameSize = mImageContainer->GetCurrentSize();
61 if (oldFrameSize != newFrameSize) {
62 mImageSizeChanged = true;
63 }
65 mPaintTarget = aTargetTime;
66 }
68 void VideoFrameContainer::Reset()
69 {
70 ClearCurrentFrame(true);
71 Invalidate();
72 mIntrinsicSize = gfxIntSize(-1, -1);
73 mPaintDelay = mozilla::TimeDuration();
74 mPaintTarget = mozilla::TimeStamp();
75 mImageContainer->ResetPaintCount();
76 }
78 void VideoFrameContainer::ClearCurrentFrame(bool aResetSize)
79 {
80 MutexAutoLock lock(mMutex);
82 // See comment in SetCurrentFrame for the reasoning behind
83 // using a kungFuDeathGrip here.
84 nsRefPtr<Image> kungFuDeathGrip;
85 kungFuDeathGrip = mImageContainer->LockCurrentImage();
86 mImageContainer->UnlockCurrentImage();
88 mImageContainer->ClearAllImages();
89 mImageSizeChanged = aResetSize;
90 }
92 ImageContainer* VideoFrameContainer::GetImageContainer() {
93 return mImageContainer;
94 }
97 double VideoFrameContainer::GetFrameDelay()
98 {
99 MutexAutoLock lock(mMutex);
100 return mPaintDelay.ToSeconds();
101 }
103 void VideoFrameContainer::InvalidateWithFlags(uint32_t aFlags)
104 {
105 NS_ASSERTION(NS_IsMainThread(), "Must call on main thread");
107 if (!mElement) {
108 // Element has been destroyed
109 return;
110 }
112 nsIFrame* frame = mElement->GetPrimaryFrame();
113 bool invalidateFrame = false;
115 {
116 MutexAutoLock lock(mMutex);
118 // Get mImageContainerSizeChanged while holding the lock.
119 invalidateFrame = mImageSizeChanged;
120 mImageSizeChanged = false;
122 if (mIntrinsicSizeChanged) {
123 mElement->UpdateMediaSize(mIntrinsicSize);
124 mIntrinsicSizeChanged = false;
126 if (frame) {
127 nsPresContext* presContext = frame->PresContext();
128 nsIPresShell *presShell = presContext->PresShell();
129 presShell->FrameNeedsReflow(frame,
130 nsIPresShell::eStyleChange,
131 NS_FRAME_IS_DIRTY);
132 }
133 }
134 }
136 bool asyncInvalidate = mImageContainer &&
137 mImageContainer->IsAsync() &&
138 !(aFlags & INVALIDATE_FORCE);
140 if (frame) {
141 if (invalidateFrame) {
142 frame->InvalidateFrame();
143 } else {
144 frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO, nullptr,
145 asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0);
146 }
147 }
149 nsSVGEffects::InvalidateDirectRenderingObservers(mElement);
150 }
152 }