Implements the gecko-parts of Picture In Picture API, to which the various platforms can add their implementation for opening a PIP Window to. nsIPictureInPictureFunctions.idl shall be implemented by the different platforms. For desktop we already have a "native" PIP implementation and this will be re-used. Platforms which does not implement nsIPictureInPictureFunctions.idl, will signal that they don't support it (and attempts to request via the API algorithms, will reject accordingly). Differential Revision: https://phabricator.services.mozilla.com/D286141
118 lines
4.1 KiB
C++
118 lines
4.1 KiB
C++
/* 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 "PictureInPictureWindow.h"
|
|
|
|
#include "PictureInPictureService.h"
|
|
#include "mozilla/AsyncEventDispatcher.h"
|
|
#include "mozilla/EventDispatcher.h"
|
|
#include "mozilla/dom/HTMLVideoElement.h"
|
|
#include "mozilla/dom/PictureInPictureWindowBinding.h"
|
|
|
|
namespace mozilla::dom {
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(PictureInPictureWindow, DOMEventTargetHelper)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(PictureInPictureWindow, DOMEventTargetHelper)
|
|
NS_IMPL_RELEASE_INHERITED(PictureInPictureWindow, DOMEventTargetHelper)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PictureInPictureWindow)
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
/* static */
|
|
bool PictureInPictureWindow::PictureInPictureEnabled() {
|
|
return StaticPrefs::dom_media_pip_enabled() &&
|
|
PictureInPictureService::IsSupported();
|
|
}
|
|
|
|
PictureInPictureWindow::PictureInPictureWindow(nsPIDOMWindowInner* aWindow,
|
|
HTMLVideoElement* aVideoElement)
|
|
: DOMEventTargetHelper(aWindow), mAssociatedVideoElement(aVideoElement) {
|
|
MOZ_ASSERT(aWindow);
|
|
MOZ_ASSERT(aVideoElement);
|
|
}
|
|
|
|
PictureInPictureWindow::~PictureInPictureWindow() = default;
|
|
|
|
JSObject* PictureInPictureWindow::WrapObject(
|
|
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
|
|
return PictureInPictureWindow_Binding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
int32_t PictureInPictureWindow::Width() const {
|
|
// The width attribute MUST return the width in CSS pixels of the
|
|
// Picture-in-Picture window associated with pictureInPictureElement if the
|
|
// state is opened. Otherwise, it MUST return 0.
|
|
if (!IsStateOpened()) {
|
|
return 0;
|
|
}
|
|
return mWidth;
|
|
}
|
|
|
|
int32_t PictureInPictureWindow::Height() const {
|
|
// The height attribute MUST return the height in CSS pixels of the
|
|
// Picture-in-Picture window associated with pictureInPictureElement if the
|
|
// state is opened. Otherwise, it MUST return 0.
|
|
if (!IsStateOpened()) {
|
|
return 0;
|
|
}
|
|
return mHeight;
|
|
}
|
|
|
|
void PictureInPictureWindow::NotifyDimensionsChanged(int32_t aWidth,
|
|
int32_t aHeight) {
|
|
mWidth = aWidth;
|
|
mHeight = aHeight;
|
|
|
|
// When the size of a Picture-in-Picture window pipWindow changes,
|
|
// the user agent MUST queue a task to fire an event named resize at
|
|
// pipWindow.
|
|
NS_DispatchToMainThread(
|
|
NS_NewRunnableFunction(__func__, [self = RefPtr{this}]() {
|
|
RefPtr<Event> event = NS_NewDOMEvent(self, nullptr, nullptr);
|
|
event->InitEvent(u"resize"_ns, false, false);
|
|
event->SetTrusted(true);
|
|
self->DispatchEvent(*event);
|
|
}));
|
|
}
|
|
|
|
void PictureInPictureWindow::Close() {
|
|
if (!mOpened) {
|
|
return;
|
|
}
|
|
mOpened = false;
|
|
|
|
// mAssociatedVideoElement is a WeakPtr; the video may already have been
|
|
// collected if its document was orphaned and released. If so, there's
|
|
// no PiP state to clear and no listener to fire the event at.
|
|
RefPtr<HTMLVideoElement> videoElement = mAssociatedVideoElement.get();
|
|
mAssociatedVideoElement = nullptr;
|
|
if (!videoElement) {
|
|
return;
|
|
}
|
|
|
|
videoElement->RemoveStates(ElementState::PICTURE_IN_PICTURE);
|
|
|
|
PictureInPictureEventInit eventInit;
|
|
eventInit.mBubbles = true;
|
|
eventInit.mCancelable = false;
|
|
eventInit.mPictureInPictureWindow = this;
|
|
|
|
RefPtr<PictureInPictureEvent> pipEvent = PictureInPictureEvent::Constructor(
|
|
this, u"leavepictureinpicture"_ns, eventInit);
|
|
pipEvent->SetTrusted(true);
|
|
|
|
// https://w3c.github.io/picture-in-picture/#exit-pip
|
|
// 3. Queue a task to fire an event named leavepictureinpicture using
|
|
// PictureInPictureEvent at the video with its bubbles attribute
|
|
// initialized to true and its pictureInPictureWindow attribute
|
|
// initialized to Picture-in-Picture window associated with
|
|
// pictureInPictureElement.
|
|
MakeRefPtr<AsyncEventDispatcher>(videoElement, pipEvent.forget(),
|
|
ChromeOnlyDispatch::eNo)
|
|
->PostDOMEvent();
|
|
}
|
|
|
|
} // namespace mozilla::dom
|