Bug 1500257 part 5 - Implement messages for loading and displaying remote subframes on PRemoteFrame. r=qdot
☠☠ backed out by aba99f466d44 ☠ ☠
authorRyan Hunt <rhunt@eqrion.net>
Wed, 23 Jan 2019 11:04:26 -0600
changeset 458418 c19bc81c4f43a5adba92184b2572c09c6c5a0680
parent 458417 697a9159e0d260118ee6ebd34948d187a8c5359f
child 458419 caafb04b7dd44d607adfa1f5f5cabcd42e367cf4
push id111822
push userrhunt@eqrion.net
push dateSun, 10 Feb 2019 01:34:27 +0000
treeherdermozilla-inbound@6097503e6300 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs1500257
milestone67.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 1500257 part 5 - Implement messages for loading and displaying remote subframes on PRemoteFrame. r=qdot This commit hooks up the pieces of the PRemoteFrame protocol that will proxy initialization, sizing, and display messages. The messages chosen are just enough to start the frame and get an initial rendering. Differential Revision: https://phabricator.services.mozilla.com/D17445
dom/base/nsFrameLoader.cpp
dom/ipc/PRemoteFrame.ipdl
dom/ipc/RemoteFrameChild.cpp
dom/ipc/RemoteFrameChild.h
dom/ipc/RemoteFrameParent.cpp
dom/ipc/RemoteFrameParent.h
dom/ipc/TabParent.h
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -351,18 +351,24 @@ nsresult nsFrameLoader::ReallyStartLoadi
   AUTO_PROFILER_LABEL("nsFrameLoader::ReallyStartLoadingInternal", OTHER);
 
   if (IsRemoteFrame()) {
     if (!mRemoteBrowser && !mRemoteFrameChild && !TryRemoteBrowser()) {
       NS_WARNING("Couldn't create child process for iframe.");
       return NS_ERROR_FAILURE;
     }
 
-    // FIXME get error codes from child
-    mRemoteBrowser->LoadURL(mURIToLoad);
+    if (mRemoteFrameChild) {
+      nsAutoCString spec;
+      mURIToLoad->GetSpec(spec);
+      Unused << mRemoteFrameChild->SendLoadURL(spec);
+    } else {
+      // FIXME get error codes from child
+      mRemoteBrowser->LoadURL(mURIToLoad);
+    }
 
     if (!mRemoteBrowserShown) {
       // This can fail if it's too early to show the frame, we will retry later.
       Unused << ShowRemoteFrame(ScreenIntSize(0, 0));
     }
 
     return NS_OK;
   }
@@ -806,22 +812,35 @@ bool nsFrameLoader::ShowRemoteFrame(cons
     }
 
     // We never want to host remote frameloaders in simple popups, like menus.
     nsIWidget* widget = nsContentUtils::WidgetForContent(mOwnerContent);
     if (!widget || static_cast<nsBaseWidget*>(widget)->IsSmallPopup()) {
       return false;
     }
 
