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

Quelle  BrowsingContextWebProgress.cpp   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "BrowsingContextWebProgress.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/BounceTrackingState.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/ErrorNames.h"
#include "mozilla/Logging.h"
#include "nsCOMPtr.h"
#include "nsIWebProgressListener.h"
#include "nsString.h"
#include "nsPrintfCString.h"
#include "nsIChannel.h"
#include "xptinfo.h"
#include "mozilla/RefPtr.h"

namespace mozilla {
namespace dom {

static mozilla::LazyLogModule gBCWebProgressLog("BCWebProgress");

static nsCString DescribeBrowsingContext(CanonicalBrowsingContext* aContext);
static nsCString DescribeWebProgress(nsIWebProgress* aWebProgress);
static nsCString DescribeRequest(nsIRequest* aRequest);
static nsCString DescribeWebProgressFlags(uint32_t aFlags,
                                          const nsACString& aPrefix);
static nsCString DescribeError(nsresult aError);

NS_IMPL_CYCLE_COLLECTION(BrowsingContextWebProgress, mCurrentBrowsingContext)

NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowsingContextWebProgress)
NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowsingContextWebProgress)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowsingContextWebProgress)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebProgress)
  NS_INTERFACE_MAP_ENTRY(nsIWebProgress)
  NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_END

BrowsingContextWebProgress::BrowsingContextWebProgress(
    CanonicalBrowsingContext* aBrowsingContext)
    : mCurrentBrowsingContext(aBrowsingContext) {}

BrowsingContextWebProgress::~BrowsingContextWebProgress() = default;

NS_IMETHODIMP BrowsingContextWebProgress::AddProgressListener(
    nsIWebProgressListener* aListener, uint32_t aNotifyMask) {
  nsWeakPtr listener = do_GetWeakReference(aListener);
  if (!listener) {
    return NS_ERROR_INVALID_ARG;
  }

  if (mListenerInfoList.Contains(listener)) {
    // The listener is already registered!
    return NS_ERROR_FAILURE;
  }

  mListenerInfoList.AppendElement(ListenerInfo(listener, aNotifyMask));
  return NS_OK;
}

NS_IMETHODIMP BrowsingContextWebProgress::RemoveProgressListener(
    nsIWebProgressListener* aListener) {
  nsWeakPtr listener = do_GetWeakReference(aListener);
  if (!listener) {
    return NS_ERROR_INVALID_ARG;
  }

  return mListenerInfoList.RemoveElement(listener) ? NS_OK : NS_ERROR_FAILURE;
}

NS_IMETHODIMP BrowsingContextWebProgress::GetBrowsingContextXPCOM(
    BrowsingContext** aBrowsingContext) {
  NS_IF_ADDREF(*aBrowsingContext = mCurrentBrowsingContext);
  return NS_OK;
}

BrowsingContext* BrowsingContextWebProgress::GetBrowsingContext() {
  return mCurrentBrowsingContext;
}

NS_IMETHODIMP BrowsingContextWebProgress::GetDOMWindow(
    mozIDOMWindowProxy** aDOMWindow) {
  return NS_ERROR_NOT_AVAILABLE;
}

NS_IMETHODIMP BrowsingContextWebProgress::GetIsTopLevel(bool* aIsTopLevel) {
  *aIsTopLevel = mCurrentBrowsingContext->IsTop();
  return NS_OK;
}

NS_IMETHODIMP BrowsingContextWebProgress::GetIsLoadingDocument(
    bool* aIsLoadingDocument) {
  *aIsLoadingDocument = mIsLoadingDocument;
  return NS_OK;
}

NS_IMETHODIMP BrowsingContextWebProgress::GetLoadType(uint32_t* aLoadType) {
  *aLoadType = mLoadType;
  return NS_OK;
}

NS_IMETHODIMP BrowsingContextWebProgress::GetTarget(nsIEventTarget** aTarget) {
  return NS_ERROR_NOT_IMPLEMENTED;
}

NS_IMETHODIMP BrowsingContextWebProgress::SetTarget(nsIEventTarget* aTarget) {
  return NS_ERROR_NOT_IMPLEMENTED;
}

