products/sources/formale Sprachen/C/Firefox/remote/shared/messagehandler/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 9 kB image not shown  

Quelle  nsDocShell.cpp   Sprache: unbekannt

 
/* -*- 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 "nsDocShell.h"

#include <algorithm>

#ifdef XP_WIN
#  include <process.h>
#  define getpid _getpid
#else
#  include <unistd.h>  // for getpid()
#endif

#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Casting.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Components.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Encoding.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/InputTaskManager.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/Logging.h"
#include "mozilla/MediaFeatureChange.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/ScrollContainerFrame.h"
#include "mozilla/ScrollTypes.h"
#include "mozilla/SimpleEnumerator.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_docshell.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_extensions.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StaticPrefs_security.h"
#include "mozilla/StaticPrefs_ui.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/StartupTimeline.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/Telemetry.h"

#include "mozilla/Unused.h"
#include "mozilla/WidgetUtils.h"

#include "mozilla/dom/AutoEntryScript.h"
#include "mozilla/dom/ChildProcessChannelListener.h"
#include "mozilla/dom/ClientChannelHelper.h"
#include "mozilla/dom/ClientHandle.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/ClientManager.h"
#include "mozilla/dom/ClientSource.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/FragmentDirective.h"
#include "mozilla/dom/HTMLAnchorElement.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/PerformanceNavigation.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/ScreenOrientation.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ServiceWorkerInterceptController.h"
#include "mozilla/dom/ServiceWorkerUtils.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/dom/SessionStoreChangeListener.h"
#include "mozilla/dom/SessionStoreChild.h"
#include "mozilla/dom/SessionStoreUtils.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/ChildSHistory.h"
#include "mozilla/dom/nsCSPContext.h"
#include "mozilla/dom/nsHTTPSOnlyUtils.h"
#include "mozilla/dom/LoadURIOptionsBinding.h"
#include "mozilla/dom/JSWindowActorChild.h"
#include "mozilla/dom/DocumentBinding.h"
#include "mozilla/glean/DocshellMetrics.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/net/DocumentChannel.h"
#include "mozilla/net/DocumentChannelChild.h"
#include "mozilla/net/ParentChannelWrapper.h"
#include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "ReferrerInfo.h"

#include "nsIAuthPrompt.h"
#include "nsIAuthPrompt2.h"
#include "nsICachingChannel.h"
#include "nsICaptivePortalService.h"
#include "nsIChannel.h"
#include "nsIChannelEventSink.h"
#include "nsIClassOfService.h"
#include "nsIConsoleReportCollector.h"
#include "nsIContent.h"
#include "nsIContentInlines.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIController.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDocumentViewer.h"
#include "mozilla/dom/Document.h"
#include "nsHTMLDocument.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIDOMWindow.h"
#include "nsIEditingSession.h"
#include "nsIEffectiveTLDService.h"
#include "nsIExternalProtocolService.h"
#include "nsIFormPOSTActionChannel.h"
#include "nsIFrame.h"
#include "nsIGlobalObject.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIIDNService.h"
#include "nsIInputStreamChannel.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILayoutHistoryState.h"
#include "nsILoadInfo.h"
#include "nsILoadURIDelegate.h"
#include "nsIMultiPartChannel.h"
#include "nsINestedURI.h"
#include "nsINetworkPredictor.h"
#include "nsINode.h"
#include "nsINSSErrorsService.h"
#include "nsIObserverService.h"
#include "nsIOService.h"
#include "nsIPrincipal.h"
#include "nsIPrivacyTransitionObserver.h"
#include "nsIPrompt.h"
#include "nsIPromptCollection.h"
#include "nsIPromptFactory.h"
#include "nsIPublicKeyPinningService.h"
#include "nsIReflowObserver.h"
#include "nsIScriptChannel.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptSecurityManager.h"
#include "nsScriptSecurityManager.h"
#include "nsIScrollObserver.h"
#include "nsISupportsPrimitives.h"
#include "nsISecureBrowserUI.h"
#include "nsISeekableStream.h"
#include "nsISelectionDisplay.h"
#include "nsISHEntry.h"
#include "nsISiteSecurityService.h"
#include "nsISocketProvider.h"
#include "nsIStringBundle.h"
#include "nsIStructuredCloneContainer.h"
#include "nsIBrowserChild.h"
#include "nsITextToSubURI.h"
#include "nsITimedChannel.h"
#include "nsITimer.h"
#include "nsITransportSecurityInfo.h"
#include "nsIUploadChannel.h"
#include "nsIURIFixup.h"
#include "nsIURIMutator.h"
#include "nsIURILoader.h"
#include "nsIViewSourceChannel.h"
#include "nsIWebBrowserChrome.h"
#include "nsIWebBrowserFind.h"
#include "nsIWebProgress.h"
#include "nsIWidget.h"
#include "nsIWindowWatcher.h"
#include "nsIWritablePropertyBag2.h"
#include "nsIX509Cert.h"
#include "nsIXULRuntime.h"

#include "nsCommandManager.h"
#include "nsPIDOMWindow.h"
#include "nsPIWindowRoot.h"

#include "IHistory.h"
#include "IUrlClassifierUITelemetry.h"

#include "nsArray.h"
#include "nsArrayUtils.h"
#include "nsCExternalHandlerService.h"
#include "nsContentDLF.h"
#include "nsContentPolicyUtils.h"  // NS_CheckContentLoadPolicy(...)
#include "nsContentSecurityManager.h"
#include "nsContentSecurityUtils.h"
#include "nsContentUtils.h"
#include "nsCURILoader.h"
#include "nsDocShellCID.h"
#include "nsDocShellEditorData.h"
#include "nsDocShellEnumerator.h"
#include "nsDocShellLoadState.h"
#include "nsDocShellLoadTypes.h"
#include "nsDOMCID.h"
#include "nsDOMNavigationTiming.h"
#include "nsDSURIContentListener.h"
#include "nsEditingSession.h"
#include "nsError.h"
#include "nsEscape.h"
#include "nsFocusManager.h"
#include "nsGlobalWindowInner.h"
#include "nsGlobalWindowOuter.h"
#include "nsJSEnvironment.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsObjectLoadingContent.h"
#include "nsPingListener.h"
#include "nsPoint.h"
#include "nsQueryObject.h"
#include "nsQueryActor.h"
#include "nsRect.h"
#include "nsRefreshTimer.h"
#include "nsSandboxFlags.h"
#include "nsSHEntry.h"
#include "nsSHistory.h"
#include "nsSHEntry.h"
#include "nsStructuredCloneContainer.h"
#include "nsSubDocumentFrame.h"
#include "nsURILoader.h"
#include "nsURLHelper.h"
#include "nsView.h"
#include "nsViewManager.h"
#include "nsViewSourceHandler.h"
#include "nsWebBrowserFind.h"
#include "nsWhitespaceTokenizer.h"
#include "nsWidgetsCID.h"
#include "nsXULAppAPI.h"

#include "CertVerifier.h"
#include "ThirdPartyUtil.h"
#include "GeckoProfiler.h"
#include "mozilla/NullPrincipal.h"
#include "Navigator.h"
#include "prenv.h"
#include "mozilla/ipc/URIUtils.h"
#include "sslerr.h"
#include "mozpkix/pkix.h"
#include "NSSErrorsService.h"

#include "nsDocShellTelemetryUtils.h"

#ifdef MOZ_PLACES
#  include "nsIFaviconService.h"
#  include "mozIPlacesPendingOperation.h"
#endif

#if NS_PRINT_PREVIEW
#  include "nsIDocumentViewerPrint.h"
#  include "nsIWebBrowserPrint.h"
#endif

using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::net;

using mozilla::ipc::Endpoint;

// Threshold value in ms for META refresh based redirects
#define REFRESH_REDIRECT_TIMER 15000

static mozilla::LazyLogModule gCharsetMenuLog("CharsetMenu");

#define LOGCHARSETMENU(args) \
  MOZ_LOG(gCharsetMenuLog, mozilla::LogLevel::Debug, args)

#ifdef DEBUG
unsigned long nsDocShell::gNumberOfDocShells = 0;
static uint64_t gDocshellIDCounter = 0;

static mozilla::LazyLogModule gDocShellLog("nsDocShell");
static mozilla::LazyLogModule gDocShellAndDOMWindowLeakLogging(
    "DocShellAndDOMWindowLeak");
#endif
static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");
extern mozilla::LazyLogModule gPageCacheLog;
mozilla::LazyLogModule gSHLog("SessionHistory");
extern mozilla::LazyLogModule gSHIPBFCacheLog;

const char kAppstringsBundleURL[] =
    "chrome://global/locale/appstrings.properties";

static bool IsTopLevelDoc(BrowsingContext* aBrowsingContext,
                          nsILoadInfo* aLoadInfo) {
  MOZ_ASSERT(aBrowsingContext);
  MOZ_ASSERT(aLoadInfo);

  if (aLoadInfo->GetExternalContentPolicyType() !=
      ExtContentPolicy::TYPE_DOCUMENT) {
    return false;
  }

  return aBrowsingContext->IsTopContent();
}

// True if loading for top level document loading in active tab.
static bool IsUrgentStart(BrowsingContext* aBrowsingContext,
                          nsILoadInfo* aLoadInfo, uint32_t aLoadType) {
  MOZ_ASSERT(aBrowsingContext);
  MOZ_ASSERT(aLoadInfo);

  if (!IsTopLevelDoc(aBrowsingContext, aLoadInfo)) {
    return false;
  }

  if (aLoadType &
      (nsIDocShell::LOAD_CMD_NORMAL | nsIDocShell::LOAD_CMD_HISTORY)) {
    return true;
  }

  return aBrowsingContext->IsActive();
}

nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
                       uint64_t aContentWindowID)
    : nsDocLoader(true),
      mContentWindowID(aContentWindowID),
      mBrowsingContext(aBrowsingContext),
      mParentCharset(nullptr),
      mTreeOwner(nullptr),
      mScrollbarPref(ScrollbarPreference::Auto),
      mCharsetReloadState(eCharsetReloadInit),
      mParentCharsetSource(0),
      mFrameMargins(-1, -1),
      mItemType(aBrowsingContext->IsContent() ? typeContent : typeChrome),
      mPreviousEntryIndex(-1),
      mLoadedEntryIndex(-1),
      mBusyFlags(BUSY_FLAGS_NONE),
      mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
      mLoadType(0),
      mFailedLoadType(0),
      mChannelToDisconnectOnPageHide(0),
      mCreatingDocument(false),
#ifdef DEBUG
      mInEnsureScriptEnv(false),
#endif
      mInitialized(false),
      mAllowSubframes(true),
      mAllowMetaRedirects(true),
      mAllowImages(true),
      mAllowMedia(true),
      mAllowDNSPrefetch(true),
      mAllowWindowControl(true),
      mCSSErrorReportingEnabled(false),
      mAllowAuth(mItemType == typeContent),
      mAllowKeywordFixup(false),
      mDisableMetaRefreshWhenInactive(false),
      mWindowDraggingAllowed(false),
      mInFrameSwap(false),
      mFiredUnloadEvent(false),
      mEODForCurrentDocument(false),
      mURIResultedInDocument(false),
      mIsBeingDestroyed(false),
      mIsExecutingOnLoadHandler(false),
      mSavingOldViewer(false),
      mInvisible(false),
      mHasLoadedNonBlankURI(false),
      mBlankTiming(false),
      mTitleValidForCurrentURI(false),
      mWillChangeProcess(false),
      mIsNavigating(false),
      mForcedAutodetection(false),
      mCheckingSessionHistory(false),
      mNeedToReportActiveAfterLoadingBecomesActive(false) {
  // If no outer window ID was provided, generate a new one.
  if (aContentWindowID == 0) {
    mContentWindowID = nsContentUtils::GenerateWindowId();
  }

  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n"this));

#ifdef DEBUG
  mDocShellID = gDocshellIDCounter++;
  // We're counting the number of |nsDocShells| to help find leaks
  ++gNumberOfDocShells;
  MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
          ("++DOCSHELL %p == %ld [pid = %d] [id = %" PRIu64 "]\n", (void*)this,
           gNumberOfDocShells, getpid(), mDocShellID));
#endif
}

nsDocShell::~nsDocShell() {
  // Avoid notifying observers while we're in the dtor.
  mIsBeingDestroyed = true;

  Destroy();

  if (mDocumentViewer) {
    mDocumentViewer->Close(nullptr);
    mDocumentViewer->Destroy();
    mDocumentViewer = nullptr;
  }

  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p destroyed\n"this));

#ifdef DEBUG
  if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)) {
    nsAutoCString url;
    if (mLastOpenedURI) {
      url = mLastOpenedURI->GetSpecOrDefault();

      // Data URLs can be very long, so truncate to avoid flooding the log.
      const uint32_t maxURLLength = 1000;
      if (url.Length() > maxURLLength) {
        url.Truncate(maxURLLength);
      }
    }

    // We're counting the number of |nsDocShells| to help find leaks
    --gNumberOfDocShells;
    MOZ_LOG(
        gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
        ("--DOCSHELL %p == %ld [pid = %d] [id = %" PRIu64 "] [url = %s]\n",
         (void*)this, gNumberOfDocShells, getpid(), mDocShellID, url.get()));
  }
#endif
}

bool nsDocShell::Initialize() {
  if (mInitialized) {
    // We've already been initialized.
    return true;
  }

  NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
               "Unexpected item type in docshell");

  NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
  mInitialized = true;

  mDisableMetaRefreshWhenInactive =
      Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
                           mDisableMetaRefreshWhenInactive);

  if (nsCOMPtr<nsIObserverService> serv = services::GetObserverService()) {
    const char* msg = mItemType == typeContent ? NS_WEBNAVIGATION_CREATE
                                               : NS_CHROME_WEBNAVIGATION_CREATE;
    serv->NotifyWhenScriptSafe(GetAsSupports(this), msg, nullptr);
  }

  return true;
}

/* static */
already_AddRefed<nsDocShell> nsDocShell::Create(
    BrowsingContext* aBrowsingContext, uint64_t aContentWindowID) {
  MOZ_ASSERT(aBrowsingContext, "DocShell without a BrowsingContext!");

  nsresult rv;
  RefPtr<nsDocShell> ds = new nsDocShell(aBrowsingContext, aContentWindowID);

  // Initialize the underlying nsDocLoader.
  rv = ds->nsDocLoader::InitWithBrowsingContext(aBrowsingContext);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }

  // Create our ContentListener
  ds->mContentListener = new nsDSURIContentListener(ds);

  // We enable if we're in the parent process in order to support non-e10s
  // configurations.
  // Note: This check is duplicated in SharedWorkerInterfaceRequestor's
  // constructor.
  if (XRE_IsParentProcess()) {
    ds->mInterceptController = new ServiceWorkerInterceptController();
  }

  // We want to hold a strong ref to the loadgroup, so it better hold a weak
  // ref to us...  use an InterfaceRequestorProxy to do this.
  nsCOMPtr<nsIInterfaceRequestor> proxy = new InterfaceRequestorProxy(ds);
  ds->mLoadGroup->SetNotificationCallbacks(proxy);

  // XXX(nika): We have our BrowsingContext, so we might be able to skip this.
  // It could be nice to directly set up our DocLoader tree?
  rv = nsDocLoader::AddDocLoaderAsChildOfRoot(ds);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }

  // Add |ds| as a progress listener to itself.  A little weird, but simpler
  // than reproducing all the listener-notification logic in overrides of the
  // various methods via which nsDocLoader can be notified.   Note that this
  // holds an nsWeakPtr to |ds|, so it's ok.
  rv = ds->AddProgressListener(ds, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
                                       nsIWebProgress::NOTIFY_STATE_NETWORK |
                                       nsIWebProgress::NOTIFY_LOCATION);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }

  // If our BrowsingContext has private browsing enabled, update the number of
  // private browsing docshells.
  if (aBrowsingContext->UsePrivateBrowsing()) {
    ds->NotifyPrivateBrowsingChanged();
  }

  // If our parent window is present in this process, set up our parent now.
  RefPtr<WindowContext> parentWC = aBrowsingContext->GetParentWindowContext();
  if (parentWC && parentWC->IsInProcess()) {
    // If we don't have a parent element anymore, we can't finish this load!
    // How'd we get here?
    RefPtr<Element> parentElement = aBrowsingContext->GetEmbedderElement();
    if (!parentElement) {
      MOZ_ASSERT_UNREACHABLE("nsDocShell::Create() - !parentElement");
      return nullptr;
    }

    // We have an in-process parent window, but don't have a parent nsDocShell?
    // How'd we get here!
    nsCOMPtr<nsIDocShell> parentShell =
        parentElement->OwnerDoc()->GetDocShell();
    if (!parentShell) {
      MOZ_ASSERT_UNREACHABLE("nsDocShell::Create() - !parentShell");
      return nullptr;
    }
    parentShell->AddChild(ds);
  }

  // Make |ds| the primary DocShell for the given context.
  aBrowsingContext->SetDocShell(ds);

  // Set |ds| default load flags on load group.
  ds->SetLoadGroupDefaultLoadFlags(aBrowsingContext->GetDefaultLoadFlags());

  if (XRE_IsParentProcess()) {
    aBrowsingContext->Canonical()->MaybeAddAsProgressListener(ds);
  }

  return ds.forget();
}