-    RenderFrame* rf = GetCurrentRenderFrame();
-    if (!rf) {
-      return false;
+    if (mRemoteFrameChild) {
+      nsCOMPtr<nsISupports> container =
+          mOwnerContent->OwnerDoc()->GetContainer();
+      nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
+      nsCOMPtr<nsIWidget> mainWidget;
+      baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
+      nsSizeMode sizeMode =
+          mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal;
+
+      Unused << mRemoteFrameChild->SendShow(
+          size, ParentWindowIsActive(mOwnerContent->OwnerDoc()), sizeMode);
+      mRemoteBrowserShown = true;
+      return true;
     }
 
-    if (!rf->AttachLayerManager()) {
+    RenderFrame* rf =
+        mRemoteBrowser ? mRemoteBrowser->GetRenderFrame() : nullptr;
+
+    if (!rf || !rf->AttachLayerManager()) {
       // This is just not going to work.
       return false;
     }
 
     mRemoteBrowser->Show(size, ParentWindowIsActive(mOwnerContent->OwnerDoc()));
     mRemoteBrowserShown = true;
 
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
@@ -829,17 +848,21 @@ bool nsFrameLoader::ShowRemoteFrame(cons
       os->NotifyObservers(ToSupports(this), "remote-browser-shown", nullptr);
     }
   } else {
     nsIntRect dimensions;
     NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
 
     // Don't show remote iframe if we are waiting for the completion of reflow.
     if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
-      mRemoteBrowser->UpdateDimensions(dimensions, size);
+      if (mRemoteBrowser) {
+        mRemoteBrowser->UpdateDimensions(dimensions, size);
+      } else if (mRemoteFrameChild) {
+        mRemoteFrameChild->UpdateDimensions(dimensions, size);
+      }
     }
   }
 
   return true;
 }
 
 void nsFrameLoader::Hide() {
   if (mHideCalled) {
@@ -918,16 +941,21 @@ nsresult nsFrameLoader::SwapWithOtherRem
   }
 
   nsIPresShell* ourShell = ourDoc->GetShell();
   nsIPresShell* otherShell = otherDoc->GetShell();
   if (!ourShell || !otherShell) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
+  // FIXME: Consider supporting FrameLoader swapping for remote sub frames.
+  if (mRemoteFrameChild) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
   if (!mRemoteBrowser || !aOther->mRemoteBrowser) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   if (mRemoteBrowser->IsIsolatedMozBrowserElement() !=
       aOther->mRemoteBrowser->IsIsolatedMozBrowserElement()) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
@@ -2281,27 +2309,31 @@ nsresult nsFrameLoader::GetWindowDimensi
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_GetInterface(parentOwner));
   treeOwnerAsWin->GetPosition(&aRect.x, &aRect.y);
   treeOwnerAsWin->GetSize(&aRect.width, &aRect.height);
   return NS_OK;
 }
 
 nsresult nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame* aIFrame) {
   if (IsRemoteFrame()) {
-    if (mRemoteBrowser) {
+    if (mRemoteBrowser || mRemoteFrameChild) {
       ScreenIntSize size = aIFrame->GetSubdocumentSize();
       // If we were not able to show remote frame before, we should probably
       // retry now to send correct showInfo.
       if (!mRemoteBrowserShown) {
         ShowRemoteFrame(size, aIFrame);
       }
       nsIntRect dimensions;
       NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
       mLazySize = size;
-      mRemoteBrowser->UpdateDimensions(dimensions, size);
+      if (mRemoteBrowser) {
+        mRemoteBrowser->UpdateDimensions(dimensions, size);
+      } else if (mRemoteFrameChild) {
+        mRemoteFrameChild->UpdateDimensions(dimensions, size);
+      }
     }
     return NS_OK;
   }
   UpdateBaseWindowPositionAndSize(aIFrame);
   return NS_OK;
 }
 
 void nsFrameLoader::UpdateBaseWindowPositionAndSize(
--- a/dom/ipc/PRemoteFrame.ipdl
+++ b/dom/ipc/PRemoteFrame.ipdl
@@ -3,23 +3,40 @@
 /* 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 protocol PBrowser;
 
 include DOMTypes;
 
+using ScreenIntSize from "Units.h";
+using nsSizeMode from "nsIWidgetListener.h";
+using mozilla::layers::LayersObserverEpoch from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::LayersId from "mozilla/layers/LayersTypes.h";
+
 namespace mozilla {
 namespace dom {
 
 /**
  * PRemoteFrame corresponds to a remote iframe.
  */
 async protocol PRemoteFrame {
   manager PBrowser;
+
+child:
+  async SetLayersId(LayersId layersId);
+
 parent:
   // Destroy the remote web browser due to the nsFrameLoader going away.
   async __delete__();
+
+  // DocShell messaging.
+  async LoadURL(nsCString aSpec);
+
+  // Out of process rendering.
+  async Show(ScreenIntSize size, bool parentIsActive, nsSizeMode sizeMode);
+  async UpdateDimensions(DimensionInfo dimensions) compressall;
+  async RenderLayers(bool aEnabled, bool aForceRepaint, LayersObserverEpoch aEpoch);
 };
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/RemoteFrameChild.cpp
+++ b/dom/ipc/RemoteFrameChild.cpp
@@ -36,14 +36,53 @@ already_AddRefed<RemoteFrameChild> Remot
   tabChild->SendPRemoteFrameConstructor(
       do_AddRef(remoteFrame).take(),
       PromiseFlatString(aContext.PresentationURL()), aRemoteType);
   remoteFrame->mIPCOpen = true;
 
   return remoteFrame.forget();
 }
 
+void RemoteFrameChild::UpdateDimensions(const nsIntRect& aRect,
+                                        const mozilla::ScreenIntSize& aSize) {
+  MOZ_DIAGNOSTIC_ASSERT(mIPCOpen);
+
+  RefPtr<Element> owner = mFrameLoader->GetOwnerContent();
+  nsCOMPtr<nsIWidget> widget = nsContentUtils::WidgetForContent(owner);
+  if (!widget) {
+    widget = nsContentUtils::WidgetForDocument(owner->OwnerDoc());
+  }
+  MOZ_DIAGNOSTIC_ASSERT(widget);
+
+  CSSToLayoutDeviceScale widgetScale = widget->GetDefaultScale();
+
+  LayoutDeviceIntRect devicePixelRect = ViewAs<LayoutDevicePixel>(
+      aRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
+  LayoutDeviceIntSize devicePixelSize = ViewAs<LayoutDevicePixel>(
+      aSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
+
+  // XXX What are clientOffset and chromeOffset used for? Are they meaningful
+  // for nested iframes with transforms?
+  LayoutDeviceIntPoint clientOffset;
+  LayoutDeviceIntPoint chromeOffset;
+
+  CSSRect unscaledRect = devicePixelRect / widgetScale;
+  CSSSize unscaledSize = devicePixelSize / widgetScale;
+  hal::ScreenOrientation orientation = hal::eScreenOrientation_Default;
+  DimensionInfo di(unscaledRect, unscaledSize, orientation, clientOffset,
+                   chromeOffset);
+
+  Unused << SendUpdateDimensions(di);
+}
+
+IPCResult RemoteFrameChild::RecvSetLayersId(
+    const mozilla::layers::LayersId& aLayersId) {
+  MOZ_ASSERT(!mLayersId.IsValid() && aLayersId.IsValid());
+  mLayersId = aLayersId;
+  return IPC_OK();
+}
+
 void RemoteFrameChild::ActorDestroy(ActorDestroyReason aWhy) {
   mIPCOpen = false;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/RemoteFrameChild.h
+++ b/dom/ipc/RemoteFrameChild.h
@@ -25,17 +25,26 @@ class RemoteFrameChild : public PRemoteF
     return static_cast<TabChild*>(PRemoteFrameChild::Manager());
   }
 
   mozilla::layers::LayersId GetLayersId() { return mLayersId; }
 
   static already_AddRefed<RemoteFrameChild> Create(nsFrameLoader* aFrameLoader,
                                                    const TabContext& aContext,
                                                    const nsString& aRemoteType);
+
+  void UpdateDimensions(const nsIntRect& aRect,
+                        const mozilla::ScreenIntSize& aSize);
+
  protected:
+  friend class PRemoteFrameChild;
+
+  mozilla::ipc::IPCResult RecvSetLayersId(
+      const mozilla::layers::LayersId& aLayersId);
+
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   explicit RemoteFrameChild(nsFrameLoader* aFrameLoader);
   ~RemoteFrameChild();
 
   mozilla::layers::LayersId mLayersId;
   bool mIPCOpen;
--- a/dom/ipc/RemoteFrameParent.cpp
+++ b/dom/ipc/RemoteFrameParent.cpp
@@ -64,17 +64,56 @@ nsresult RemoteFrameParent::Init(const n
     return NS_ERROR_FAILURE;
   }
 
   // Set our TabParent object to the newly created browser.
   mTabParent = TabParent::GetFrom(browser);
   mTabParent->SetOwnerElement(Manager()->GetOwnerElement());
   mTabParent->InitRendering();
 
+  RenderFrame* rf = mTabParent->GetRenderFrame();
+  if (NS_WARN_IF(!rf)) {
+    MOZ_ASSERT(false, "No RenderFrame");
+    return NS_ERROR_FAILURE;
+  }
+
+  // Send the newly created layers ID back into content.
+  Unused << SendSetLayersId(rf->GetLayersId());
   return NS_OK;
 }
 
+IPCResult RemoteFrameParent::RecvShow(const ScreenIntSize& aSize,
+                                      const bool& aParentIsActive,
+                                      const nsSizeMode& aSizeMode) {
+  RenderFrame* rf = mTabParent->GetRenderFrame();
+  if (!rf->AttachLayerManager()) {
+    MOZ_CRASH();
+  }
+
+  Unused << mTabParent->SendShow(aSize, mTabParent->GetShowInfo(),
+                                 aParentIsActive, aSizeMode);
+  return IPC_OK();
+}
+
+IPCResult RemoteFrameParent::RecvLoadURL(const nsCString& aUrl) {
+  Unused << mTabParent->SendLoadURL(aUrl, mTabParent->GetShowInfo());
+  return IPC_OK();
+}
+
+IPCResult RemoteFrameParent::RecvUpdateDimensions(
+    const DimensionInfo& aDimensions) {
+  Unused << mTabParent->SendUpdateDimensions(aDimensions);
+  return IPC_OK();
+}
+
+IPCResult RemoteFrameParent::RecvRenderLayers(
+    const bool& aEnabled, const bool& aForceRepaint,
+    const layers::LayersObserverEpoch& aEpoch) {
+  Unused << mTabParent->SendRenderLayers(aEnabled, aForceRepaint, aEpoch);
+  return IPC_OK();
+}
+
 void RemoteFrameParent::ActorDestroy(ActorDestroyReason aWhy) {
   mIPCOpen = false;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/RemoteFrameParent.h
+++ b/dom/ipc/RemoteFrameParent.h
@@ -26,16 +26,28 @@ class RemoteFrameParent : public PRemote
 
   // Get our manager actor.
   TabParent* Manager() {
     MOZ_ASSERT(mIPCOpen);
     return static_cast<TabParent*>(PRemoteFrameParent::Manager());
   }
 
  protected:
+  friend class PRemoteFrameParent;
+
+  mozilla::ipc::IPCResult RecvShow(const ScreenIntSize& aSize,
+                                   const bool& aParentIsActive,
+                                   const nsSizeMode& aSizeMode);
+  mozilla::ipc::IPCResult RecvLoadURL(const nsCString& aUrl);
+  mozilla::ipc::IPCResult RecvUpdateDimensions(
+      const DimensionInfo& aDimensions);
+  mozilla::ipc::IPCResult RecvRenderLayers(const bool& aEnabled,
+                                           const bool& aForceRepaint,
+                                           const LayersObserverEpoch& aEpoch);
+
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   ~RemoteFrameParent();
 
   RefPtr<TabParent> mTabParent;
   bool mIPCOpen;
 };
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -553,16 +553,18 @@ class TabParent final : public PBrowserP
   bool IsReadyToHandleInputEvents() { return mIsReadyToHandleInputEvents; }
 
   static bool AreRecordReplayTabsActive() {
     return gNumActiveRecordReplayTabs != 0;
   }
 
   void NavigateByKey(bool aForward, bool aForDocumentNavigation);
 
+  ShowInfo GetShowInfo();
+
  protected:
   bool ReceiveMessage(
       const nsString& aMessage, bool aSync, ipc::StructuredCloneData* aData,
       mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
       nsTArray<ipc::StructuredCloneData>* aJSONRetVal = nullptr);
 
   mozilla::ipc::IPCResult RecvAsyncAuthPrompt(const nsCString& aUri,
                                               const nsString& aRealm,
@@ -721,18 +723,16 @@ class TabParent final : public PBrowserP
   // and have to ensure that the child did not modify links to be loaded.
   bool QueryDropLinksForVerification();
   nsTArray<nsString> mVerifyDropLinks;
 
 #ifdef DEBUG
   int32_t mActiveSupressDisplayportCount;
 #endif
 
-  ShowInfo GetShowInfo();
-
  private:
   // This is used when APZ needs to find the TabParent associated with a layer
   // to dispatch events.
   typedef nsDataHashtable<nsUint64HashKey, TabParent*> LayerToTabParentTable;
   static LayerToTabParentTable* sLayerToTabParentTable;
 
   static void AddTabParentToTable(layers::LayersId aLayersId,
                                   TabParent* aTabParent);