void BrowsingContextWebProgress::UpdateAndNotifyListeners(
    uint32_t aFlag,
    const std::function<void(nsIWebProgressListener*)>& aCallback) {
  RefPtr<BrowsingContextWebProgress> kungFuDeathGrip = this;

  ListenerArray::ForwardIterator iter(mListenerInfoList);
  while (iter.HasMore()) {
    ListenerInfo& info = iter.GetNext();
    if (!(info.mNotifyMask & aFlag)) {
      continue;
    }

    nsCOMPtr<nsIWebProgressListener> listener =
        do_QueryReferent(info.mWeakListener);
    if (!listener) {
      mListenerInfoList.RemoveElement(info);
      continue;
    }

    aCallback(listener);
  }

  mListenerInfoList.Compact();

  // Notify the parent BrowsingContextWebProgress of the event to continue
  // propagating.
  auto* parent = mCurrentBrowsingContext->GetParent();
  if (parent && parent->GetWebProgress()) {
    aCallback(parent->GetWebProgress());
  }
}

void BrowsingContextWebProgress::ContextDiscarded() {
  if (mBounceTrackingState) {
    mBounceTrackingState->OnBrowsingContextDiscarded();
  }

  if (!mIsLoadingDocument) {
    return;
  }

  // If our BrowsingContext is being discarded while still loading a document,
  // fire a synthetic `STATE_STOP` to end the ongoing load.
  MOZ_LOG(gBCWebProgressLog, LogLevel::Info,
          ("Discarded while loading %s",
           DescribeBrowsingContext(mCurrentBrowsingContext).get()));

  // This matches what nsDocLoader::doStopDocumentLoad does, except we don't
  // bother notifying for `STATE_STOP | STATE_IS_DOCUMENT`,
  // nsBrowserStatusFilter would filter it out before it gets to the parent
  // process.
  nsCOMPtr<nsIRequest> request = mLoadingDocumentRequest;
  OnStateChange(this, request, STATE_STOP | STATE_IS_WINDOW | STATE_IS_NETWORK,
                NS_ERROR_ABORT);
}

void BrowsingContextWebProgress::ContextReplaced(
    CanonicalBrowsingContext* aNewContext) {
  mCurrentBrowsingContext = aNewContext;
}

already_AddRefed<BounceTrackingState>
BrowsingContextWebProgress::GetBounceTrackingState() {
  if (!mBounceTrackingState) {
    nsresult rv = NS_OK;
    mBounceTrackingState = BounceTrackingState::GetOrCreate(this, rv);
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                         "Failed to get BounceTrackingState.");
  }
  return do_AddRef(mBounceTrackingState);
}

void BrowsingContextWebProgress::DropBounceTrackingState() {
  mBounceTrackingState = nullptr;
}

////////////////////////////////////////////////////////////////////////////////
// nsIWebProgressListener

NS_IMETHODIMP
BrowsingContextWebProgress::OnStateChange(nsIWebProgress* aWebProgress,
                                          nsIRequest* aRequest,
                                          uint32_t aStateFlags,
                                          nsresult aStatus) {
  MOZ_LOG(
      gBCWebProgressLog, LogLevel::Info,
      ("OnStateChange(%s, %s, %s, %s) on %s",
       DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
       DescribeWebProgressFlags(aStateFlags, "STATE_"_ns).get(),
       DescribeError(aStatus).get(),
       DescribeBrowsingContext(mCurrentBrowsingContext).get()));

  bool targetIsThis = aWebProgress == this;

  // We may receive a request from an in-process nsDocShell which doesn't have
  // `aWebProgress == this` which we should still consider as targeting
  // ourselves.
  if (nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
      docShell && docShell->GetBrowsingContext() == mCurrentBrowsingContext) {
    targetIsThis = true;
    aWebProgress->GetLoadType(&mLoadType);
  }

  // Track `mIsLoadingDocument` based on the notifications we've received so far
  // if the nsIWebProgress being targeted is this one.
  if (targetIsThis) {
    constexpr uint32_t startFlags = nsIWebProgressListener::STATE_START |
                                    nsIWebProgressListener::STATE_IS_DOCUMENT |
                                    nsIWebProgressListener::STATE_IS_REQUEST |
                                    nsIWebProgressListener::STATE_IS_WINDOW |
                                    nsIWebProgressListener::STATE_IS_NETWORK;
    constexpr uint32_t stopFlags = nsIWebProgressListener::STATE_STOP |
                                   nsIWebProgressListener::STATE_IS_WINDOW;
    constexpr uint32_t redirectFlags =
        nsIWebProgressListener::STATE_IS_REDIRECTED_DOCUMENT;
    if ((aStateFlags & startFlags) == startFlags) {
      if (mIsLoadingDocument) {
        // We received a duplicate `STATE_START` notification, silence this
        // notification until we receive the matching `STATE_STOP` to not fire
        // duplicate `STATE_START` notifications into frontend on process
        // switches.
        return NS_OK;
      }
      mIsLoadingDocument = true;

      // Record the request we started the load with, so we can emit a synthetic
      // `STATE_STOP` notification if the BrowsingContext is discarded before
      // the notification arrives.
      mLoadingDocumentRequest = aRequest;
    } else if ((aStateFlags & stopFlags) == stopFlags) {
      // We've received a `STATE_STOP` notification targeting this web progress,
      // clear our loading document flag.
      mIsLoadingDocument = false;
      mLoadingDocumentRequest = nullptr;
    } else if (mIsLoadingDocument &&
               (aStateFlags & redirectFlags) == redirectFlags) {
      // If we see a redirected document load, update the loading request which
      // we'll emit the synthetic STATE_STOP notification with.
      mLoadingDocumentRequest = aRequest;
    }
  }

  UpdateAndNotifyListeners(
      ((aStateFlags >> 16) & nsIWebProgress::NOTIFY_STATE_ALL),
      [&](nsIWebProgressListener* listener) {
        listener->OnStateChange(aWebProgress, aRequest, aStateFlags, aStatus);
      });
  return NS_OK;
}