void nsDocShell::DestroyChildren() {
  for (auto* child : mChildList.ForwardRange()) {
    nsCOMPtr<nsIDocShellTreeItem> shell = do_QueryObject(child);
    NS_ASSERTION(shell, "docshell has null child");

    if (shell) {
      shell->SetTreeOwner(nullptr);
    }
  }

  nsDocLoader::DestroyChildren();
}

NS_IMPL_CYCLE_COLLECTION_WEAK_PTR_INHERITED(nsDocShell, nsDocLoader,
                                            mScriptGlobal, mInitialClientSource,
                                            mBrowsingContext,
                                            mChromeEventHandler)

NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell)
  NS_INTERFACE_MAP_ENTRY(nsIDocShell)
  NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
  NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
  NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
  NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
  NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
  NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
  NS_INTERFACE_MAP_ENTRY(nsILoadContext)
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINetworkInterceptController,
                                     mInterceptController)
NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)

NS_IMETHODIMP
nsDocShell::GetInterface(const nsIID& aIID, void** aSink) {
  MOZ_ASSERT(aSink, "null out param");

  *aSink = nullptr;

  if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
    NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
    *aSink = static_cast<nsICommandManager*>(mCommandManager.get());
  } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
    *aSink = mContentListener;
  } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
              aIID.Equals(NS_GET_IID(nsIGlobalObject)) ||
              aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) ||
              aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) ||
              aIID.Equals(NS_GET_IID(nsIDOMWindow))) &&
             NS_SUCCEEDED(EnsureScriptEnvironment())) {
    return mScriptGlobal->QueryInterface(aIID, aSink);
  } else if (aIID.Equals(NS_GET_IID(Document)) &&
             NS_SUCCEEDED(EnsureDocumentViewer())) {
    RefPtr<Document> doc = mDocumentViewer->GetDocument();
    doc.forget(aSink);
    return *aSink ? NS_OK : NS_NOINTERFACE;
  } else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
             NS_SUCCEEDED(EnsureScriptEnvironment())) {
    nsresult rv;
    nsCOMPtr<nsIWindowWatcher> wwatch =
        do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    // Get the an auth prompter for our window so that the parenting
    // of the dialogs works as it should when using tabs.
    nsIPrompt* prompt;
    rv = wwatch->GetNewPrompter(mScriptGlobal, &prompt);
    NS_ENSURE_SUCCESS(rv, rv);

    *aSink = prompt;
    return NS_OK;
  } else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
             aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
    return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink))
               ? NS_OK
               : NS_NOINTERFACE;
  } else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
    // This is deprecated, you should instead directly get
    // ChildSHistory from the browsing context.
    MOZ_DIAGNOSTIC_ASSERT(
        false"Do not try to get a nsISHistory interface from nsIDocShell");
    return NS_NOINTERFACE;
  } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
    nsresult rv = EnsureFind();
    if (NS_FAILED(rv)) {
      return rv;
    }

    *aSink = mFind;
    NS_ADDREF((nsISupports*)*aSink);
    return NS_OK;
  } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
    if (PresShell* presShell = GetPresShell()) {
      return presShell->QueryInterface(aIID, aSink);
    }
  } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
    nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
    nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
    if (NS_SUCCEEDED(rv) && treeOwner) {
      return treeOwner->QueryInterface(aIID, aSink);
    }
  } else if (aIID.Equals(NS_GET_IID(nsIBrowserChild))) {
    *aSink = GetBrowserChild().take();
    return *aSink ? NS_OK : NS_ERROR_FAILURE;
  } else {
    return nsDocLoader::GetInterface(aIID, aSink);
  }

  NS_IF_ADDREF(((nsISupports*)*aSink));
  return *aSink ? NS_OK : NS_NOINTERFACE;
}

