Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/dom/base/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 14 kB image not shown  

Quelle  nsFrameLoaderOwner.cpp   Sprache: C

 
/* -*- 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 "nsFrameLoaderOwner.h"
#include "mozilla/dom/BrowserParent.h"
#include "nsFrameLoader.h"
#include "nsFocusManager.h"
#include "nsNetUtil.h"
#include "nsSubDocumentFrame.h"
#include "nsQueryObject.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/Logging.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/FrameLoaderBinding.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/MozFrameLoaderOwnerBinding.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/dom/BrowserBridgeChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/BrowserBridgeHost.h"
#include "mozilla/dom/BrowserHost.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/EventStateManager.h"

extern mozilla::LazyLogModule gSHIPBFCacheLog;

using namespace mozilla;
using namespace mozilla::dom;

already_AddRefed<nsFrameLoader> nsFrameLoaderOwner::GetFrameLoader() {
  return do_AddRef(mFrameLoader);
}

void nsFrameLoaderOwner::SetFrameLoader(nsFrameLoader* aNewFrameLoader) {
  mFrameLoader = aNewFrameLoader;
}

mozilla::dom::BrowsingContext* nsFrameLoaderOwner::GetBrowsingContext() {
  if (mFrameLoader) {
    return mFrameLoader->GetBrowsingContext();
  }
  return nullptr;
}

mozilla::dom::BrowsingContext* nsFrameLoaderOwner::GetExtantBrowsingContext() {
  if (mFrameLoader) {
    return mFrameLoader->GetExtantBrowsingContext();
  }
  return nullptr;
}

bool nsFrameLoaderOwner::UseRemoteSubframes() {
  RefPtr<Element> owner = do_QueryObject(this);

  nsILoadContext* loadContext = owner->OwnerDoc()->GetLoadContext();
  MOZ_DIAGNOSTIC_ASSERT(loadContext);

  return loadContext->UseRemoteSubframes();
}

nsFrameLoaderOwner::ChangeRemotenessContextType
nsFrameLoaderOwner::ShouldPreserveBrowsingContext(
    bool aIsRemote, bool aReplaceBrowsingContext) {
  if (aReplaceBrowsingContext) {
    return ChangeRemotenessContextType::DONT_PRESERVE;
  }

  if (XRE_IsParentProcess()) {
    // Don't preserve for remote => parent loads.
    if (!aIsRemote) {
      return ChangeRemotenessContextType::DONT_PRESERVE;
    }

    // Don't preserve for parent => remote loads.
    if (mFrameLoader && !mFrameLoader->IsRemoteFrame()) {
      return ChangeRemotenessContextType::DONT_PRESERVE;
    }
  }

  return ChangeRemotenessContextType::PRESERVE;
}

void nsFrameLoaderOwner::ChangeRemotenessCommon(
    const ChangeRemotenessContextType& aContextType,
    const NavigationIsolationOptions& aOptions, bool aSwitchingInProgressLoad,
    bool aIsRemote, BrowsingContextGroup* aGroup,
    std::function<void()>& aFrameLoaderInit, mozilla::ErrorResult& aRv) {
  MOZ_ASSERT_IF(aGroup, aContextType != ChangeRemotenessContextType::PRESERVE);

  RefPtr<mozilla::dom::BrowsingContext> bc;
  bool networkCreated = false;

  // In this case, we're not reparenting a frameloader, we're just destroying
  // our current one and creating a new one, so we can use ourselves as the
  // owner.
  RefPtr<Element> owner = do_QueryObject(this);
  MOZ_ASSERT(owner);

  // When we destroy the original frameloader, it will stop blocking the parent
  // document's load event, and immediately trigger the load event if there are
  // no other blockers. Since we're going to be adding a new blocker as soon as
  // we recreate the frame loader, this is not what we want, so add our own
  // blocker until the process is complete.
  Document* doc = owner->OwnerDoc();
  doc->BlockOnload();
  auto cleanup = MakeScopeExit([&]() { doc->UnblockOnload(false); });

  // If we store the previous nsFrameLoader in the bfcache, this will be filled
  // with the SessionHistoryEntry which now owns the frame.
  RefPtr<SessionHistoryEntry> bfcacheEntry;

  {
    // Introduce a script blocker to ensure no JS is executed during the
    // nsFrameLoader teardown & recreation process. Unload listeners will be run
    // for the previous document, and the load will be started for the new one,
    // at the end of this block.
    nsAutoScriptBlocker sb;

    // If we already have a Frameloader, destroy it, possibly preserving its
    // browsing context.
    if (mFrameLoader) {
      // Calling `GetBrowsingContext` here will force frameloader
      // initialization if it hasn't already happened, which we neither need
      // or want, so we use the initial (possibly pending) browsing context
      // directly, instead.
      bc = mFrameLoader->GetMaybePendingBrowsingContext();

      if (nsFocusManager* fm = nsFocusManager::GetFocusManager()) {
        fm->FixUpFocusBeforeFrameLoaderChange(*owner, bc);
      }

      networkCreated = mFrameLoader->IsNetworkCreated();

      MOZ_ASSERT_IF(aOptions.mTryUseBFCache, aOptions.mReplaceBrowsingContext);
      if (aOptions.mTryUseBFCache && bc) {
        bfcacheEntry = bc->Canonical()->GetActiveSessionHistoryEntry();
        bool useBFCache = bfcacheEntry &&
                          bfcacheEntry == aOptions.mActiveSessionHistoryEntry &&
                          !bfcacheEntry->GetFrameLoader();
        if (useBFCache) {
          MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
                  ("nsFrameLoaderOwner::ChangeRemotenessCommon: store the old "
                   "page in bfcache"));
          Unused << bc->SetIsInBFCache(true);
          bfcacheEntry->SetFrameLoader(mFrameLoader);
          // Session history owns now the frameloader.
          mFrameLoader = nullptr;
        }
      }

      if (mFrameLoader) {
        if (aContextType == ChangeRemotenessContextType::PRESERVE) {
          mFrameLoader->SetWillChangeProcess();
        }

        // Preserve the networkCreated status, as nsDocShells created after a
        // process swap may shouldn't change their dynamically-created status.
        mFrameLoader->Destroy(aSwitchingInProgressLoad);
        mFrameLoader = nullptr;
      }
    }

    mFrameLoader = nsFrameLoader::Recreate(
        owner, bc, aGroup, aOptions, aIsRemote, networkCreated,
        aContextType == ChangeRemotenessContextType::PRESERVE);
    if (NS_WARN_IF(!mFrameLoader)) {
      aRv.Throw(NS_ERROR_FAILURE);
      return;
    }

    // Invoke the frame loader initialization callback to perform setup on our
    // new nsFrameLoader. This may cause our ErrorResult to become errored, so
    // double-check after calling.
    aFrameLoaderInit();
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }
  }

  // Now that we have a new FrameLoader, we'll eventually need to reset
  // nsSubDocumentFrame to use the new one. We can delay doing this if we're
  // keeping our old frameloader around in the BFCache and the new frame hasn't
  // presented yet to continue painting the previous document.
  const bool retainPaint = bfcacheEntry && mFrameLoader->IsRemoteFrame();
  if (!retainPaint) {
    MOZ_LOG(
        gSHIPBFCacheLog, LogLevel::Debug,
        ("Previous frameLoader not entering BFCache - not retaining paint data"
         "(bfcacheEntry=%p, isRemoteFrame=%d)",
         bfcacheEntry.get(), mFrameLoader->IsRemoteFrame()));
  }

  ChangeFrameLoaderCommon(owner, retainPaint);

  UpdateFocusAndMouseEnterStateAfterFrameLoaderChange(owner);
}

void nsFrameLoaderOwner::ChangeFrameLoaderCommon(Element* aOwner,
                                                 bool aRetainPaint) {
  // Now that we've got a new FrameLoader, we need to reset our
  // nsSubDocumentFrame to use the new FrameLoader.
  if (nsSubDocumentFrame* ourFrame = do_QueryFrame(aOwner->GetPrimaryFrame())) {
    auto retain = aRetainPaint ? nsSubDocumentFrame::RetainPaintData::Yes
                               : nsSubDocumentFrame::RetainPaintData::No;
    ourFrame->ResetFrameLoader(retain);
  }

  if (aOwner->IsXULElement()) {
    // Assuming this element is a XULFrameElement, once we've reset our
    // FrameLoader, fire an event to act like we've recreated ourselves, similar
    // to what XULFrameElement does after rebinding to the tree.
    // ChromeOnlyDispatch is turns on to make sure this isn't fired into
    // content.
    mozilla::AsyncEventDispatcher::RunDOMEventWhenSafe(
        *aOwner, u"XULFrameLoaderCreated"_ns, mozilla::CanBubble::eYes,
        mozilla::ChromeOnlyDispatch::eYes);
  }

  if (mFrameLoader) {
    mFrameLoader->PropagateIsUnderHiddenEmbedderElement(
        !aOwner->GetPrimaryFrame() ||
        !aOwner->GetPrimaryFrame()->StyleVisibility()->IsVisible());
  }
}

void nsFrameLoaderOwner::UpdateFocusAndMouseEnterStateAfterFrameLoaderChange() {
  RefPtr<Element> owner = do_QueryObject(this);
  UpdateFocusAndMouseEnterStateAfterFrameLoaderChange(owner);
}

void nsFrameLoaderOwner::UpdateFocusAndMouseEnterStateAfterFrameLoaderChange(
    Element* aOwner) {
  // If the element is focused, or the current mouse over target then
  // we need to update that state for the new BrowserParent too.
  if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
    if (fm->GetFocusedElement() == aOwner) {
      fm->FixUpFocusAfterFrameLoaderChange(*aOwner);
    }
  }

  if (aOwner->GetPrimaryFrame()) {
    EventStateManager* eventManager =
        aOwner->GetPrimaryFrame()->PresContext()->EventStateManager();
    eventManager->RecomputeMouseEnterStateForRemoteFrame(*aOwner);
  }
}

void nsFrameLoaderOwner::ChangeRemoteness(
    const mozilla::dom::RemotenessOptions& aOptions, mozilla::ErrorResult& rv) {
  bool isRemote = !aOptions.mRemoteType.IsEmpty();

  std::function<void()> frameLoaderInit = [&] {
    if (isRemote) {
      mFrameLoader->ConfigRemoteProcess(aOptions.mRemoteType, nullptr);
    }

    if (aOptions.mPendingSwitchID.WasPassed()) {
      mFrameLoader->ResumeLoad(aOptions.mPendingSwitchID.Value());
    } else {
      mFrameLoader->LoadFrame(/* aOriginalSrc */ false,
                              /* aShouldCheckForRecursion */ false);
    }
  };

  auto shouldPreserve = ShouldPreserveBrowsingContext(
      isRemote, /* replaceBrowsingContext */ false);
  NavigationIsolationOptions options;
  ChangeRemotenessCommon(shouldPreserve, options,
                         aOptions.mSwitchingInProgressLoad, isRemote,
                         /* group */ nullptr, frameLoaderInit, rv);
}

