diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/presentation/PresentationAvailability.cpp | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/presentation/PresentationAvailability.cpp')
-rw-r--r-- | dom/presentation/PresentationAvailability.cpp | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/dom/presentation/PresentationAvailability.cpp b/dom/presentation/PresentationAvailability.cpp new file mode 100644 index 0000000000..ba816f975a --- /dev/null +++ b/dom/presentation/PresentationAvailability.cpp @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "PresentationAvailability.h" + +#include "mozilla/dom/PresentationAvailabilityBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/Logging.h" +#include "mozilla/Unused.h" +#include "nsContentUtils.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIPresentationService.h" +#include "nsServiceManagerUtils.h" +#include "AvailabilityCollection.h" +#include "PresentationLog.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationAvailability) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationAvailability, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromises) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationAvailability, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromises); + tmp->Shutdown(); + NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_ADDREF_INHERITED(PresentationAvailability, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(PresentationAvailability, DOMEventTargetHelper) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PresentationAvailability) + NS_INTERFACE_MAP_ENTRY(nsIPresentationAvailabilityListener) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +/* static */ +already_AddRefed<PresentationAvailability> PresentationAvailability::Create( + nsPIDOMWindowInner* aWindow, const nsTArray<nsString>& aUrls, + RefPtr<Promise>& aPromise) { + RefPtr<PresentationAvailability> availability = + new PresentationAvailability(aWindow, aUrls); + return NS_WARN_IF(!availability->Init(aPromise)) ? nullptr + : availability.forget(); +} + +PresentationAvailability::PresentationAvailability( + nsPIDOMWindowInner* aWindow, const nsTArray<nsString>& aUrls) + : DOMEventTargetHelper(aWindow), mIsAvailable(false), mUrls(aUrls.Clone()) { + for (uint32_t i = 0; i < mUrls.Length(); ++i) { + mAvailabilityOfUrl.AppendElement(false); + } +} + +PresentationAvailability::~PresentationAvailability() { Shutdown(); } + +bool PresentationAvailability::Init(RefPtr<Promise>& aPromise) { + nsCOMPtr<nsIPresentationService> service = + do_GetService(PRESENTATION_SERVICE_CONTRACTID); + if (NS_WARN_IF(!service)) { + return false; + } + + nsresult rv = service->RegisterAvailabilityListener(mUrls, this); + if (NS_WARN_IF(NS_FAILED(rv))) { + // If the user agent is unable to monitor available device, + // Resolve promise with |value| set to false. + mIsAvailable = false; + aPromise->MaybeResolve(this); + return true; + } + + EnqueuePromise(aPromise); + + AvailabilityCollection* collection = AvailabilityCollection::GetSingleton(); + if (collection) { + collection->Add(this); + } + + return true; +} + +void PresentationAvailability::Shutdown() { + AvailabilityCollection* collection = AvailabilityCollection::GetSingleton(); + if (collection) { + collection->Remove(this); + } + + nsCOMPtr<nsIPresentationService> service = + do_GetService(PRESENTATION_SERVICE_CONTRACTID); + if (NS_WARN_IF(!service)) { + return; + } + + Unused << NS_WARN_IF( + NS_FAILED(service->UnregisterAvailabilityListener(mUrls, this))); +} + +/* virtual */ +void PresentationAvailability::DisconnectFromOwner() { + Shutdown(); + DOMEventTargetHelper::DisconnectFromOwner(); +} + +/* virtual */ +JSObject* PresentationAvailability::WrapObject( + JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { + return PresentationAvailability_Binding::Wrap(aCx, this, aGivenProto); +} + +bool PresentationAvailability::Equals(const uint64_t aWindowID, + const nsTArray<nsString>& aUrls) const { + if (GetOwner() && GetOwner()->WindowID() == aWindowID && + mUrls.Length() == aUrls.Length()) { + for (const auto& url : aUrls) { + if (!mUrls.Contains(url)) { + return false; + } + } + return true; + } + + return false; +} + +bool PresentationAvailability::IsCachedValueReady() { + // All pending promises will be solved when cached value is ready and + // no promise should be enqueued afterward. + return mPromises.IsEmpty(); +} + +void PresentationAvailability::EnqueuePromise(RefPtr<Promise>& aPromise) { + mPromises.AppendElement(aPromise); +} + +bool PresentationAvailability::Value() const { + if (nsContentUtils::ShouldResistFingerprinting()) { + return false; + } + + return mIsAvailable; +} + +NS_IMETHODIMP +PresentationAvailability::NotifyAvailableChange( + const nsTArray<nsString>& aAvailabilityUrls, bool aIsAvailable) { + bool available = false; + for (uint32_t i = 0; i < mUrls.Length(); ++i) { + if (aAvailabilityUrls.Contains(mUrls[i])) { + mAvailabilityOfUrl[i] = aIsAvailable; + } + available |= mAvailabilityOfUrl[i]; + } + + return NS_DispatchToCurrentThread(NewRunnableMethod<bool>( + "dom::PresentationAvailability::UpdateAvailabilityAndDispatchEvent", this, + &PresentationAvailability::UpdateAvailabilityAndDispatchEvent, + available)); +} + +void PresentationAvailability::UpdateAvailabilityAndDispatchEvent( + bool aIsAvailable) { + PRES_DEBUG("%s\n", __func__); + bool isChanged = (aIsAvailable != mIsAvailable); + + mIsAvailable = aIsAvailable; + + if (!mPromises.IsEmpty()) { + // Use the first availability change notification to resolve promise. + do { + nsTArray<RefPtr<Promise>> promises = std::move(mPromises); + + if (nsContentUtils::ShouldResistFingerprinting()) { + continue; + } + + for (auto& promise : promises) { + promise->MaybeResolve(this); + } + // more promises may have been added to mPromises, at least in theory + } while (!mPromises.IsEmpty()); + + return; + } + + if (nsContentUtils::ShouldResistFingerprinting()) { + return; + } + + if (isChanged) { + Unused << NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(u"change"_ns))); + } +} + +} // namespace dom +} // namespace mozilla |