NS_IMETHODIMP
nsDocShell::SetCancelContentJSEpoch(int32_t aEpoch) {
  // Note: this gets called fairly early (before a pageload actually starts).
  // We could probably defer this even longer.
  nsCOMPtr<nsIBrowserChild> browserChild = GetBrowserChild();
  static_cast<BrowserChild*>(browserChild.get())
      ->SetCancelContentJSEpoch(aEpoch);
  return NS_OK;
}

nsresult nsDocShell::CheckDisallowedJavascriptLoad(
    nsDocShellLoadState* aLoadState) {
  if (!net::SchemeIsJavascript(aLoadState->URI())) {
    return NS_OK;
  }

  if (nsCOMPtr<nsIPrincipal> targetPrincipal =
          GetInheritedPrincipal(/* aConsiderCurrentDocument */ true)) {
    if (!aLoadState->TriggeringPrincipal()->Subsumes(targetPrincipal)) {
      return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI;
    }
    return NS_OK;
  }
  return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI;
}

NS_IMETHODIMP
nsDocShell::LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating) {
  return LoadURI(aLoadState, aSetNavigating, false);
}

nsresult nsDocShell::LoadURI(nsDocShellLoadState* aLoadState,
                             bool aSetNavigating,
                             bool aContinueHandlingSubframeHistory) {
  MOZ_ASSERT(aLoadState, "Must have a valid load state!");
  // NOTE: This comparison between what appears to be internal/external load
  // flags is intentional, as it's ensuring that the caller isn't using any of
  // the flags reserved for implementations by the `nsIWebNavigation` interface.
  // In the future, this check may be dropped.
  MOZ_ASSERT(
      (aLoadState->LoadFlags() & INTERNAL_LOAD_FLAGS_LOADURI_SETUP_FLAGS) == 0,
      "Should not have these flags set");
  MOZ_ASSERT(aLoadState->TargetBrowsingContext().IsNull(),
             "Targeting doesn't occur until InternalLoad");

  if (!aLoadState->TriggeringPrincipal()) {
    MOZ_ASSERT(false"LoadURI must have a triggering principal");
    return NS_ERROR_FAILURE;
  }

  MOZ_TRY(CheckDisallowedJavascriptLoad(aLoadState));

  bool oldIsNavigating = mIsNavigating;
  auto cleanupIsNavigating =
      MakeScopeExit([&]() { mIsNavigating = oldIsNavigating; });
  if (aSetNavigating) {
    mIsNavigating = true;
  }

  PopupBlocker::PopupControlState popupState = PopupBlocker::openOverridden;
  if (aLoadState->HasLoadFlags(LOAD_FLAGS_ALLOW_POPUPS)) {
    popupState = PopupBlocker::openAllowed;
    // If we allow popups as part of the navigation, ensure we fake a user
    // interaction, so that popups can, in fact, be allowed to open.
    if (WindowContext* wc = mBrowsingContext->GetCurrentWindowContext()) {
      wc->NotifyUserGestureActivation();
    }
  }

  AutoPopupStatePusher statePusher(popupState);

  if (aLoadState->GetCancelContentJSEpoch().isSome()) {
    SetCancelContentJSEpoch(*aLoadState->GetCancelContentJSEpoch());
  }

  // Note: we allow loads to get through here even if mFiredUnloadEvent is
  // true; that case will get handled in LoadInternal or LoadHistoryEntry,
  // so we pass false as the second parameter to IsNavigationAllowed.
  // However, we don't allow the page to change location *in the middle of*
  // firing beforeunload, so we do need to check if *beforeunload* is currently
  // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
  if (!IsNavigationAllowed(truefalse)) {
    return NS_OK;  // JS may not handle returning of an error code
  }

  nsLoadFlags defaultLoadFlags = mBrowsingContext->GetDefaultLoadFlags();
  if (aLoadState->HasLoadFlags(LOAD_FLAGS_FORCE_TRR)) {
    defaultLoadFlags |= nsIRequest::LOAD_TRR_ONLY_MODE;
  } else if (aLoadState->HasLoadFlags(LOAD_FLAGS_DISABLE_TRR)) {
    defaultLoadFlags |= nsIRequest::LOAD_TRR_DISABLED_MODE;
  }

  MOZ_ALWAYS_SUCCEEDS(mBrowsingContext->SetDefaultLoadFlags(defaultLoadFlags));

  if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
      mItemType == typeContent && !NS_IsAboutBlank(aLoadState->URI())) {
    StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
  }

  // LoadType used to be set to a default value here, if no LoadInfo/LoadState
  // object was passed in. That functionality has been removed as of bug
  // 1492648. LoadType should now be set up by the caller at the time they
  // create their nsDocShellLoadState object to pass into LoadURI.

  MOZ_LOG(
      gDocShellLeakLog, LogLevel::Debug,
      ("nsDocShell[%p]: loading %s with flags 0x%08x"this,
       aLoadState->URI()->GetSpecOrDefault().get(), aLoadState->LoadFlags()));

  if ((!aLoadState->LoadIsFromSessionHistory() &&
       !LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),
                            LOAD_FLAGS_REPLACE_HISTORY)) ||
      aContinueHandlingSubframeHistory) {
    // This is possibly a subframe, so handle it accordingly.
    //
    // If history exists, it will be loaded into the aLoadState object, and the
    // LoadType will be changed.
    if (MaybeHandleSubframeHistory(aLoadState,
                                   aContinueHandlingSubframeHistory)) {
      // MaybeHandleSubframeHistory returns true if we need to continue loading
      // asynchronously.
      return NS_OK;
    }
  }

  if (aLoadState->LoadIsFromSessionHistory()) {
    MOZ_LOG(gSHLog, LogLevel::Debug,
            ("nsDocShell[%p]: loading from session history"this));

    if (!mozilla::SessionHistoryInParent()) {
      nsCOMPtr<nsISHEntry> entry = aLoadState->SHEntry();
      return LoadHistoryEntry(entry, aLoadState->LoadType(),
                              aLoadState->HasValidUserGestureActivation());
    }

    // FIXME Null check aLoadState->GetLoadingSessionHistoryInfo()?
    return LoadHistoryEntry(*aLoadState->GetLoadingSessionHistoryInfo(),
                            aLoadState->LoadType(),
                            aLoadState->HasValidUserGestureActivation());
  }

  // On history navigation via Back/Forward buttons, don't execute
  // automatic JavaScript redirection such as |location.href = ...| or
  // |window.open()|
  //
  // LOAD_NORMAL:        window.open(...) etc.
  // LOAD_STOP_CONTENT:  location.href = ..., location.assign(...)
  if ((aLoadState->LoadType() == LOAD_NORMAL ||
       aLoadState->LoadType() == LOAD_STOP_CONTENT) &&
      ShouldBlockLoadingForBackButton()) {
    return NS_OK;
  }

  BrowsingContext::Type bcType = mBrowsingContext->GetType();

  // Set up the inheriting principal in LoadState.
  nsresult rv = aLoadState->SetupInheritingPrincipal(
      bcType, mBrowsingContext->OriginAttributesRef());
  NS_ENSURE_SUCCESS(rv, rv);

  rv = aLoadState->SetupTriggeringPrincipal(
      mBrowsingContext->OriginAttributesRef());
  NS_ENSURE_SUCCESS(rv, rv);

  aLoadState->CalculateLoadURIFlags();

  MOZ_ASSERT(aLoadState->TypeHint().IsVoid(),
             "Typehint should be null when calling InternalLoad from LoadURI");
  MOZ_ASSERT(aLoadState->FileName().IsVoid(),
             "FileName should be null when calling InternalLoad from LoadURI");
  MOZ_ASSERT(!aLoadState->LoadIsFromSessionHistory(),
             "Shouldn't be loading from an entry when calling InternalLoad "
             "from LoadURI");

  // If we have a system triggering principal, we can assume that this load was
  // triggered by some UI in the browser chrome, such as the URL bar or
  // bookmark bar. This should count as a user interaction for the current sh
  // entry, so that the user may navigate back to the current entry, from the
  // entry that is going to be added as part of this load.
  nsCOMPtr<nsIPrincipal> triggeringPrincipal =
      aLoadState->TriggeringPrincipal();
  if (triggeringPrincipal && triggeringPrincipal->IsSystemPrincipal()) {
    if (mozilla::SessionHistoryInParent()) {
      WindowContext* topWc = mBrowsingContext->GetTopWindowContext();
      if (topWc && !topWc->IsDiscarded()) {
        MOZ_ALWAYS_SUCCEEDS(topWc->SetSHEntryHasUserInteraction(true));
      }
    } else {
      bool oshe = false;
      nsCOMPtr<nsISHEntry> currentSHEntry;
      GetCurrentSHEntry(getter_AddRefs(currentSHEntry), &oshe);
      if (currentSHEntry) {
        currentSHEntry->SetHasUserInteraction(true);
      }
    }
  }

  rv = InternalLoad(aLoadState);
  NS_ENSURE_SUCCESS(rv, rv);

  if (aLoadState->GetOriginalURIString().isSome()) {
    // Save URI string in case it's needed later when
    // sending to search engine service in EndPageLoad()
    mOriginalUriString = *aLoadState->GetOriginalURIString();
  }

  return NS_OK;
}