void nsFrameLoaderOwner::ChangeRemotenessWithBridge(BrowserBridgeChild* aBridge,
                                                    mozilla::ErrorResult& rv) {
  MOZ_ASSERT(XRE_IsContentProcess());
  if (NS_WARN_IF(!mFrameLoader)) {
    rv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }

  std::function<void()> frameLoaderInit = [&] {
    MOZ_DIAGNOSTIC_ASSERT(!mFrameLoader->mInitialized);
    RefPtr<BrowserBridgeHost> host = aBridge->FinishInit(mFrameLoader);
    mFrameLoader->mPendingBrowsingContext->SetEmbedderElement(
        mFrameLoader->GetOwnerContent());
    mFrameLoader->mRemoteBrowser = host;
    mFrameLoader->mInitialized = true;
  };

  NavigationIsolationOptions options;
  ChangeRemotenessCommon(ChangeRemotenessContextType::PRESERVE, options,
                         /* inProgress */ true,
                         /* isRemote */ true, /* group */ nullptr,
                         frameLoaderInit, rv);
}

void nsFrameLoaderOwner::ChangeRemotenessToProcess(
    ContentParent* aContentParent, const NavigationIsolationOptions& aOptions,
    BrowsingContextGroup* aGroup, mozilla::ErrorResult& rv) {
  MOZ_ASSERT(XRE_IsParentProcess());
  MOZ_ASSERT_IF(aGroup, aOptions.mReplaceBrowsingContext);
  bool isRemote = aContentParent != nullptr;

  std::function<void()> frameLoaderInit = [&] {
    if (isRemote) {
      mFrameLoader->ConfigRemoteProcess(aContentParent->GetRemoteType(),
                                        aContentParent);
    }
  };

  auto shouldPreserve =
      ShouldPreserveBrowsingContext(isRemote, aOptions.mReplaceBrowsingContext);
  ChangeRemotenessCommon(shouldPreserve, aOptions, /* inProgress */ true,
                         isRemote, aGroup, frameLoaderInit, rv);
}