NS_IMETHODIMP
BrowsingContextWebProgress::OnProgressChange(nsIWebProgress* aWebProgress,
                                             nsIRequest* aRequest,
                                             int32_t aCurSelfProgress,
                                             int32_t aMaxSelfProgress,
                                             int32_t aCurTotalProgress,
                                             int32_t aMaxTotalProgress) {
  MOZ_LOG(
      gBCWebProgressLog, LogLevel::Info,
      ("OnProgressChange(%s, %s, %d, %d, %d, %d) on %s",
       DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
       aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress,
       DescribeBrowsingContext(mCurrentBrowsingContext).get()));
  UpdateAndNotifyListeners(
      nsIWebProgress::NOTIFY_PROGRESS, [&](nsIWebProgressListener* listener) {
        listener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress,
                                   aMaxSelfProgress, aCurTotalProgress,
                                   aMaxTotalProgress);
      });
  return NS_OK;
}

NS_IMETHODIMP
BrowsingContextWebProgress::OnLocationChange(nsIWebProgress* aWebProgress,
                                             nsIRequest* aRequest,
                                             nsIURI* aLocation,
                                             uint32_t aFlags) {
  MOZ_LOG(
      gBCWebProgressLog, LogLevel::Info,
      ("OnLocationChange(%s, %s, %s, %s) on %s",
       DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
       aLocation ? aLocation->GetSpecOrDefault().get() : "",
       DescribeWebProgressFlags(aFlags, "LOCATION_CHANGE_"_ns).get(),
       DescribeBrowsingContext(mCurrentBrowsingContext).get()));
  UpdateAndNotifyListeners(
      nsIWebProgress::NOTIFY_LOCATION, [&](nsIWebProgressListener* listener) {
        listener->OnLocationChange(aWebProgress, aRequest, aLocation, aFlags);
      });
  return NS_OK;
}

NS_IMETHODIMP
BrowsingContextWebProgress::OnStatusChange(nsIWebProgress* aWebProgress,
                                           nsIRequest* aRequest,
                                           nsresult aStatus,
                                           const char16_t* aMessage) {
  MOZ_LOG(
      gBCWebProgressLog, LogLevel::Info,
      ("OnStatusChange(%s, %s, %s, \"%s\") on %s",
       DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
       DescribeError(aStatus).get(), NS_ConvertUTF16toUTF8(aMessage).get(),
       DescribeBrowsingContext(mCurrentBrowsingContext).get()));
  UpdateAndNotifyListeners(
      nsIWebProgress::NOTIFY_STATUS, [&](nsIWebProgressListener* listener) {
        listener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
      });
  return NS_OK;
}

NS_IMETHODIMP
BrowsingContextWebProgress::OnSecurityChange(nsIWebProgress* aWebProgress,
                                             nsIRequest* aRequest,
                                             uint32_t aState) {
  MOZ_LOG(
      gBCWebProgressLog, LogLevel::Info,
      ("OnSecurityChange(%s, %s, %x) on %s",
       DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
       aState, DescribeBrowsingContext(mCurrentBrowsingContext).get()));
  UpdateAndNotifyListeners(
      nsIWebProgress::NOTIFY_SECURITY, [&](nsIWebProgressListener* listener) {
        listener->OnSecurityChange(aWebProgress, aRequest, aState);
      });
  return NS_OK;
}