bool nsDocShell::IsLoadingFromSessionHistory() {
  return mActiveEntryIsLoadingFromSessionHistory;
}

// StopDetector is modeled similarly to OnloadBlocker; it is a rather
// dummy nsIRequest implementation which can be added to an nsILoadGroup to
// detect Cancel calls.
class StopDetector final : public nsIRequest {
 public:
  StopDetector() = default;

  NS_DECL_ISUPPORTS
  NS_DECL_NSIREQUEST

  bool Canceled() { return mCanceled; }

 private:
  ~StopDetector() = default;

  bool mCanceled = false;
};

NS_IMPL_ISUPPORTS(StopDetector, nsIRequest)

NS_IMETHODIMP
StopDetector::GetName(nsACString& aResult) {
  aResult.AssignLiteral("about:stop-detector");
  return NS_OK;
}

NS_IMETHODIMP
StopDetector::IsPending(bool* aRetVal) {
  *aRetVal = true;
  return NS_OK;
}

NS_IMETHODIMP
StopDetector::GetStatus(nsresult* aStatus) {
  *aStatus = NS_OK;
  return NS_OK;
}

NS_IMETHODIMP StopDetector::SetCanceledReason(const nsACString& aReason) {
  return SetCanceledReasonImpl(aReason);
}

NS_IMETHODIMP StopDetector::GetCanceledReason(nsACString& aReason) {
  return GetCanceledReasonImpl(aReason);
}

NS_IMETHODIMP StopDetector::CancelWithReason(nsresult aStatus,
                                             const nsACString& aReason) {
  return CancelWithReasonImpl(aStatus, aReason);
}

NS_IMETHODIMP
StopDetector::Cancel(nsresult aStatus) {
  mCanceled = true;
  return NS_OK;
}

NS_IMETHODIMP
StopDetector::Suspend(void) { return NS_OK; }
NS_IMETHODIMP
StopDetector::Resume(void) { return NS_OK; }

NS_IMETHODIMP
StopDetector::GetLoadGroup(nsILoadGroup** aLoadGroup) {
  *aLoadGroup = nullptr;
  return NS_OK;
}

NS_IMETHODIMP
StopDetector::SetLoadGroup(nsILoadGroup* aLoadGroup) { return NS_OK; }

NS_IMETHODIMP
StopDetector::GetLoadFlags(nsLoadFlags* aLoadFlags) {
  *aLoadFlags = nsIRequest::LOAD_NORMAL;
  return NS_OK;
}

NS_IMETHODIMP
StopDetector::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
  return GetTRRModeImpl(aTRRMode);
}

