Bug 1491212 part 3 - Have Document.exitFullscreen return a Promise. r=smaug
authorXidorn Quan <me@upsuper.org>
Mon, 17 Sep 2018 23:25:10 +0000
changeset 436906 32b021561f8cfd5e6911dfacb4372aa538d2b615
parent 436905 824f566f9043419551c6d035441928d6ba12ffac
child 436907 b444a3e482d851a920442aa10a56afd8f02540d3
push id34665
push userebalazs@mozilla.com
push dateTue, 18 Sep 2018 14:32:15 +0000
treeherdermozilla-central@d073607e0ffa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1491212
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1491212 part 3 - Have Document.exitFullscreen return a Promise. r=smaug Depends on D5989 Differential Revision: https://phabricator.services.mozilla.com/D5990
dom/base/FullscreenChange.h
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/html/test/file_fullscreen-api.html
dom/webidl/Document.webidl
testing/web-platform/meta/fullscreen/api/promises-reject.html.ini
testing/web-platform/meta/fullscreen/idlharness.window.js.ini
--- a/dom/base/FullscreenChange.h
+++ b/dom/base/FullscreenChange.h
@@ -146,11 +146,40 @@ private:
     , mElement(aElement)
     , mCallerType(aCallerType)
     , mShouldNotifyNewOrigin(aShouldNotifyNewOrigin)
   {
     MOZ_COUNT_CTOR(FullscreenRequest);
   }
 };
 
+class FullscreenExit : public FullscreenChange
+{
+public:
+  static const ChangeType kType = eExit;
+
+  static UniquePtr<FullscreenExit> Create(nsIDocument* aDoc, ErrorResult& aRv)
+  {
+    RefPtr<Promise> promise = Promise::Create(aDoc->GetOwnerGlobal(), aRv);
+    return WrapUnique(new FullscreenExit(aDoc, promise.forget()));
+  }
+
+  static UniquePtr<FullscreenExit> CreateForRemote(nsIDocument* aDoc)
+  {
+    return WrapUnique(new FullscreenExit(aDoc, nullptr));
+  }
+
+  ~FullscreenExit()
+  {
+    MOZ_COUNT_DTOR(FullscreenExit);
+  }
+
+private:
+  FullscreenExit(nsIDocument* aDoc, already_AddRefed<Promise> aPromise)
+    : FullscreenChange(kType, aDoc, std::move(aPromise))
+  {
+    MOZ_COUNT_CTOR(FullscreenExit);
+  }
+};
+
 } // namespace mozilla
 
 #endif // mozilla_FullscreenRequest_h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -10725,20 +10725,23 @@ nsIDocument::GetFullscreenRoot()
 }
 
 void
 nsIDocument::SetFullscreenRoot(nsIDocument* aRoot)
 {
   mFullscreenRoot = do_GetWeakReference(aRoot);
 }
 