NS_IMETHODIMP
BrowsingContextWebProgress::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
                                                   nsIRequest* aRequest,
                                                   uint32_t aEvent) {
  MOZ_LOG(
      gBCWebProgressLog, LogLevel::Info,
      ("OnContentBlockingEvent(%s, %s, %x) on %s",
       DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
       aEvent, DescribeBrowsingContext(mCurrentBrowsingContext).get()));
  UpdateAndNotifyListeners(nsIWebProgress::NOTIFY_CONTENT_BLOCKING,
                           [&](nsIWebProgressListener* listener) {
                             listener->OnContentBlockingEvent(aWebProgress,
                                                              aRequest, aEvent);
                           });
  return NS_OK;
}

NS_IMETHODIMP
BrowsingContextWebProgress::GetDocumentRequest(nsIRequest** aRequest) {
  NS_IF_ADDREF(*aRequest = mLoadingDocumentRequest);
  return NS_OK;
}

////////////////////////////////////////////////////////////////////////////////
// Helper methods for notification logging

static nsCString DescribeBrowsingContext(CanonicalBrowsingContext* aContext) {
  if (!aContext) {
    return ""_ns;
  }

  nsCOMPtr<nsIURI> currentURI = aContext->GetCurrentURI();
  return nsPrintfCString(
      "{top:%d, id:%" PRIx64 ", url:%s}", aContext->IsTop(), aContext->Id(),
      currentURI ? currentURI->GetSpecOrDefault().get() : "");
}

static nsCString DescribeWebProgress(nsIWebProgress* aWebProgress) {
  if (!aWebProgress) {
    return ""_ns;
  }

  bool isTopLevel = false;
  aWebProgress->GetIsTopLevel(&isTopLevel);
  bool isLoadingDocument = false;
  aWebProgress->GetIsLoadingDocument(&isLoadingDocument);
  return nsPrintfCString("{isTopLevel:%d, isLoadingDocument:%d}", isTopLevel,
                         isLoadingDocument);
}

static nsCString DescribeRequest(nsIRequest* aRequest) {
  if (!aRequest) {
    return ""_ns;
  }

  nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
  if (!channel) {
    return ""_ns;
  }

  nsCOMPtr<nsIURI> originalURI;
  channel->GetOriginalURI(getter_AddRefs(originalURI));
  nsCOMPtr<nsIURI> uri;
  channel->GetURI(getter_AddRefs(uri));

  return nsPrintfCString(
      "{URI:%s, originalURI:%s}",
      uri ? uri->GetSpecOrDefault().get() : "",
      originalURI ? originalURI->GetSpecOrDefault().get() : "");
}

static nsCString DescribeWebProgressFlags(uint32_t aFlags,
                                          const nsACString& aPrefix) {
  nsCString flags;
  uint32_t remaining = aFlags;

  // Hackily fetch the names of each constant from the XPT information used for
  // reflecting it into JS. This doesn't need to be reliable and just exists as
  // a logging aid.
  //
  // If a change to xpt in the future breaks this code, just delete it and
  // replace it with a normal hex log.
  if (const auto* ifaceInfo =
          nsXPTInterfaceInfo::ByIID(NS_GET_IID(nsIWebProgressListener))) {
    for (uint16_t i = 0; i < ifaceInfo->ConstantCount(); ++i) {
      const auto& constInfo = ifaceInfo->Constant(i);
      nsDependentCString name(constInfo.Name());
      if (!StringBeginsWith(name, aPrefix)) {
        continue;
      }

      if (remaining & constInfo.mValue) {
        remaining &= ~constInfo.mValue;
        if (!flags.IsEmpty()) {
          flags.AppendLiteral("|");
        }
        flags.Append(name);
      }
    }
  }
  if (remaining != 0 || flags.IsEmpty()) {
    if (!flags.IsEmpty()) {
      flags.AppendLiteral("|");
    }
    flags.AppendInt(remaining, 16);
  }
  return flags;
}

static nsCString DescribeError(nsresult aError) {
  nsCString name;
  GetErrorName(aError, name);
  return name;
}

}  // namespace dom
}  // namespace mozilla

97%


¤ Dauer der Verarbeitung: 0.23 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.