NS_IMETHODIMP
StopDetector::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
  return SetTRRModeImpl(aTRRMode);
}

NS_IMETHODIMP
StopDetector::SetLoadFlags(nsLoadFlags aLoadFlags) { return NS_OK; }

bool nsDocShell::MaybeHandleSubframeHistory(
    nsDocShellLoadState* aLoadState, bool aContinueHandlingSubframeHistory) {
  // First, verify if this is a subframe.
  // Note, it is ok to rely on docshell here and not browsing context since when
  // an iframe is created, it has first in-process docshell.
  nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
  GetInProcessSameTypeParent(getter_AddRefs(parentAsItem));
  nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));

  if (!parentDS || parentDS == static_cast<nsIDocShell*>(this)) {
    if (mBrowsingContext && mBrowsingContext->IsTop()) {
      // This is the root docshell. If we got here while
      // executing an onLoad Handler,this load will not go
      // into session history.
      // XXX Why is this code in a method which deals with iframes!
      if (aLoadState->IsFormSubmission()) {
#ifdef DEBUG
        if (!mEODForCurrentDocument) {
          const MaybeDiscarded<BrowsingContext>& targetBC =
              aLoadState->TargetBrowsingContext();
          MOZ_ASSERT_IF(GetBrowsingContext() == targetBC.get(),
                        aLoadState->LoadType() == LOAD_NORMAL_REPLACE);
        }
#endif
      } else {
        bool inOnLoadHandler = false;
        GetIsExecutingOnLoadHandler(&inOnLoadHandler);
        if (inOnLoadHandler) {
          aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
        }
      }
    }
    return false;
  }

  /* OK. It is a subframe. Checkout the parent's loadtype. If the parent was
   * loaded through a history mechanism, then get the SH entry for the child
   * from the parent. This is done to restore frameset navigation while going
   * back/forward. If the parent was loaded through any other loadType, set the
   * child's loadType too accordingly, so that session history does not get
   * confused.
   */


  // Get the parent's load type
  uint32_t parentLoadType;
  parentDS->GetLoadType(&parentLoadType);

  if (!aContinueHandlingSubframeHistory) {
    if (mozilla::SessionHistoryInParent()) {
      if (nsDocShell::Cast(parentDS.get())->IsLoadingFromSessionHistory() &&
          !GetCreatedDynamically()) {
        if (XRE_IsContentProcess()) {
          dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
          nsCOMPtr<nsILoadGroup> loadGroup;
          GetLoadGroup(getter_AddRefs(loadGroup));
          if (contentChild && loadGroup && !mCheckingSessionHistory) {
            RefPtr<Document> parentDoc = parentDS->GetDocument();
            parentDoc->BlockOnload();
            RefPtr<BrowsingContext> browsingContext = mBrowsingContext;
            Maybe<uint64_t> currentLoadIdentifier =
                mBrowsingContext->GetCurrentLoadIdentifier();
            RefPtr<nsDocShellLoadState> loadState = aLoadState;
            bool isNavigating = mIsNavigating;
            RefPtr<StopDetector> stopDetector = new StopDetector();
            loadGroup->AddRequest(stopDetector, nullptr);
            // Need to set mCheckingSessionHistory so that
            // GetIsAttemptingToNavigate() returns true.
            mCheckingSessionHistory = true;

            auto resolve =
                [currentLoadIdentifier, browsingContext, parentDoc, loadState,
                 isNavigating, loadGroup, stopDetector](
                    mozilla::Maybe<LoadingSessionHistoryInfo>&& aResult) {
                  RefPtr<nsDocShell> docShell =
                      static_cast<nsDocShell*>(browsingContext->GetDocShell());
                  auto unblockParent = MakeScopeExit(
                      [loadGroup, stopDetector, parentDoc, docShell]() {
                        if (docShell) {
                          docShell->mCheckingSessionHistory = false;
                        }
                        loadGroup->RemoveRequest(stopDetector, nullptr, NS_OK);
                        parentDoc->UnblockOnload(false);
                      });

                  if (!docShell || !docShell->mCheckingSessionHistory) {
                    return;
                  }

                  if (stopDetector->Canceled()) {
                    return;
                  }
                  if (currentLoadIdentifier ==
                          browsingContext->GetCurrentLoadIdentifier() &&
                      aResult.isSome()) {
                    loadState->SetLoadingSessionHistoryInfo(aResult.value());
                    // This is an initial subframe load from the session
                    // history, index doesn't need to be updated.
                    loadState->SetLoadIsFromSessionHistory(0, false);
                  }

                  // We got the results back from the parent process, call
                  // LoadURI again with the possibly updated data.
                  docShell->LoadURI(loadState, isNavigating, true);
                };
            auto reject = [loadGroup, stopDetector, browsingContext,
                           parentDoc](mozilla::ipc::ResponseRejectReason) {
              RefPtr<nsDocShell> docShell =
                  static_cast<nsDocShell*>(browsingContext->GetDocShell());
              if (docShell) {
                docShell->mCheckingSessionHistory = false;
              }
              // In practise reject shouldn't be called ever.
              loadGroup->RemoveRequest(stopDetector, nullptr, NS_OK);
              parentDoc->UnblockOnload(false);
            };
            contentChild->SendGetLoadingSessionHistoryInfoFromParent(
                mBrowsingContext, std::move(resolve), std::move(reject));
            return true;
          }
        } else {
          Maybe<LoadingSessionHistoryInfo> info;
          mBrowsingContext->Canonical()->GetLoadingSessionHistoryInfoFromParent(
              info);
          if (info.isSome()) {
            aLoadState->SetLoadingSessionHistoryInfo(info.value());
            // This is an initial subframe load from the session
            // history, index doesn't need to be updated.
            aLoadState->SetLoadIsFromSessionHistory(0, false);
          }
        }
      }
    } else {
      // Get the ShEntry for the child from the parent
      nsCOMPtr<nsISHEntry> currentSH;
      bool oshe = false;
      parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
      bool dynamicallyAddedChild = GetCreatedDynamically();

      if (!dynamicallyAddedChild && !oshe && currentSH) {
        // Only use the old SHEntry, if we're sure enough that
        // it wasn't originally for some other frame.
        nsCOMPtr<nsISHEntry> shEntry;
        currentSH->GetChildSHEntryIfHasNoDynamicallyAddedChild(
            mBrowsingContext->ChildOffset(), getter_AddRefs(shEntry));
        if (shEntry) {
          aLoadState->SetSHEntry(shEntry);
        }
      }
    }
  }

  // Make some decisions on the child frame's loadType based on the
  // parent's loadType, if the subframe hasn't loaded anything into it.
  //
  // In some cases privileged scripts may try to get the DOMWindow
  // reference of this docshell before the loading starts, causing the
  // initial about:blank content viewer being created and mCurrentURI being
  // set. To handle this case we check if mCurrentURI is about:blank and
  // currentSHEntry is null.
  bool oshe = false;
  nsCOMPtr<nsISHEntry> currentChildEntry;
  GetCurrentSHEntry(getter_AddRefs(currentChildEntry), &oshe);

  if (mCurrentURI && (!NS_IsAboutBlank(mCurrentURI) || currentChildEntry ||
                      mLoadingEntry || mActiveEntry)) {
    // This is a pre-existing subframe. If
    // 1. The load of this frame was not originally initiated by session
    //    history directly (i.e. (!shEntry) condition succeeded, but it can
    //    still be a history load on parent which causes this frame being
    //    loaded), which we checked with the above assert, and
    // 2. mCurrentURI is not null, nor the initial about:blank,
    // it is possible that a parent's onLoadHandler or even self's
    // onLoadHandler is loading a new page in this child. Check parent's and
    // self's busy flag and if it is set, we don't want this onLoadHandler
    // load to get in to session history.
    BusyFlags parentBusy = parentDS->GetBusyFlags();
    BusyFlags selfBusy = GetBusyFlags();

    if (parentBusy & BUSY_FLAGS_BUSY || selfBusy & BUSY_FLAGS_BUSY) {
      aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
      aLoadState->ClearLoadIsFromSessionHistory();
    }
    return false;
  }

  // This is a newly created frame. Check for exception cases first.
  // By default the subframe will inherit the parent's loadType.
  if (aLoadState->LoadIsFromSessionHistory() &&
      (parentLoadType == LOAD_NORMAL || parentLoadType == LOAD_LINK)) {
    // The parent was loaded normally. In this case, this *brand new*
    // child really shouldn't have a SHEntry. If it does, it could be
    // because the parent is replacing an existing frame with a new frame,
    // in the onLoadHandler. We don't want this url to get into session
    // history. Clear off shEntry, and set load type to
    // LOAD_BYPASS_HISTORY.
    bool inOnLoadHandler = false;
    parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
    if (inOnLoadHandler) {
      aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
      aLoadState->ClearLoadIsFromSessionHistory();
    }
  } else if (parentLoadType == LOAD_REFRESH) {
    // Clear shEntry. For refresh loads, we have to load
    // what comes through the pipe, not what's in history.
    aLoadState->ClearLoadIsFromSessionHistory();
  } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
             (aLoadState->LoadIsFromSessionHistory() &&
              ((parentLoadType & LOAD_CMD_HISTORY) ||
               (parentLoadType == LOAD_RELOAD_NORMAL) ||
               (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
               (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) ||
               (parentLoadType ==
                LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) {
    // If the parent url, bypassed history or was loaded from
    // history, pass on the parent's loadType to the new child
    // frame too, so that the child frame will also
    // avoid getting into history.
    aLoadState->SetLoadType(parentLoadType);
  } else if (parentLoadType == LOAD_ERROR_PAGE) {
    // If the parent document is an error page, we don't
    // want to update global/session history. However,
    // this child frame is not an error page.
    aLoadState->SetLoadType(LOAD_BYPASS_HISTORY);
  } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
             (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
             (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
    // the new frame should inherit the parent's load type so that it also
    // bypasses the cache and/or proxy
    aLoadState->SetLoadType(parentLoadType);
  }

  return false;
}

/*
 * Reset state to a new content model within the current document and the
 * document viewer. Called by the document before initiating an out of band
 * document.write().
 */

NS_IMETHODIMP
nsDocShell::PrepareForNewContentModel() {
  // Clear out our form control state, because the state of controls
  // in the pre-open() document should not affect the state of
  // controls that are now going to be written.
  SetLayoutHistoryState(nullptr);
  mEODForCurrentDocument = false;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::FirePageHideNotification(bool aIsUnload) {
  FirePageHideNotificationInternal(aIsUnload, false);
  return NS_OK;
}

void nsDocShell::FirePageHideNotificationInternal(
    bool aIsUnload, bool aSkipCheckingDynEntries) {
  if (mDocumentViewer && !mFiredUnloadEvent) {
    // Keep an explicit reference since calling PageHide could release
    // mDocumentViewer
    nsCOMPtr<nsIDocumentViewer> viewer(mDocumentViewer);
    mFiredUnloadEvent = true;

    if (mTiming) {
      mTiming->NotifyUnloadEventStart();
    }

    viewer->PageHide(aIsUnload);

    if (mTiming) {
      mTiming->NotifyUnloadEventEnd();
    }

    AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
    uint32_t n = mChildList.Length();
    kids.SetCapacity(n);
    for (uint32_t i = 0; i < n; i++) {
      kids.AppendElement(do_QueryInterface(ChildAt(i)));
    }

    n = kids.Length();
    for (uint32_t i = 0; i < n; ++i) {
      RefPtr<nsDocShell> child = static_cast<nsDocShell*>(kids[i].get());
      if (child) {
        // Skip checking dynamic subframe entries in our children.
        child->FirePageHideNotificationInternal(aIsUnload, true);
      }
    }

    // If the document is unloading, remove all dynamic subframe entries.
    if (aIsUnload && !aSkipCheckingDynEntries) {
      RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
      if (rootSH) {
        MOZ_LOG(
            gSHLog, LogLevel::Debug,
            ("nsDocShell %p unloading, remove dynamic subframe entries"this));
        if (mozilla::SessionHistoryInParent()) {
          if (mActiveEntry) {
            mBrowsingContext->RemoveDynEntriesFromActiveSessionHistoryEntry();
          }
          MOZ_LOG(gSHLog, LogLevel::Debug,
                  ("nsDocShell %p unloading, no active entries"this));
        } else if (mOSHE) {
          int32_t index = rootSH->Index();
          rootSH->LegacySHistory()->RemoveDynEntries(index, mOSHE);
        }
      }
    }

    // Now make sure our editor, if any, is detached before we go
    // any farther.
    DetachEditorFromWindow();
  }
}

void nsDocShell::ThawFreezeNonRecursive(bool aThaw) {
  MOZ_ASSERT(mozilla::BFCacheInParent());

  if (!mScriptGlobal) {
    return;
  }

  if (RefPtr<nsGlobalWindowInner> inner =
          nsGlobalWindowInner::Cast(mScriptGlobal->GetCurrentInnerWindow())) {
    if (aThaw) {
      inner->Thaw(false);
    } else {
      inner->Freeze(false);
    }
  }
}

void nsDocShell::FirePageHideShowNonRecursive(bool aShow) {
  MOZ_ASSERT(mozilla::BFCacheInParent());

  if (!mDocumentViewer) {
    return;
  }

  // Emulate what non-SHIP BFCache does too. In pageshow case
  // add and remove a request and before that call SetCurrentURI to get
  // the location change notification.
  // For pagehide, set mFiredUnloadEvent to true, so that unload doesn't fire.
  nsCOMPtr<nsIDocumentViewer> viewer(mDocumentViewer);
  if (aShow) {
    viewer->SetIsHidden(false);
    mRefreshURIList = std::move(mBFCachedRefreshURIList);
    RefreshURIFromQueue();
    mFiredUnloadEvent = false;
    RefPtr<Document> doc = viewer->GetDocument();
    if (doc) {
      doc->NotifyActivityChanged();
      nsCOMPtr<nsPIDOMWindowInner> inner =
          mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindow() : nullptr;
      if (mBrowsingContext->IsTop()) {
        doc->NotifyPossibleTitleChange(false);
        doc->SetLoadingOrRestoredFromBFCacheTimeStampToNow();
        if (inner) {
          // Now that we have found the inner window of the page restored
          // from the history, we have to make sure that
          // performance.navigation.type is 2.
          // Traditionally this type change has been done to the top level page
          // only.
          Performance* performance = inner->GetPerformance();
          if (performance) {
            performance->GetDOMTiming()->NotifyRestoreStart();
          }
        }
      }

      nsCOMPtr<nsIChannel> channel = doc->GetChannel();
      if (channel) {
        SetLoadType(LOAD_HISTORY);
        mEODForCurrentDocument = false;
        mIsRestoringDocument = true;
        mLoadGroup->AddRequest(channel, nullptr);
        nsCOMPtr<nsIURI> uri;
        if (doc->FragmentDirective()) {
          // If we have fragment directives, then we've mutated the document
          // uri. Set the current URI from session history instead.
          if (mozilla::SessionHistoryInParent()) {
            uri = mActiveEntry ? mActiveEntry->GetURI() : nullptr;
          } else if (mOSHE) {
            uri = mOSHE->GetURI();
          }
        }
        if (!uri) {
          uri = doc->GetDocumentURI();
        }
        SetCurrentURI(uri, channel,
                      /* aFireOnLocationChange */ true,
                      /* aIsInitialAboutBlank */ false,
                      /* aLocationFlags */ 0);
        mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
        mIsRestoringDocument = false;
      }
      RefPtr<PresShell> presShell = GetPresShell();
      if (presShell) {
        presShell->Thaw(false);
      }

      if (inner) {
        inner->FireDelayedDOMEvents(false);
      }
    }
  } else if (!mFiredUnloadEvent) {
    // XXXBFCache check again that the page can enter bfcache.
    // XXXBFCache should mTiming->NotifyUnloadEventStart()/End() be called here?

    if (mRefreshURIList) {
      RefreshURIToQueue();
      mBFCachedRefreshURIList = std::move(mRefreshURIList);
    } else {
      // If Stop was called, the list was moved to mSavedRefreshURIList after
      // calling SuspendRefreshURIs, which calls RefreshURIToQueue.
      mBFCachedRefreshURIList = std::move(mSavedRefreshURIList);
    }

    mFiredUnloadEvent = true;
    viewer->PageHide(false);

    RefPtr<PresShell> presShell = GetPresShell();
    if (presShell) {
      presShell->Freeze(false);
    }
  }
}

nsresult nsDocShell::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable) {
  nsCOMPtr<nsIRunnable> runnable(aRunnable);
  if (NS_WARN_IF(!GetWindow())) {
    // Window should only be unavailable after destroyed.
    MOZ_ASSERT(mIsBeingDestroyed);
    return NS_ERROR_FAILURE;
  }
  return SchedulerGroup::Dispatch(runnable.forget());
}

NS_IMETHODIMP
nsDocShell::DispatchLocationChangeEvent() {
  return Dispatch(NewRunnableMethod("nsDocShell::FireDummyOnLocationChange",
                                    this,
                                    &nsDocShell::FireDummyOnLocationChange));
}

NS_IMETHODIMP
nsDocShell::StartDelayedAutoplayMediaComponents() {
  RefPtr<nsPIDOMWindowOuter> outerWindow = GetWindow();
  if (outerWindow) {
    outerWindow->ActivateMediaComponents();
  }
  return NS_OK;
}

bool nsDocShell::MaybeInitTiming() {
  if (mTiming && !mBlankTiming) {
    return false;
  }

  bool canBeReset = false;

  if (mScriptGlobal && mBlankTiming) {
    nsPIDOMWindowInner* innerWin = mScriptGlobal->GetCurrentInnerWindow();
    if (innerWin && innerWin->GetPerformance()) {
      mTiming = innerWin->GetPerformance()->GetDOMTiming();
      mBlankTiming = false;
    }
  }

  if (!mTiming) {
    mTiming = new nsDOMNavigationTiming(this);
    canBeReset = true;
  }

  mTiming->NotifyNavigationStart(
      mBrowsingContext->IsActive()
          ? nsDOMNavigationTiming::DocShellState::eActive
          : nsDOMNavigationTiming::DocShellState::eInactive);

  return canBeReset;
}

void nsDocShell::MaybeResetInitTiming(bool aReset) {
  if (aReset) {
    mTiming = nullptr;
  }
}

nsDOMNavigationTiming* nsDocShell::GetNavigationTiming() const {
  return mTiming;
}

nsPresContext* nsDocShell::GetEldestPresContext() {
  nsIDocumentViewer* viewer = mDocumentViewer;
  while (viewer) {
    nsIDocumentViewer* prevViewer = viewer->GetPreviousViewer();
    if (!prevViewer) {
      return viewer->GetPresContext();
    }
    viewer = prevViewer;
  }

  return nullptr;
}

nsPresContext* nsDocShell::GetPresContext() {
  if (!mDocumentViewer) {
    return nullptr;
  }

  return mDocumentViewer->GetPresContext();
}

PresShell* nsDocShell::GetPresShell() {
  nsPresContext* presContext = GetPresContext();
  return presContext ? presContext->GetPresShell() : nullptr;
}

PresShell* nsDocShell::GetEldestPresShell() {
  nsPresContext* presContext = GetEldestPresContext();

  if (presContext) {
    return presContext->GetPresShell();
  }

  return nullptr;
}

NS_IMETHODIMP
nsDocShell::GetDocViewer(nsIDocumentViewer** aDocumentViewer) {
  NS_ENSURE_ARG_POINTER(aDocumentViewer);

  *aDocumentViewer = mDocumentViewer;
  NS_IF_ADDREF(*aDocumentViewer);
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetOuterWindowID(uint64_t* aWindowID) {
  *aWindowID = mContentWindowID;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::SetChromeEventHandler(EventTarget* aChromeEventHandler) {
  mChromeEventHandler = aChromeEventHandler;

  if (mScriptGlobal) {
    mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
  }

  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetChromeEventHandler(EventTarget** aChromeEventHandler) {
  NS_ENSURE_ARG_POINTER(aChromeEventHandler);
  RefPtr<EventTarget> handler = mChromeEventHandler;
  handler.forget(aChromeEventHandler);
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::SetCurrentURIForSessionStore(nsIURI* aURI) {
  // Note that securityUI will set STATE_IS_INSECURE, even if
  // the scheme of |aURI| is "https".
  SetCurrentURI(aURI, nullptr,
                /* aFireOnLocationChange */
                true,
                /* aIsInitialAboutBlank */
                false,
                /* aLocationFlags */
                nsIWebProgressListener::LOCATION_CHANGE_SESSION_STORE);
  return NS_OK;
}

bool nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
                               bool aFireOnLocationChange,
                               bool aIsInitialAboutBlank,
                               uint32_t aLocationFlags) {
  MOZ_ASSERT(!mIsBeingDestroyed);

  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
          ("DOCSHELL %p SetCurrentURI %s\n"this,
           aURI ? aURI->GetSpecOrDefault().get() : ""));

  // We don't want to send a location change when we're displaying an error
  // page, and we don't want to change our idea of "current URI" either
  if (mLoadType == LOAD_ERROR_PAGE) {
    return false;
  }

  bool uriIsEqual = false;
  if (!mCurrentURI || !aURI ||
      NS_FAILED(mCurrentURI->Equals(aURI, &uriIsEqual)) || !uriIsEqual) {
    mTitleValidForCurrentURI = false;
  }

  SetCurrentURIInternal(aURI);

#ifdef DEBUG
  mLastOpenedURI = aURI;
#endif

  if (!NS_IsAboutBlank(mCurrentURI)) {
    mHasLoadedNonBlankURI = true;
  }

  // Don't fire onLocationChange when creating a subframe's initial about:blank
  // document, as this can happen when it's not safe for us to run script.
  if (aIsInitialAboutBlank && !mHasLoadedNonBlankURI &&
      !mBrowsingContext->IsTop()) {
    MOZ_ASSERT(!aRequest && aLocationFlags == 0);
    return false;
  }

  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());

  if (aFireOnLocationChange) {
    FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
  }
  return !aFireOnLocationChange;
}

void nsDocShell::SetCurrentURIInternal(nsIURI* aURI) {
  mCurrentURI = aURI;
  if (mBrowsingContext) {
    mBrowsingContext->ClearCachedValuesOfLocations();
  }
}

NS_IMETHODIMP
nsDocShell::GetCharset(nsACString& aCharset) {
  aCharset.Truncate();

  PresShell* presShell = GetPresShell();
  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
  Document* doc = presShell->GetDocument();
  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
  doc->GetDocumentCharacterSet()->Name(aCharset);
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::ForceEncodingDetection() {
  nsCOMPtr<nsIDocumentViewer> viewer;
  GetDocViewer(getter_AddRefs(viewer));
  if (!viewer) {
    return NS_OK;
  }

  Document* doc = viewer->GetDocument();
  if (!doc || doc->WillIgnoreCharsetOverride()) {
    return NS_OK;
  }

  mForcedAutodetection = true;

  nsIURI* url = doc->GetOriginalURI();
  bool isFileURL = url && SchemeIsFile(url);

  int32_t charsetSource = doc->GetDocumentCharacterSetSource();
  auto encoding = doc->GetDocumentCharacterSet();
  // AsHTMLDocument is valid, because we called
  // WillIgnoreCharsetOverride() above.
  if (doc->AsHTMLDocument()->IsPlainText()) {
    switch (charsetSource) {
      case kCharsetFromInitialAutoDetectionASCII:
        // Deliberately no final version
        LOGCHARSETMENU(("TEXT:UnlabeledAscii"));
        break;
      case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8GenericInitialWasASCII:
      case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8ContentInitialWasASCII:
        LOGCHARSETMENU(("TEXT:UnlabeledNonUtf8"));
        break;
      case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLDInitialWasASCII:
        LOGCHARSETMENU(("TEXT:UnlabeledNonUtf8TLD"));
        break;
      case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
      case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
        LOGCHARSETMENU(("TEXT:UnlabeledUtf8"));
        break;
      case kCharsetFromChannel:
        if (encoding == UTF_8_ENCODING) {
          LOGCHARSETMENU(("TEXT:ChannelUtf8"));
        } else {
          LOGCHARSETMENU(("TEXT:ChannelNonUtf8"));
        }
        break;
      default:
        LOGCHARSETMENU(("TEXT:Bug"));
        break;
    }
  } else {
    switch (charsetSource) {
      case kCharsetFromInitialAutoDetectionASCII:
        // Deliberately no final version
        LOGCHARSETMENU(("HTML:UnlabeledAscii"));
        break;
      case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Generic:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Generic:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8GenericInitialWasASCII:
      case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8Content:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8Content:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8ContentInitialWasASCII:
        LOGCHARSETMENU(("HTML:UnlabeledNonUtf8"));
        break;
      case kCharsetFromInitialAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLD:
      case kCharsetFromFinalAutoDetectionWouldNotHaveBeenUTF8DependedOnTLDInitialWasASCII:
        LOGCHARSETMENU(("HTML:UnlabeledNonUtf8TLD"));
        break;
      case kCharsetFromInitialAutoDetectionWouldHaveBeenUTF8:
      case kCharsetFromFinalAutoDetectionWouldHaveBeenUTF8InitialWasASCII:
        LOGCHARSETMENU(("HTML:UnlabeledUtf8"));
        break;
      case kCharsetFromChannel:
        if (encoding == UTF_8_ENCODING) {
          LOGCHARSETMENU(("HTML:ChannelUtf8"));
        } else {
          LOGCHARSETMENU(("HTML:ChannelNonUtf8"));
        }
        break;
      case kCharsetFromXmlDeclaration:
      case kCharsetFromMetaTag:
        if (isFileURL) {
          LOGCHARSETMENU(("HTML:LocalLabeled"));
        } else if (encoding == UTF_8_ENCODING) {
          LOGCHARSETMENU(("HTML:MetaUtf8"));
        } else {
          LOGCHARSETMENU(("HTML:MetaNonUtf8"));
        }
        break;
      default:
        LOGCHARSETMENU(("HTML:Bug"));
        break;
    }
  }
  return NS_OK;
}

void nsDocShell::SetParentCharset(const Encoding*& aCharset,
                                  int32_t aCharsetSource,
                                  nsIPrincipal* aPrincipal) {
  mParentCharset = aCharset;
  mParentCharsetSource = aCharsetSource;
  mParentCharsetPrincipal = aPrincipal;
}

void nsDocShell::GetParentCharset(const Encoding*& aCharset,
                                  int32_t* aCharsetSource,
                                  nsIPrincipal** aPrincipal) {
  aCharset = mParentCharset;
  *aCharsetSource = mParentCharsetSource;
  NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal);
}

NS_IMETHODIMP
nsDocShell::GetHasTrackingContentBlocked(Promise** aPromise) {
  MOZ_ASSERT(aPromise);

  ErrorResult rv;
  RefPtr<Document> doc(GetDocument());
  RefPtr<Promise> retPromise = Promise::Create(doc->GetOwnerGlobal(), rv);
  if (NS_WARN_IF(rv.Failed())) {
    return rv.StealNSResult();
  }

  // Retrieve the document's content blocking events from the parent process.
  RefPtr<Document::GetContentBlockingEventsPromise> promise =
      doc->GetContentBlockingEvents();
  if (promise) {
    promise->Then(
        GetCurrentSerialEventTarget(), __func__,
        [retPromise](const Document::GetContentBlockingEventsPromise::
                         ResolveOrRejectValue& aValue) {
          if (aValue.IsResolve()) {
            bool has = aValue.ResolveValue() &
                       nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT;
            retPromise->MaybeResolve(has);
          } else {
            retPromise->MaybeResolve(false);
          }
        });
  } else {
    retPromise->MaybeResolve(false);
  }

  retPromise.forget(aPromise);
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetCssErrorReportingEnabled(bool* aEnabled) {
  MOZ_ASSERT(aEnabled);
  *aEnabled = mCSSErrorReportingEnabled;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::SetCssErrorReportingEnabled(bool aEnabled) {
  mCSSErrorReportingEnabled = aEnabled;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing) {
  NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
  return mBrowsingContext->GetUsePrivateBrowsing(aUsePrivateBrowsing);
}

void nsDocShell::NotifyPrivateBrowsingChanged() {
  MOZ_ASSERT(!mIsBeingDestroyed);

  nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
  while (iter.HasMore()) {
    nsWeakPtr ref = iter.GetNext();
    nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref);
    if (!obs) {
      iter.Remove();
    } else {
      obs->PrivateModeChanged(UsePrivateBrowsing());
    }
  }
}

NS_IMETHODIMP
nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing) {
  return mBrowsingContext->SetUsePrivateBrowsing(aUsePrivateBrowsing);
}

NS_IMETHODIMP
nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing) {
  return mBrowsingContext->SetPrivateBrowsing(aUsePrivateBrowsing);
}

NS_IMETHODIMP
nsDocShell::GetHasLoadedNonBlankURI(bool* aResult) {
  NS_ENSURE_ARG_POINTER(aResult);

  *aResult = mHasLoadedNonBlankURI;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs) {
  NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
  return mBrowsingContext->GetUseRemoteTabs(aUseRemoteTabs);
}

NS_IMETHODIMP
nsDocShell::SetRemoteTabs(bool aUseRemoteTabs) {
  return mBrowsingContext->SetRemoteTabs(aUseRemoteTabs);
}

NS_IMETHODIMP
nsDocShell::GetUseRemoteSubframes(bool* aUseRemoteSubframes) {
  NS_ENSURE_ARG_POINTER(aUseRemoteSubframes);
  return mBrowsingContext->GetUseRemoteSubframes(aUseRemoteSubframes);
}

NS_IMETHODIMP
nsDocShell::SetRemoteSubframes(bool aUseRemoteSubframes) {
  return mBrowsingContext->SetRemoteSubframes(aUseRemoteSubframes);
}

NS_IMETHODIMP
nsDocShell::AddWeakPrivacyTransitionObserver(
    nsIPrivacyTransitionObserver* aObserver) {
  nsWeakPtr weakObs = do_GetWeakReference(aObserver);
  if (!weakObs) {
    return NS_ERROR_NOT_AVAILABLE;
  }
  mPrivacyObservers.AppendElement(weakObs);
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver) {
  nsWeakPtr weakObs = do_GetWeakReference(aObserver);
  if (!weakObs) {
    return NS_ERROR_FAILURE;
  }
  mReflowObservers.AppendElement(weakObs);
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver) {
  nsWeakPtr obs = do_GetWeakReference(aObserver);
  return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
}

NS_IMETHODIMP
nsDocShell::NotifyReflowObservers(bool aInterruptible,
                                  DOMHighResTimeStamp aStart,
                                  DOMHighResTimeStamp aEnd) {
  nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers);
  while (iter.HasMore()) {
    nsWeakPtr ref = iter.GetNext();
    nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref);
    if (!obs) {
      iter.Remove();
    } else if (aInterruptible) {
      obs->ReflowInterruptible(aStart, aEnd);
    } else {
      obs->Reflow(aStart, aEnd);
    }
  }
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetAllowMetaRedirects(bool* aReturn) {
  NS_ENSURE_ARG_POINTER(aReturn);

  *aReturn = mAllowMetaRedirects;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::SetAllowMetaRedirects(bool aValue) {
  mAllowMetaRedirects = aValue;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetAllowSubframes(bool* aAllowSubframes) {
  NS_ENSURE_ARG_POINTER(aAllowSubframes);

  *aAllowSubframes = mAllowSubframes;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::SetAllowSubframes(bool aAllowSubframes) {
  mAllowSubframes = aAllowSubframes;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetAllowImages(bool* aAllowImages) {
  NS_ENSURE_ARG_POINTER(aAllowImages);

  *aAllowImages = mAllowImages;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::SetAllowImages(bool aAllowImages) {
  mAllowImages = aAllowImages;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::GetAllowMedia(bool* aAllowMedia) {
  *aAllowMedia = mAllowMedia;
  return NS_OK;
}

NS_IMETHODIMP
nsDocShell::SetAllowMedia(bool aAllowMedia) {
  mAllowMedia = aAllowMedia;

  // Mute or unmute audio contexts attached to the inner window.
  if (mScriptGlobal) {
    if (nsPIDOMWindowInner* innerWin = mScriptGlobal->GetCurrentInnerWindow()) {
      if (aAllowMedia) {
        innerWin->UnmuteAudioContexts();
--> --------------------

--> maximum size reached

--> --------------------

98%


[ Verzeichnis aufwärts0.19unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]