tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WindowContext.cpp (30615B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/WindowContext.h"
      8 #include "mozilla/dom/WindowGlobalActorsBinding.h"
      9 #include "mozilla/dom/WindowGlobalChild.h"
     10 #include "mozilla/dom/WindowGlobalParent.h"
     11 #include "mozilla/dom/SyncedContextInlines.h"
     12 #include "mozilla/dom/BrowsingContext.h"
     13 #include "mozilla/dom/CloseWatcherManager.h"
     14 #include "mozilla/dom/Document.h"
     15 #include "mozilla/dom/DocumentPictureInPicture.h"
     16 #include "mozilla/dom/UserActivationIPCUtils.h"
     17 #include "mozilla/dom/WorkerCommon.h"
     18 #include "mozilla/PermissionDelegateIPCUtils.h"
     19 #include "mozilla/StaticPrefs_dom.h"
     20 #include "mozilla/StaticPtr.h"
     21 #include "mozilla/ClearOnShutdown.h"
     22 #include "nsGlobalWindowInner.h"
     23 #include "nsIScriptError.h"
     24 #include "nsIWebProgressListener.h"
     25 #include "nsIXULRuntime.h"
     26 #include "nsRFPTargetSetIDL.h"
     27 #include "nsRefPtrHashtable.h"
     28 #include "nsContentUtils.h"
     29 
     30 namespace mozilla {
     31 namespace dom {
     32 
     33 // Explicit specialization of the `Transaction` type. Required by the `extern
     34 // template class` declaration in the header.
     35 template class syncedcontext::Transaction<WindowContext>;
     36 
     37 static LazyLogModule gWindowContextLog("WindowContext");
     38 static LazyLogModule gWindowContextSyncLog("WindowContextSync");
     39 
     40 extern mozilla::LazyLogModule gUserInteractionPRLog;
     41 
     42 #define USER_ACTIVATION_LOG(msg, ...) \
     43  MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
     44 
     45 using WindowContextByIdMap = nsTHashMap<nsUint64HashKey, WindowContext*>;
     46 static StaticAutoPtr<WindowContextByIdMap> gWindowContexts;
     47 
     48 /* static */
     49 LogModule* WindowContext::GetLog() { return gWindowContextLog; }
     50 
     51 /* static */
     52 LogModule* WindowContext::GetSyncLog() { return gWindowContextSyncLog; }
     53 
     54 /* static */
     55 already_AddRefed<WindowContext> WindowContext::GetById(
     56    uint64_t aInnerWindowId) {
     57  if (!gWindowContexts) {
     58    return nullptr;
     59  }
     60  return do_AddRef(gWindowContexts->Get(aInnerWindowId));
     61 }
     62 
     63 BrowsingContextGroup* WindowContext::Group() const {
     64  return mBrowsingContext->Group();
     65 }
     66 
     67 WindowGlobalParent* WindowContext::Canonical() {
     68  MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
     69  return static_cast<WindowGlobalParent*>(this);
     70 }
     71 
     72 bool WindowContext::IsCurrent() const {
     73  return mBrowsingContext->mCurrentWindowContext == this;
     74 }
     75 
     76 bool WindowContext::IsInBFCache() {
     77  if (mozilla::SessionHistoryInParent()) {
     78    return mBrowsingContext->IsInBFCache();
     79  }
     80  return TopWindowContext()->GetWindowStateSaved();
     81 }
     82 
     83 already_AddRefed<nsIRFPTargetSetIDL>
     84 WindowContext::GetOverriddenFingerprintingSettingsWebIDL() const {
     85  Maybe<RFPTargetSet> overriddenFingerprintingSettings =
     86      GetOverriddenFingerprintingSettings();
     87  if (overriddenFingerprintingSettings.isNothing()) {
     88    return nullptr;
     89  }
     90 
     91  nsCOMPtr<nsIRFPTargetSetIDL> protections =
     92      new nsRFPTargetSetIDL(overriddenFingerprintingSettings.ref());
     93  return protections.forget();
     94 }
     95 
     96 nsGlobalWindowInner* WindowContext::GetInnerWindow() const {
     97  return mWindowGlobalChild ? mWindowGlobalChild->GetWindowGlobal() : nullptr;
     98 }
     99 
    100 Document* WindowContext::GetDocument() const {
    101  nsGlobalWindowInner* innerWindow = GetInnerWindow();
    102  return innerWindow ? innerWindow->GetDocument() : nullptr;
    103 }
    104 
    105 Document* WindowContext::GetExtantDoc() const {
    106  nsGlobalWindowInner* innerWindow = GetInnerWindow();
    107  return innerWindow ? innerWindow->GetExtantDoc() : nullptr;
    108 }
    109 
    110 WindowGlobalChild* WindowContext::GetWindowGlobalChild() const {
    111  return mWindowGlobalChild;
    112 }
    113 
    114 WindowContext* WindowContext::GetParentWindowContext() {
    115  return mBrowsingContext->GetParentWindowContext();
    116 }
    117 
    118 WindowContext* WindowContext::TopWindowContext() {
    119  WindowContext* current = this;
    120  while (current->GetParentWindowContext()) {
    121    current = current->GetParentWindowContext();
    122  }
    123  return current;
    124 }
    125 
    126 bool WindowContext::IsTop() const { return mBrowsingContext->IsTop(); }
    127 
    128 bool WindowContext::SameOriginWithTop() const {
    129  return mBrowsingContext->SameOriginWithTop();
    130 }
    131 
    132 nsIGlobalObject* WindowContext::GetParentObject() const {
    133  return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
    134 }
    135 
    136 void WindowContext::AppendChildBrowsingContext(
    137    BrowsingContext* aBrowsingContext) {
    138  MOZ_DIAGNOSTIC_ASSERT(Group() == aBrowsingContext->Group(),
    139                        "Mismatched groups?");
    140  MOZ_DIAGNOSTIC_ASSERT(!mChildren.Contains(aBrowsingContext));
    141 
    142  ClearLightDOMChildren();
    143 
    144  mChildren.AppendElement(aBrowsingContext);
    145  if (!aBrowsingContext->IsEmbedderTypeObjectOrEmbed()) {
    146    mNonSyntheticChildren.AppendElement(aBrowsingContext);
    147  }
    148 
    149  // If we're the current WindowContext in our BrowsingContext, make sure to
    150  // clear any cached `children` value.
    151  if (IsCurrent()) {
    152    BrowsingContext_Binding::ClearCachedChildrenValue(mBrowsingContext);
    153  }
    154 }
    155 
    156 void WindowContext::RemoveChildBrowsingContext(
    157    BrowsingContext* aBrowsingContext) {
    158  MOZ_DIAGNOSTIC_ASSERT(Group() == aBrowsingContext->Group(),
    159                        "Mismatched groups?");
    160  ClearLightDOMChildren();
    161 
    162  mChildren.RemoveElement(aBrowsingContext);
    163  mNonSyntheticChildren.RemoveElement(aBrowsingContext);
    164 
    165  // If we're the current WindowContext in our BrowsingContext, make sure to
    166  // clear any cached `children` value.
    167  if (IsCurrent()) {
    168    BrowsingContext_Binding::ClearCachedChildrenValue(mBrowsingContext);
    169  }
    170 }
    171 
    172 void WindowContext::UpdateChildSynthetic(BrowsingContext* aBrowsingContext,
    173                                         bool aIsSynthetic) {
    174  if (aIsSynthetic) {
    175    mNonSyntheticChildren.RemoveElement(aBrowsingContext);
    176  } else {
    177    // The same BrowsingContext will be reused for error pages, so it can be in
    178    // the list already.
    179    if (!mNonSyntheticChildren.Contains(aBrowsingContext)) {
    180      mNonSyntheticChildren.AppendElement(aBrowsingContext);
    181    }
    182  }
    183 }
    184 
    185 void WindowContext::ClearLightDOMChildren() {
    186  mNonSyntheticLightDOMChildren.reset();
    187 }
    188 
    189 void WindowContext::EnsureLightDOMChildren() {
    190  if (mNonSyntheticLightDOMChildren.isSome()) {
    191    return;
    192  }
    193  mNonSyntheticLightDOMChildren.emplace();
    194 
    195  for (const RefPtr<BrowsingContext>& bc : mNonSyntheticChildren) {
    196    if (Element* el = bc->GetEmbedderElement(); el && el->IsInShadowTree()) {
    197      continue;
    198    }
    199    mNonSyntheticLightDOMChildren->AppendElement(bc);
    200  }
    201 }
    202 
    203 BrowsingContext* WindowContext::NonSyntheticLightDOMChildAt(uint32_t aIndex) {
    204  EnsureLightDOMChildren();
    205  return aIndex < mNonSyntheticLightDOMChildren->Length()
    206             ? mNonSyntheticLightDOMChildren->ElementAt(aIndex).get()
    207             : nullptr;
    208 }
    209 
    210 uint32_t WindowContext::NonSyntheticLightDOMChildrenCount() {
    211  EnsureLightDOMChildren();
    212  return mNonSyntheticLightDOMChildren->Length();
    213 }
    214 
    215 void WindowContext::SendCommitTransaction(ContentParent* aParent,
    216                                          const BaseTransaction& aTxn,
    217                                          uint64_t aEpoch) {
    218  (void)aParent->SendCommitWindowContextTransaction(this, aTxn, aEpoch);
    219 }
    220 
    221 void WindowContext::SendCommitTransaction(ContentChild* aChild,
    222                                          const BaseTransaction& aTxn,
    223                                          uint64_t aEpoch) {
    224  aChild->SendCommitWindowContextTransaction(this, aTxn, aEpoch);
    225 }
    226 
    227 bool WindowContext::CheckOnlyOwningProcessCanSet(ContentParent* aSource) {
    228  if (IsInProcess()) {
    229    return true;
    230  }
    231 
    232  if (XRE_IsParentProcess() && aSource) {
    233    return Canonical()->GetContentParent() == aSource;
    234  }
    235 
    236  return false;
    237 }
    238 
    239 bool WindowContext::CanSet(FieldIndex<IDX_IsSecure>, const bool& aIsSecure,
    240                           ContentParent* aSource) {
    241  return CheckOnlyOwningProcessCanSet(aSource);
    242 }
    243 
    244 bool WindowContext::CanSet(FieldIndex<IDX_NeedsBeforeUnload>,
    245                           const bool& aHasBeforeUnload,
    246                           ContentParent* aSource) {
    247  return CheckOnlyOwningProcessCanSet(aSource);
    248 }
    249 
    250 bool WindowContext::CanSet(FieldIndex<IDX_NeedsTraverse>,
    251                           const bool& aNeedsTraverse, ContentParent* aSource) {
    252  return CheckOnlyOwningProcessCanSet(aSource);
    253 }
    254 
    255 bool WindowContext::CanSet(FieldIndex<IDX_CookieBehavior>,
    256                           const Maybe<uint32_t>& aValue,
    257                           ContentParent* aSource) {
    258  return CheckOnlyOwningProcessCanSet(aSource);
    259 }
    260 
    261 bool WindowContext::CanSet(FieldIndex<IDX_IsOnContentBlockingAllowList>,
    262                           const bool& aValue, ContentParent* aSource) {
    263  return CheckOnlyOwningProcessCanSet(aSource);
    264 }
    265 
    266 bool WindowContext::CanSet(FieldIndex<IDX_IsThirdPartyWindow>,
    267                           const bool& IsThirdPartyWindow,
    268                           ContentParent* aSource) {
    269  return CheckOnlyOwningProcessCanSet(aSource);
    270 }
    271 
    272 bool WindowContext::CanSet(FieldIndex<IDX_IsThirdPartyTrackingResourceWindow>,
    273                           const bool& aIsThirdPartyTrackingResourceWindow,
    274                           ContentParent* aSource) {
    275  return CheckOnlyOwningProcessCanSet(aSource);
    276 }
    277 
    278 bool WindowContext::CanSet(FieldIndex<IDX_UsingStorageAccess>,
    279                           const bool& aUsingStorageAccess,
    280                           ContentParent* aSource) {
    281  return CheckOnlyOwningProcessCanSet(aSource);
    282 }
    283 
    284 bool WindowContext::CanSet(FieldIndex<IDX_ShouldResistFingerprinting>,
    285                           const bool& aShouldResistFingerprinting,
    286                           ContentParent* aSource) {
    287  return CheckOnlyOwningProcessCanSet(aSource);
    288 }
    289 
    290 bool WindowContext::CanSet(FieldIndex<IDX_OverriddenFingerprintingSettings>,
    291                           const Maybe<RFPTargetSet>& aValue,
    292                           ContentParent* aSource) {
    293  return CheckOnlyOwningProcessCanSet(aSource);
    294 }
    295 
    296 bool WindowContext::CanSet(FieldIndex<IDX_IsSecureContext>,
    297                           const bool& aIsSecureContext,
    298                           ContentParent* aSource) {
    299  return CheckOnlyOwningProcessCanSet(aSource);
    300 }
    301 
    302 bool WindowContext::CanSet(FieldIndex<IDX_IsOriginalFrameSource>,
    303                           const bool& aIsOriginalFrameSource,
    304                           ContentParent* aSource) {
    305  return CheckOnlyOwningProcessCanSet(aSource);
    306 }
    307 
    308 bool WindowContext::CanSet(FieldIndex<IDX_DocTreeHadMedia>, const bool& aValue,
    309                           ContentParent* aSource) {
    310  return IsTop();
    311 }
    312 
    313 bool WindowContext::CanSet(FieldIndex<IDX_AutoplayPermission>,
    314                           const uint32_t& aValue, ContentParent* aSource) {
    315  return CheckOnlyOwningProcessCanSet(aSource);
    316 }
    317 
    318 bool WindowContext::CanSet(FieldIndex<IDX_ShortcutsPermission>,
    319                           const uint32_t& aValue, ContentParent* aSource) {
    320  return IsTop() && CheckOnlyOwningProcessCanSet(aSource);
    321 }
    322 
    323 bool WindowContext::CanSet(FieldIndex<IDX_ActiveMediaSessionContextId>,
    324                           const Maybe<uint64_t>& aValue,
    325                           ContentParent* aSource) {
    326  return IsTop();
    327 }
    328 
    329 bool WindowContext::CanSet(FieldIndex<IDX_PopupPermission>, const uint32_t&,
    330                           ContentParent* aSource) {
    331  return CheckOnlyOwningProcessCanSet(aSource);
    332 }
    333 
    334 bool WindowContext::CanSet(
    335    FieldIndex<IDX_DelegatedPermissions>,
    336    const PermissionDelegateHandler::DelegatedPermissionList& aValue,
    337    ContentParent* aSource) {
    338  return CheckOnlyOwningProcessCanSet(aSource);
    339 }
    340 
    341 bool WindowContext::CanSet(
    342    FieldIndex<IDX_DelegatedExactHostMatchPermissions>,
    343    const PermissionDelegateHandler::DelegatedPermissionList& aValue,
    344    ContentParent* aSource) {
    345  return CheckOnlyOwningProcessCanSet(aSource);
    346 }
    347 
    348 bool WindowContext::CanSet(FieldIndex<IDX_IsLocalIP>, const bool& aValue,
    349                           ContentParent* aSource) {
    350  return CheckOnlyOwningProcessCanSet(aSource);
    351 }
    352 
    353 bool WindowContext::CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue,
    354                           ContentParent* aSource) {
    355  return (XRE_IsParentProcess() && !aSource) ||
    356         CheckOnlyOwningProcessCanSet(aSource);
    357 }
    358 
    359 void WindowContext::DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue) {
    360  RecomputeCanExecuteScripts();
    361 }
    362 
    363 bool WindowContext::CanSet(FieldIndex<IDX_HasActivePeerConnections>, bool,
    364                           ContentParent*) {
    365  return XRE_IsParentProcess() && IsTop();
    366 }
    367 
    368 void WindowContext::ProcessCloseRequest() {
    369  MOZ_ASSERT(XRE_IsParentProcess(), "Window must be Global Parent");
    370  BrowsingContext* top = mBrowsingContext->Top();
    371  top->PreOrderWalk([&](BrowsingContext* aBrowsingContext) {
    372    CanonicalBrowsingContext* canonical = aBrowsingContext->Canonical();
    373    if (WindowGlobalParent* parent = canonical->GetCurrentWindowGlobal()) {
    374      (void)parent->SendProcessCloseRequest(aBrowsingContext);
    375    }
    376  });
    377 }
    378 
    379 void WindowContext::RecomputeCanExecuteScripts(bool aApplyChanges) {
    380  const bool old = mCanExecuteScripts;
    381  if (!AllowJavascript()) {
    382    // Scripting has been explicitly disabled on our WindowContext.
    383    mCanExecuteScripts = false;
    384  } else {
    385    // Otherwise, inherit.
    386    mCanExecuteScripts = mBrowsingContext->CanExecuteScripts();
    387  }
    388 
    389  if (aApplyChanges && old != mCanExecuteScripts) {
    390    // Inform our active DOM window.
    391    if (nsGlobalWindowInner* window = GetInnerWindow()) {
    392      // Only update scriptability if the window is current. Windows will have
    393      // scriptability disabled when entering the bfcache and updated when
    394      // coming out.
    395      if (window->IsCurrentInnerWindow()) {
    396        auto& scriptability =
    397            xpc::Scriptability::Get(window->GetGlobalJSObject());
    398        scriptability.SetWindowAllowsScript(mCanExecuteScripts);
    399      }
    400    }
    401 
    402    for (const RefPtr<BrowsingContext>& child : Children()) {
    403      child->RecomputeCanExecuteScripts();
    404    }
    405  }
    406 }
    407 
    408 void WindowContext::DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>,
    409                           bool aOldValue) {
    410  MOZ_ASSERT(
    411      TopWindowContext() == this,
    412      "SHEntryHasUserInteraction can only be set on the top window context");
    413  // This field is set when the child notifies us of new user interaction, so we
    414  // also set the currently active shentry in the parent as having interaction.
    415  if (XRE_IsParentProcess() && mBrowsingContext) {
    416    SessionHistoryEntry* activeEntry =
    417        mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
    418    if (activeEntry && GetSHEntryHasUserInteraction()) {
    419      activeEntry->SetHasUserInteraction(true);
    420    }
    421  }
    422 }
    423 
    424 void WindowContext::DidSet(FieldIndex<IDX_HasActivePeerConnections>,
    425                           bool aOldValue) {
    426  MOZ_ASSERT(
    427      TopWindowContext() == this,
    428      "IDX_HasActivePeerConnections can only be set on the top window context");
    429 
    430  BrowsingContext* top = mBrowsingContext->Top();
    431 
    432  top->PreOrderWalk([&](BrowsingContext* aBrowsingContext) {
    433    WindowContext* windowContext = aBrowsingContext->GetCurrentWindowContext();
    434    if (windowContext) {
    435      auto* win{windowContext->GetInnerWindow()};
    436      if (win && (aOldValue != win->HasActivePeerConnections())) {
    437        dom::UpdateWorkersPeerConnections(*win,
    438                                          win->HasActivePeerConnections());
    439      }
    440    }
    441  });
    442 }
    443 
    444 void WindowContext::DidSet(FieldIndex<IDX_UserActivationStateAndModifiers>) {
    445  MOZ_ASSERT_IF(!IsInProcess(), mLastActivationTimestamp.IsNull());
    446  USER_ACTIVATION_LOG("Set user gesture activation 0x%02" PRIu8
    447                      " for %s browsing context 0x%08" PRIx64,
    448                      GetUserActivationStateAndModifiers(),
    449                      XRE_IsParentProcess() ? "Parent" : "Child", Id());
    450  if (IsInProcess()) {
    451    USER_ACTIVATION_LOG(
    452        "Set user gesture start time for %s browsing context 0x%08" PRIx64,
    453        XRE_IsParentProcess() ? "Parent" : "Child", Id());
    454    if (GetUserActivationState() == UserActivation::State::FullActivated) {
    455      mLastActivationTimestamp = TimeStamp::Now();
    456    } else if (GetUserActivationState() == UserActivation::State::None) {
    457      mLastActivationTimestamp = TimeStamp();
    458    }
    459  }
    460 }
    461 
    462 void WindowContext::DidSet(FieldIndex<IDX_HasReportedShadowDOMUsage>,
    463                           bool aOldValue) {
    464  if (!aOldValue && GetHasReportedShadowDOMUsage() && IsInProcess()) {
    465    MOZ_ASSERT(TopWindowContext() == this);
    466    if (mBrowsingContext) {
    467      Document* topLevelDoc = mBrowsingContext->GetDocument();
    468      if (topLevelDoc) {
    469        nsAutoString uri;
    470        (void)topLevelDoc->GetDocumentURI(uri);
    471        if (!uri.IsEmpty()) {
    472          nsAutoString msg = u"Shadow DOM used in ["_ns + uri +
    473                             u"] or in some of its subdocuments."_ns;
    474          nsContentUtils::ReportToConsoleNonLocalized(
    475              msg, nsIScriptError::infoFlag, "DOM"_ns, topLevelDoc);
    476        }
    477      }
    478    }
    479  }
    480 }
    481 
    482 bool WindowContext::CanSet(FieldIndex<IDX_WindowStateSaved>, bool aValue,
    483                           ContentParent* aSource) {
    484  return !mozilla::SessionHistoryInParent() && IsTop() &&
    485         CheckOnlyOwningProcessCanSet(aSource);
    486 }
    487 
    488 void WindowContext::CreateFromIPC(IPCInitializer&& aInit) {
    489  MOZ_RELEASE_ASSERT(XRE_IsContentProcess(),
    490                     "Should be a WindowGlobalParent in the parent");
    491 
    492  RefPtr<BrowsingContext> bc = BrowsingContext::Get(aInit.mBrowsingContextId);
    493  MOZ_RELEASE_ASSERT(bc);
    494 
    495  if (bc->IsDiscarded()) {
    496    // If we have already closed our browsing context, the
    497    // WindowGlobalChild actor is bound to be destroyed soon and it's
    498    // safe to ignore creating the WindowContext.
    499    return;
    500  }
    501 
    502  RefPtr<WindowContext> context = new WindowContext(
    503      bc, aInit.mInnerWindowId, aInit.mOuterWindowId, std::move(aInit.mFields));
    504  context->Init();
    505 }
    506 
    507 void WindowContext::Init() {
    508  MOZ_LOG(GetLog(), LogLevel::Debug,
    509          ("Registering 0x%" PRIx64 " (bc=0x%" PRIx64 ")", mInnerWindowId,
    510           mBrowsingContext->Id()));
    511 
    512  // Register the WindowContext in the `WindowContextByIdMap`.
    513  if (!gWindowContexts) {
    514    gWindowContexts = new WindowContextByIdMap();
    515    ClearOnShutdown(&gWindowContexts);
    516  }
    517  auto& entry = gWindowContexts->LookupOrInsert(mInnerWindowId);
    518  MOZ_RELEASE_ASSERT(!entry, "Duplicate WindowContext for ID!");
    519  entry = this;
    520 
    521  // Register this to the browsing context.
    522  mBrowsingContext->RegisterWindowContext(this);
    523  Group()->Register(this);
    524 }
    525 
    526 void WindowContext::Discard() {
    527  MOZ_LOG(GetLog(), LogLevel::Debug,
    528          ("Discarding 0x%" PRIx64 " (bc=0x%" PRIx64 ")", mInnerWindowId,
    529           mBrowsingContext->Id()));
    530  if (mIsDiscarded) {
    531    return;
    532  }
    533 
    534  mIsDiscarded = true;
    535  if (gWindowContexts) {
    536    gWindowContexts->Remove(InnerWindowId());
    537  }
    538  mBrowsingContext->UnregisterWindowContext(this);
    539  Group()->Unregister(this);
    540 }
    541 
    542 void WindowContext::AddSecurityState(uint32_t aStateFlags) {
    543  MOZ_ASSERT(TopWindowContext() == this);
    544  MOZ_ASSERT((aStateFlags &
    545              (nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
    546               nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
    547               nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT |
    548               nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT |
    549               nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED |
    550               nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED |
    551               nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED_FIRST)) ==
    552                 aStateFlags,
    553             "Invalid flags specified!");
    554 
    555  if (XRE_IsParentProcess()) {
    556    Canonical()->AddSecurityState(aStateFlags);
    557  } else {
    558    ContentChild* child = ContentChild::GetSingleton();
    559    child->SendAddSecurityState(this, aStateFlags);
    560  }
    561 }
    562 
    563 void WindowContext::NotifyUserGestureActivation(
    564    UserActivation::Modifiers
    565        aModifiers /* = UserActivation::Modifiers::None() */) {
    566  UserActivation::StateAndModifiers stateAndModifiers;
    567  stateAndModifiers.SetState(UserActivation::State::FullActivated);
    568  stateAndModifiers.SetModifiers(aModifiers);
    569  if (auto* innerWindow = GetInnerWindow()) {
    570    innerWindow->EnsureCloseWatcherManager()->NotifyUserInteraction();
    571  }
    572  (void)SetUserActivationStateAndModifiers(stateAndModifiers.GetRawData());
    573 }
    574 
    575 void WindowContext::NotifyResetUserGestureActivation() {
    576  UserActivation::StateAndModifiers stateAndModifiers;
    577  stateAndModifiers.SetState(UserActivation::State::None);
    578  (void)SetUserActivationStateAndModifiers(stateAndModifiers.GetRawData());
    579 }
    580 
    581 bool WindowContext::HasBeenUserGestureActivated() {
    582  return GetUserActivationState() != UserActivation::State::None;
    583 }
    584 
    585 const TimeStamp& WindowContext::GetUserGestureStart() const {
    586  MOZ_ASSERT(IsInProcess());
    587  return mLastActivationTimestamp;
    588 }
    589 
    590 // https://html.spec.whatwg.org/#transient-activation
    591 bool WindowContext::HasValidTransientUserGestureActivation() {
    592  MOZ_ASSERT(IsInProcess());
    593 
    594  if (GetUserActivationState() != UserActivation::State::FullActivated) {
    595    // mLastActivationTimestamp should be null if the document hasn't ever been
    596    // activated by user gesture
    597    MOZ_ASSERT_IF(GetUserActivationState() == UserActivation::State::None,
    598                  mLastActivationTimestamp.IsNull());
    599    return false;
    600  }
    601 
    602  MOZ_ASSERT(
    603      !mLastActivationTimestamp.IsNull(),
    604      "mLastActivationTimestamp shouldn't be null if the document has ever "
    605      "been activated by user gesture");
    606 
    607  TimeDuration timeout = TimeDuration::FromMilliseconds(
    608      StaticPrefs::dom_user_activation_transient_timeout());
    609 
    610  // "When the current high resolution time given W is greater than or equal to
    611  // the last activation timestamp in W, and less than the last activation
    612  // timestamp in W plus the transient activation duration, then W is said to
    613  // have transient activation."
    614  return timeout <= TimeDuration() ||
    615         (TimeStamp::Now() - mLastActivationTimestamp) <= timeout;
    616 }
    617 
    618 template <typename F>
    619 static void ConsumeUserGestureActivationBetweenPiP(BrowsingContext* aTop,
    620                                                   F&& aCallback) {
    621  // https://wicg.github.io/document-picture-in-picture/#user-activation-propagation
    622  // Monkey patch to consume user activation
    623  if (aTop->GetIsDocumentPiP()) {
    624    // 4. If top is a PIP window, then extend navigables with the opener
    625    // window's inclusive decendant navigables
    626    RefPtr<BrowsingContext> opener = aTop->GetOpener();
    627    if (!opener) {
    628      return;
    629    }
    630    opener->GetBrowsingContext()->PreOrderWalk(aCallback);
    631  } else {
    632    // 5. Get top-level navigable's last opened PiP window
    633    nsPIDOMWindowOuter* outer = aTop->GetDOMWindow();
    634    NS_ENSURE_TRUE_VOID(outer);
    635    nsPIDOMWindowInner* inner = outer->GetCurrentInnerWindow();
    636    NS_ENSURE_TRUE_VOID(inner);
    637    DocumentPictureInPicture* dpip = inner->GetExtantDocumentPictureInPicture();
    638    if (!dpip) {
    639      return;
    640    }
    641    nsGlobalWindowInner* pip = dpip->GetWindow();
    642    if (!pip) {
    643      return;
    644    }
    645 
    646    // 6. Extend navigables with the inclusive descendant navigables of the PIP
    647    // window.
    648    BrowsingContext* pipBC = pip->GetBrowsingContext();
    649    NS_ENSURE_TRUE_VOID(pipBC);
    650    WindowContext* pipWC = pipBC->GetCurrentWindowContext();
    651    NS_ENSURE_TRUE_VOID(pipWC);
    652    pipBC->PreOrderWalk(aCallback);
    653  }
    654 }
    655 
    656 // https://html.spec.whatwg.org/#consume-user-activation
    657 bool WindowContext::ConsumeTransientUserGestureActivation() {
    658  MOZ_ASSERT(IsInProcess());
    659  // 1. If W's navigable is null, then return.
    660  if (!IsCurrent()) {
    661    return false;
    662  }
    663 
    664  if (!HasValidTransientUserGestureActivation()) {
    665    return false;
    666  }
    667 
    668  // 2. Let top be W's navigable's top-level traversable.
    669  BrowsingContext* top = mBrowsingContext->Top();
    670 
    671  // 3. Let navigables be the inclusive descendant navigables of top's active
    672  // document.
    673  auto callback = [&](BrowsingContext* aBrowsingContext) {
    674    // 4. Let windows be the list of Window objects constructed by taking the
    675    // active window of each item in navigables.
    676    WindowContext* windowContext = aBrowsingContext->GetCurrentWindowContext();
    677 
    678    // 5. For each window in windows, if window's last activation timestamp is
    679    // not positive infinity, then set window's last activation timestamp to
    680    // negative infinity.
    681    if (windowContext && windowContext->GetUserActivationState() ==
    682                             UserActivation::State::FullActivated) {
    683      auto stateAndModifiers = UserActivation::StateAndModifiers(
    684          GetUserActivationStateAndModifiers());
    685      // Setting UserActivationStateAndModifiers will trigger
    686      // DidSet(FieldIndex<IDX_UserActivationStateAndModifiers>),
    687      // which in turn updates mLastActivationTimestamp.
    688      stateAndModifiers.SetState(UserActivation::State::HasBeenActivated);
    689      (void)windowContext->SetUserActivationStateAndModifiers(
    690          stateAndModifiers.GetRawData());
    691    }
    692  };
    693  top->PreOrderWalk(callback);
    694 
    695  ConsumeUserGestureActivationBetweenPiP(top, callback);
    696 
    697  return true;
    698 }
    699 
    700 // https://html.spec.whatwg.org/multipage/interaction.html#history-action-activation
    701 bool WindowContext::HasValidHistoryActivation() const {
    702  MOZ_ASSERT(IsInProcess());
    703  return mHistoryActivation != mLastActivationTimestamp;
    704 }
    705 
    706 // https://html.spec.whatwg.org/multipage/interaction.html#consume-history-action-user-activation
    707 // Step 1-2
    708 void WindowContext::ConsumeHistoryActivation() {
    709  MOZ_ASSERT(IsInProcess());
    710 
    711  // 1. If W's navigable is null, then return.
    712 
    713  // 2. Let top be W's navigable's top-level traversable.
    714  RefPtr<BrowsingContext> top = mBrowsingContext->Top();
    715 
    716  // Consuming a history activation must happen across all child processes,
    717  // including for example cross-origin iframes. As such we need to send an
    718  // message over the IPC boundary to ensure out of processes contexts also
    719  // consume their activations.
    720  MOZ_ASSERT(XRE_IsContentProcess());
    721  ContentChild::GetSingleton()->SendConsumeHistoryActivation(top);
    722 
    723  // Update the local process children immediately.
    724  top->ConsumeHistoryActivation();
    725 }
    726 
    727 void WindowContext::UpdateLastHistoryActivation() {
    728  mHistoryActivation = mLastActivationTimestamp;
    729 }
    730 
    731 bool WindowContext::GetTransientUserGestureActivationModifiers(
    732    UserActivation::Modifiers* aModifiers) {
    733  if (!HasValidTransientUserGestureActivation()) {
    734    return false;
    735  }
    736 
    737  auto stateAndModifiers =
    738      UserActivation::StateAndModifiers(GetUserActivationStateAndModifiers());
    739  *aModifiers = stateAndModifiers.GetModifiers();
    740  return true;
    741 }
    742 
    743 bool WindowContext::CanShowPopup() {
    744  uint32_t permit = GetPopupPermission();
    745  if (permit == nsIPermissionManager::ALLOW_ACTION) {
    746    return true;
    747  }
    748  if (permit == nsIPermissionManager::DENY_ACTION) {
    749    return false;
    750  }
    751 
    752  return !StaticPrefs::dom_disable_open_during_load();
    753 }
    754 
    755 void WindowContext::TransientSetHasActivePeerConnections() {
    756  if (!IsTop()) {
    757    return;
    758  }
    759 
    760  mFields.SetWithoutSyncing<IDX_HasActivePeerConnections>(true);
    761 }
    762 
    763 WindowContext::IPCInitializer WindowContext::GetIPCInitializer() {
    764  IPCInitializer init;
    765  init.mInnerWindowId = mInnerWindowId;
    766  init.mOuterWindowId = mOuterWindowId;
    767  init.mBrowsingContextId = mBrowsingContext->Id();
    768  init.mFields = mFields.RawValues();
    769  return init;
    770 }
    771 
    772 WindowContext::WindowContext(BrowsingContext* aBrowsingContext,
    773                             uint64_t aInnerWindowId, uint64_t aOuterWindowId,
    774                             FieldValues&& aInit)
    775    : mFields(std::move(aInit)),
    776      mInnerWindowId(aInnerWindowId),
    777      mOuterWindowId(aOuterWindowId),
    778      mBrowsingContext(aBrowsingContext) {
    779  MOZ_ASSERT(mBrowsingContext);
    780  MOZ_ASSERT(mInnerWindowId);
    781  MOZ_ASSERT(mOuterWindowId);
    782  RecomputeCanExecuteScripts(/* aApplyChanges */ false);
    783 }
    784 
    785 WindowContext::~WindowContext() {
    786  if (gWindowContexts) {
    787    gWindowContexts->Remove(InnerWindowId());
    788  }
    789 }
    790 
    791 JSObject* WindowContext::WrapObject(JSContext* cx,
    792                                    JS::Handle<JSObject*> aGivenProto) {
    793  return WindowContext_Binding::Wrap(cx, this, aGivenProto);
    794 }
    795 
    796 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowContext)
    797  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    798  NS_INTERFACE_MAP_ENTRY(nsISupports)
    799 NS_INTERFACE_MAP_END
    800 
    801 NS_IMPL_CYCLE_COLLECTING_ADDREF(WindowContext)
    802 NS_IMPL_CYCLE_COLLECTING_RELEASE(WindowContext)
    803 
    804 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WindowContext)
    805 
    806 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WindowContext)
    807  if (gWindowContexts) {
    808    gWindowContexts->Remove(tmp->InnerWindowId());
    809  }
    810 
    811  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
    812  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildren)
    813  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonSyntheticChildren)
    814  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonSyntheticLightDOMChildren);
    815  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    816 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    817 
    818 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WindowContext)
    819  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
    820  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
    821  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonSyntheticChildren)
    822  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonSyntheticLightDOMChildren)
    823 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    824 
    825 }  // namespace dom
    826 }  // namespace mozilla
    827 
    828 namespace IPC {
    829 
    830 using mozilla::dom::MaybeDiscarded;
    831 using mozilla::dom::WindowContext;
    832 
    833 void ParamTraits<MaybeDiscarded<WindowContext>>::Write(
    834    MessageWriter* aWriter, const MaybeDiscarded<WindowContext>& aParam) {
    835  uint64_t id = aParam.ContextId();
    836  WriteParam(aWriter, id);
    837 }
    838 
    839 bool ParamTraits<MaybeDiscarded<WindowContext>>::Read(
    840    MessageReader* aReader, MaybeDiscarded<WindowContext>* aResult) {
    841  uint64_t id = 0;
    842  if (!ReadParam(aReader, &id)) {
    843    return false;
    844  }
    845 
    846  if (id == 0) {
    847    *aResult = nullptr;
    848  } else if (RefPtr<WindowContext> wc = WindowContext::GetById(id)) {
    849    *aResult = std::move(wc);
    850  } else {
    851    aResult->SetDiscarded(id);
    852  }
    853  return true;
    854 }
    855 
    856 void ParamTraits<WindowContext::IPCInitializer>::Write(
    857    MessageWriter* aWriter, const WindowContext::IPCInitializer& aInit) {
    858  // Write actor ID parameters.
    859  WriteParam(aWriter, aInit.mInnerWindowId);
    860  WriteParam(aWriter, aInit.mOuterWindowId);
    861  WriteParam(aWriter, aInit.mBrowsingContextId);
    862  WriteParam(aWriter, aInit.mFields);
    863 }
    864 
    865 bool ParamTraits<WindowContext::IPCInitializer>::Read(
    866    MessageReader* aReader, WindowContext::IPCInitializer* aInit) {
    867  // Read actor ID parameters.
    868  return ReadParam(aReader, &aInit->mInnerWindowId) &&
    869         ReadParam(aReader, &aInit->mOuterWindowId) &&
    870         ReadParam(aReader, &aInit->mBrowsingContextId) &&
    871         ReadParam(aReader, &aInit->mFields);
    872 }
    873 
    874 template struct ParamTraits<WindowContext::BaseTransaction>;
    875 
    876 }  // namespace IPC