Bug 1423372 - Move MediaDecoder::BackgroundVideoDecodingPermissionObserver to its own file. r=jwwang

This class contains a bunch of Gecko DOM specific stuff, and it would make
keeping the copy of MediaDecoder in Servo up to date easier if the Gecko
DOM stuff wasn't in MediaDecoder (and the other classes we import).

MozReview-Commit-ID: 3dP1nrQ7sT3

--HG--
extra : rebase_source : 79040a8d3cff6ac946b20a99d68e57630ec60848
This commit is contained in:
Chris Pearce 2017-12-06 11:22:36 +13:00
Родитель f27fb376d0
Коммит 4d4bf4593d
5 изменённых файлов: 258 добавлений и 173 удалений

Просмотреть файл

@ -0,0 +1,198 @@
/* 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 "BackgroundVideoDecodingPermissionObserver.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "MediaDecoder.h"
#include "MediaPrefs.h"
#include "nsContentUtils.h"
#include "nsIDocument.h"
namespace mozilla {
BackgroundVideoDecodingPermissionObserver::
BackgroundVideoDecodingPermissionObserver(MediaDecoder* aDecoder)
: mDecoder(aDecoder)
, mIsRegisteredForEvent(false)
{
MOZ_ASSERT(mDecoder);
}
NS_IMETHODIMP
BackgroundVideoDecodingPermissionObserver::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (!MediaPrefs::ResumeVideoDecodingOnTabHover()) {
return NS_OK;
}
if (!IsValidEventSender(aSubject)) {
return NS_OK;
}
if (strcmp(aTopic, "unselected-tab-hover") == 0) {
bool allowed = !NS_strcmp(aData, u"true");
mDecoder->SetIsBackgroundVideoDecodingAllowed(allowed);
}
return NS_OK;
}
void
BackgroundVideoDecodingPermissionObserver::RegisterEvent()
{
MOZ_ASSERT(!mIsRegisteredForEvent);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, "unselected-tab-hover", false);
mIsRegisteredForEvent = true;
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(
TaskCategory::Other,
NewRunnableMethod(
"BackgroundVideoDecodingPermissionObserver::"
"EnableEvent",
this,
&BackgroundVideoDecodingPermissionObserver::
EnableEvent));
}
} else {
EnableEvent();
}
}
}
void
BackgroundVideoDecodingPermissionObserver::UnregisterEvent()
{
MOZ_ASSERT(mIsRegisteredForEvent);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, "unselected-tab-hover");
mIsRegisteredForEvent = false;
mDecoder->SetIsBackgroundVideoDecodingAllowed(false);
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(
TaskCategory::Other,
NewRunnableMethod(
"BackgroundVideoDecodingPermissionObserver::"
"DisableEvent",
this,
&BackgroundVideoDecodingPermissionObserver::
DisableEvent));
}
} else {
DisableEvent();
}
}
}
BackgroundVideoDecodingPermissionObserver::
~BackgroundVideoDecodingPermissionObserver()
{
MOZ_ASSERT(!mIsRegisteredForEvent);
}
void
BackgroundVideoDecodingPermissionObserver::EnableEvent() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return;
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc,
NS_LITERAL_STRING("UnselectedTabHover:Enable"),
/* Bubbles */ true,
/* OnlyChromeDispatch */ true);
asyncDispatcher->PostDOMEvent();
}
void
BackgroundVideoDecodingPermissionObserver::DisableEvent() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return;
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc,
NS_LITERAL_STRING("UnselectedTabHover:Disable"),
/* Bubbles */ true,
/* OnlyChromeDispatch */ true);
asyncDispatcher->PostDOMEvent();
}
already_AddRefed<nsPIDOMWindowOuter>
BackgroundVideoDecodingPermissionObserver::GetOwnerWindow() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowInner> innerWin = doc->GetInnerWindow();
if (!innerWin) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> outerWin = innerWin->GetOuterWindow();
if (!outerWin) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> topWin = outerWin->GetTop();
return topWin.forget();
}
nsIDocument*
BackgroundVideoDecodingPermissionObserver::GetOwnerDoc() const
{
if (!mDecoder->GetOwner()) {
return nullptr;
}
return mDecoder->GetOwner()->GetDocument();
}
bool
BackgroundVideoDecodingPermissionObserver::IsValidEventSender(
nsISupports* aSubject) const
{
nsCOMPtr<nsPIDOMWindowInner> senderInner(do_QueryInterface(aSubject));
if (!senderInner) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> senderOuter = senderInner->GetOuterWindow();
if (!senderOuter) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> senderTop = senderOuter->GetTop();
if (!senderTop) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> ownerTop = GetOwnerWindow();
if (!ownerTop) {
return false;
}
return ownerTop == senderTop;
}
NS_IMPL_ISUPPORTS(BackgroundVideoDecodingPermissionObserver, nsIObserver)
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,48 @@
/* 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/. */
#if !defined(BackgroundVideoDecodingPermissionObserver_h_)
#define BackgroundVideoDecodingPermissionObserver_h_
#include "nsIObserver.h"
#include "nsISupportsImpl.h"
class nsIDocument;
class nsISupports;
class nsPIDOMWindowOuter;
namespace mozilla {
class MediaDecoder;
class BackgroundVideoDecodingPermissionObserver final
: public nsIObserver
{
public:
NS_DECL_ISUPPORTS
explicit BackgroundVideoDecodingPermissionObserver(MediaDecoder* aDecoder);
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) override;
void RegisterEvent();
void UnregisterEvent();
private:
~BackgroundVideoDecodingPermissionObserver();
void EnableEvent() const;
void DisableEvent() const;
already_AddRefed<nsPIDOMWindowOuter> GetOwnerWindow() const;
nsIDocument* GetOwnerDoc() const;
bool IsValidEventSender(nsISupports* aSubject) const;
// The life cycle of observer would always be shorter than decoder, so we
// use raw pointer here.
MediaDecoder* mDecoder;
bool mIsRegisteredForEvent;
};
} // namespace mozilla
#endif // BackgroundVideoDecodingPermissionObserver_h_