void nsFrameLoaderOwner::SubframeCrashed() {
  MOZ_ASSERT(XRE_IsContentProcess());

  std::function<void()> frameLoaderInit = [&] {
    RefPtr<nsFrameLoader> frameLoader = mFrameLoader;
    nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
        "nsFrameLoaderOwner::SubframeCrashed", [frameLoader]() {
          nsCOMPtr<nsIURI> uri;
          nsresult rv = NS_NewURI(getter_AddRefs(uri), "about:blank");
          if (NS_WARN_IF(NS_FAILED(rv))) {
            return;
          }

          RefPtr<nsDocShell> docShell =
              frameLoader->GetDocShell(IgnoreErrors());
          if (NS_WARN_IF(!docShell)) {
            return;
          }
          bool displayed = false;
          docShell->DisplayLoadError(NS_ERROR_FRAME_CRASHED, uri,
                                     u"about:blank", nullptr, &displayed);
        }));
  };

  NavigationIsolationOptions options;
  ChangeRemotenessCommon(ChangeRemotenessContextType::PRESERVE, options,
                         /* inProgress */ false, /* isRemote */ false,
                         /* group */ nullptr, frameLoaderInit, IgnoreErrors());
}

void nsFrameLoaderOwner::RestoreFrameLoaderFromBFCache(
    nsFrameLoader* aNewFrameLoader) {
  MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
          ("nsFrameLoaderOwner::RestoreFrameLoaderFromBFCache: Replace "
           "frameloader"));

  Maybe<bool> renderLayers;
  if (mFrameLoader) {
    if (auto* oldParent = mFrameLoader->GetBrowserParent()) {
      renderLayers.emplace(oldParent->GetRenderLayers());
    }
  }

  mFrameLoader = aNewFrameLoader;

  if (auto* browserParent = mFrameLoader->GetBrowserParent()) {
    browserParent->AddWindowListeners();
    if (renderLayers.isSome()) {
      browserParent->SetRenderLayers(renderLayers.value());
    }
  }

  RefPtr<Element> owner = do_QueryObject(this);
  ChangeFrameLoaderCommon(owner, /* aRetainPaint = */ false);
}

void nsFrameLoaderOwner::AttachFrameLoader(nsFrameLoader* aFrameLoader) {
  mFrameLoaderList.insertBack(aFrameLoader);
}

void nsFrameLoaderOwner::DetachFrameLoader(nsFrameLoader* aFrameLoader) {
  if (aFrameLoader->isInList()) {
    MOZ_ASSERT(mFrameLoaderList.contains(aFrameLoader));
    aFrameLoader->remove();
  }
}

void nsFrameLoaderOwner::FrameLoaderDestroying(nsFrameLoader* aFrameLoader,
                                               bool aDestroyBFCached) {
  if (aFrameLoader == mFrameLoader) {
    if (aDestroyBFCached) {
      while (!mFrameLoaderList.isEmpty()) {
        RefPtr<nsFrameLoader> loader = mFrameLoaderList.popFirst();
        if (loader != mFrameLoader) {
          loader->Destroy();
        }
      }
    }
  } else {
    DetachFrameLoader(aFrameLoader);
  }
}

99%


¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.