-void
-nsIDocument::ExitFullscreen()
-{
-  RestorePreviousFullscreenState();
+already_AddRefed<Promise>
+nsIDocument::ExitFullscreen(ErrorResult& aRv)
+{
+  UniquePtr<FullscreenExit> exit = FullscreenExit::Create(this, aRv);
+  RefPtr<Promise> promise = exit->GetPromise();
+  RestorePreviousFullscreenState(std::move(exit));
+  return promise.forget();
 }
 
 static void
 AskWindowToExitFullscreen(nsIDocument* aDoc)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     nsContentUtils::DispatchEventOnlyToChrome(
       aDoc, ToSupports(aDoc), NS_LITERAL_STRING("MozDOMFullscreen:Exit"),
@@ -10900,16 +10903,24 @@ private:
 /* static */ void
 nsIDocument::ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
 {
   MOZ_ASSERT(aMaybeNotARootDoc);
 
   // Unlock the pointer
   UnlockPointer();
 
+  // Resolve all promises which waiting for exit fullscreen.
+  PendingFullscreenChangeList::Iterator<FullscreenExit> iter(
+    aMaybeNotARootDoc, PendingFullscreenChangeList::eDocumentsWithSameRoot);
+  while (!iter.AtEnd()) {
+    UniquePtr<FullscreenExit> exit = iter.TakeAndNext();
+    exit->MayResolvePromise();
+  }
+
   nsCOMPtr<nsIDocument> root = aMaybeNotARootDoc->GetFullscreenRoot();
   if (!root || !root->FullscreenStackTop()) {
     // If a document was detached before exiting from fullscreen, it is
     // possible that the root had left fullscreen state. In this case,
     // we would not get anything from the ResetFullscreen() call. Root's
     // not being a fullscreen doc also means the widget should have
     // exited fullscreen state. It means even if we do not return here,
     // we would actually do nothing below except crashing ourselves via
@@ -10943,22 +10954,23 @@ DispatchFullscreenNewOriginEvent(nsIDocu
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(
         aDoc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
         CanBubble::eYes, ChromeOnlyDispatch::eYes);
   asyncDispatcher->PostDOMEvent();
 }
 
 void
-nsIDocument::RestorePreviousFullscreenState()
+nsIDocument::RestorePreviousFullscreenState(UniquePtr<FullscreenExit> aExit)
 {
   NS_ASSERTION(!FullscreenStackTop() || !FullscreenRoots::IsEmpty(),
     "Should have at least 1 fullscreen root when fullscreen!");
 
   if (!FullscreenStackTop() || !GetWindow() || FullscreenRoots::IsEmpty()) {
+    aExit->MayRejectPromise();
     return;
   }
 
   nsCOMPtr<nsIDocument> fullScreenDoc = GetFullscreenLeaf(this);
   AutoTArray<Element*, 8> exitElements;
 
   nsIDocument* doc = fullScreenDoc;
   // Collect all subdocuments.
@@ -10989,16 +11001,17 @@ nsIDocument::RestorePreviousFullscreenSt
     }
   }
 
   nsIDocument* lastDoc = exitElements.LastElement()->OwnerDoc();
   if (!lastDoc->GetParentDocument() &&
       lastDoc->mFullscreenStack.Length() == 1) {
     // If we are fully exiting fullscreen, don't touch anything here,
     // just wait for the window to get out from fullscreen first.
+    PendingFullscreenChangeList::Add(std::move(aExit));
     AskWindowToExitFullscreen(this);
     return;
   }
 
   // If fullscreen mode is updated the pointer should be unlocked
   UnlockPointer();
   // All documents listed in the array except the last one are going to
   // completely exit from the fullscreen state.
@@ -11016,16 +11029,17 @@ nsIDocument::RestorePreviousFullscreenSt
     newFullscreenDoc = lastDoc->GetParentDocument();
   }
   // Dispatch the fullscreenchange event to all document listed. Note
   // that the loop order is reversed so that events are dispatched in
   // the tree order as indicated in the spec.
   for (Element* e : Reversed(exitElements)) {
     DispatchFullscreenChange(e->OwnerDoc(), e);
   }
+  aExit->MayResolvePromise();
 
   MOZ_ASSERT(newFullscreenDoc, "If we were going to exit from fullscreen on "
              "all documents in this doctree, we should've asked the window to "
              "exit first instead of reaching here.");
   if (fullScreenDoc != newFullscreenDoc &&
       !nsContentUtils::HaveEqualPrincipals(fullScreenDoc, newFullscreenDoc)) {
     // We've popped so enough off the stack that we've rolled back to
     // a fullscreen element in a parent document. If this document is
@@ -11224,17 +11238,18 @@ nsresult nsIDocument::RemoteFrameFullscr
   // this has no effect.
   auto request = FullscreenRequest::CreateForRemote(aFrameElement);
   RequestFullscreen(std::move(request));
   return NS_OK;
 }
 
 nsresult nsIDocument::RemoteFrameFullscreenReverted()
 {
-  RestorePreviousFullscreenState();
+  UniquePtr<FullscreenExit> exit = FullscreenExit::CreateForRemote(this);
+  RestorePreviousFullscreenState(std::move(exit));
   return NS_OK;
 }
 
 /* static */ bool
 nsIDocument::IsUnprefixedFullscreenEnabled(JSContext* aCx, JSObject* aObject)
 {
   MOZ_ASSERT(NS_IsMainThread());
   return nsContentUtils::IsSystemCaller(aCx) ||
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -121,16 +121,17 @@ class nsIXULWindow;
 
 namespace mozilla {
 class AbstractThread;
 class CSSStyleSheet;
 class Encoding;
 class ErrorResult;
 class EventStates;
 class EventListenerManager;
+class FullscreenExit;
 class FullscreenRequest;
 class PendingAnimationTracker;
 class ServoStyleSet;
 template<typename> class OwningNonNull;
 struct URLExtraData;
 
 namespace css {
 class Loader;
@@ -1806,17 +1807,18 @@ public:
    */
    nsresult RemoteFrameFullscreenReverted();
 
   /**
    * Restores the previous fullscreen element to fullscreen status. If there
    * is no former fullscreen element, this exits fullscreen, moving the
    * top-level browser window out of fullscreen mode.
    */
-  void RestorePreviousFullscreenState();
+  void RestorePreviousFullscreenState(
+    mozilla::UniquePtr<mozilla::FullscreenExit>);
 
   /**
    * Returns true if this document is a fullscreen leaf document, i.e. it
    * is in fullscreen mode and has no fullscreen children.
    */
   bool IsFullscreenLeaf();
 
   /**
@@ -3288,17 +3290,17 @@ public:
   nsIURI* GetDocumentURIObject() const;
   // Not const because all the fullscreen goop is not const
   bool FullscreenEnabled(mozilla::dom::CallerType aCallerType);
   Element* FullscreenStackTop();
   bool Fullscreen()
   {
     return !!GetFullscreenElement();
   }
-  void ExitFullscreen();
+  already_AddRefed<mozilla::dom::Promise> ExitFullscreen(ErrorResult&);
   void ExitPointerLock()
   {
     UnlockPointer(this);
   }
 
   static bool IsUnprefixedFullscreenEnabled(JSContext* aCx, JSObject* aObject);
 
 #ifdef MOZILLA_INTERNAL_API
--- a/dom/html/test/file_fullscreen-api.html
+++ b/dom/html/test/file_fullscreen-api.html
@@ -104,24 +104,25 @@ function enter2(event) {
      "Full-screen element should be iframe element.");
   is(iframe.contentDocument.fullscreenElement, iframe.contentDocument.body,
      "Full-screen element in subframe should be body");
   
   // The iframe's body is full-screen. Cancel full-screen in the subdocument to return
   // the full-screen element to the previous full-screen element. This causes
   // a fullscreenchange event.
   addFullscreenChangeContinuation("exit", exit2);
-  document.exitFullscreen();
+  promise = document.exitFullscreen();
 }
 
 function exit2(event) {
   is(document.fullscreenElement, null,
      "Full-screen element should have rolled back.");
   is(iframe.contentDocument.fullscreenElement, null,
      "Full-screen element in subframe should be null");
+  assertPromiseResolved(promise, "in exit2");
   
   addFullscreenChangeContinuation("enter", enter3);
   promise = FULLSCREEN_ELEMENT.requestFullscreen();
 }
 
 function enter3(event) {
   is(event.target, FULLSCREEN_ELEMENT,
      "Event target should be the fullscreen element #3");
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -264,20 +264,20 @@ partial interface Document {
   readonly attribute boolean fullscreen;
   [BinaryName="fullscreen"]
   readonly attribute boolean mozFullScreen;
   [LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled", NeedsCallerType]
   readonly attribute boolean fullscreenEnabled;
   [BinaryName="fullscreenEnabled", NeedsCallerType]
   readonly attribute boolean mozFullScreenEnabled;
 
-  [Func="nsDocument::IsUnprefixedFullscreenEnabled"]
-  void exitFullscreen();
-  [BinaryName="exitFullscreen"]
-  void mozCancelFullScreen();
+  [Throws, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
+  Promise<void> exitFullscreen();
+  [Throws, BinaryName="exitFullscreen"]
+  Promise<void> mozCancelFullScreen();
 
   // Events handlers
   [Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   attribute EventHandler onfullscreenchange;
   [Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   attribute EventHandler onfullscreenerror;
 };
 
deleted file mode 100644
--- a/testing/web-platform/meta/fullscreen/api/promises-reject.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[promises-reject.html]
-  [Promises#reject 1]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/fullscreen/idlharness.window.js.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[idlharness.window.html]
-  [Document interface: operation exitFullscreen()]
-    expected: FAIL
-