Просмотреть файл

@ -15,7 +15,6 @@
#include "VideoFrameContainer.h"
#include "VideoUtils.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Preferences.h"
@ -123,177 +122,6 @@ public:
}
};
class MediaDecoder::BackgroundVideoDecodingPermissionObserver final :
public nsIObserver
{
public:
NS_DECL_ISUPPORTS
explicit BackgroundVideoDecodingPermissionObserver(MediaDecoder* aDecoder)
: mDecoder(aDecoder)
, mIsRegisteredForEvent(false)
{
MOZ_ASSERT(mDecoder);
}
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) override
{
if (!MediaPrefs::ResumeVideoDecodingOnTabHover()) {
return NS_OK;
}
if (!IsValidEventSender(aSubject)) {
return NS_OK;
}
if (strcmp(aTopic, "unselected-tab-hover") == 0) {
mDecoder->mIsBackgroundVideoDecodingAllowed = !NS_strcmp(aData, u"true");
mDecoder->UpdateVideoDecodeMode();
}
return NS_OK;
}
void RegisterEvent() {
MOZ_ASSERT(!mIsRegisteredForEvent);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, "unselected-tab-hover", false);
mIsRegisteredForEvent = true;
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(TaskCategory::Other,
NewRunnableMethod(
"MediaDecoder::BackgroundVideoDecodingPermissionObserver::EnableEvent",
this, &MediaDecoder::BackgroundVideoDecodingPermissionObserver::EnableEvent));
}
} else {
EnableEvent();
}
}
}
void UnregisterEvent() {
MOZ_ASSERT(mIsRegisteredForEvent);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, "unselected-tab-hover");
mIsRegisteredForEvent = false;
mDecoder->mIsBackgroundVideoDecodingAllowed = false;
mDecoder->UpdateVideoDecodeMode();
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(TaskCategory::Other,
NewRunnableMethod(
"MediaDecoder::BackgroundVideoDecodingPermissionObserver::DisableEvent",
this, &MediaDecoder::BackgroundVideoDecodingPermissionObserver::DisableEvent));
}
} else {
DisableEvent();
}
}
}
private:
~BackgroundVideoDecodingPermissionObserver() {
MOZ_ASSERT(!mIsRegisteredForEvent);
}
void EnableEvent() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return;
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc,
NS_LITERAL_STRING("UnselectedTabHover:Enable"),
/* Bubbles */ true,
/* OnlyChromeDispatch */ true);
asyncDispatcher->PostDOMEvent();
}
void DisableEvent() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return;
}
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc,
NS_LITERAL_STRING("UnselectedTabHover:Disable"),
/* Bubbles */ true,
/* OnlyChromeDispatch */ true);
asyncDispatcher->PostDOMEvent();
}
already_AddRefed<nsPIDOMWindowOuter> GetOwnerWindow() const
{
nsIDocument* doc = GetOwnerDoc();
if (!doc) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowInner> innerWin = doc->GetInnerWindow();
if (!innerWin) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> outerWin = innerWin->GetOuterWindow();
if (!outerWin) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> topWin = outerWin->GetTop();
return topWin.forget();
}
nsIDocument* GetOwnerDoc() const
{
if (!mDecoder->mOwner) {
return nullptr;
}
return mDecoder->mOwner->GetDocument();
}
bool IsValidEventSender(nsISupports* aSubject) const
{
nsCOMPtr<nsPIDOMWindowInner> senderInner(do_QueryInterface(aSubject));
if (!senderInner) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> senderOuter = senderInner->GetOuterWindow();
if (!senderOuter) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> senderTop = senderOuter->GetTop();
if (!senderTop) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> ownerTop = GetOwnerWindow();
if (!ownerTop) {
return false;
}
return ownerTop == senderTop;
}
// The life cycle of observer would always be shorter than decoder, so we
// use raw pointer here.
MediaDecoder* mDecoder;
bool mIsRegisteredForEvent;
};
NS_IMPL_ISUPPORTS(MediaDecoder::BackgroundVideoDecodingPermissionObserver, nsIObserver)
StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
LazyLogModule gMediaTimerLog("MediaTimer");
@ -1200,6 +1028,13 @@ MediaDecoder::UpdateVideoDecodeMode()
}
}
void
MediaDecoder::SetIsBackgroundVideoDecodingAllowed(bool aAllowed)
{
mIsBackgroundVideoDecodingAllowed = aAllowed;
UpdateVideoDecodeMode();
}
bool
MediaDecoder::HasSuspendTaint() const
{

Просмотреть файл

@ -7,6 +7,7 @@
#if !defined(MediaDecoder_h_)
#define MediaDecoder_h_
#include "BackgroundVideoDecodingPermissionObserver.h"
#include "DecoderDoctorDiagnostics.h"
#include "MediaContainerType.h"
#include "MediaDecoderOwner.h"
@ -306,6 +307,8 @@ private:
void UpdateVideoDecodeMode();
void SetIsBackgroundVideoDecodingAllowed(bool aAllowed);
/******
* The following methods must only be called on the main
* thread.
@ -641,7 +644,6 @@ protected:
// We can allow video decoding in background when we match some special
// conditions, eg. when the cursor is hovering over the tab. This observer is
// used to listen the related events.
class BackgroundVideoDecodingPermissionObserver;
RefPtr<BackgroundVideoDecodingPermissionObserver> mVideoDecodingOberver;
// True if we want to resume video decoding even the media element is in the

Просмотреть файл

@ -99,6 +99,7 @@ EXPORTS += [
'AudioSegment.h',
'AudioStream.h',
'AutoplayPolicy.h',
'BackgroundVideoDecodingPermissionObserver.h',
'Benchmark.h',
'BitReader.h',
'BufferMediaResource.h',
@ -215,6 +216,7 @@ UNIFIED_SOURCES += [
'AudioTrack.cpp',
'AudioTrackList.cpp',
'AutoplayPolicy.cpp',
'BackgroundVideoDecodingPermissionObserver.cpp',
'BaseMediaResource.cpp',
'Benchmark.cpp',
'BitReader.cpp',