tor-browser

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

nsGenericHTMLFrameElement.cpp (11112B)


      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsGenericHTMLFrameElement.h"
      8 
      9 #include "mozilla/ErrorResult.h"
     10 #include "mozilla/Preferences.h"
     11 #include "mozilla/PresShell.h"
     12 #include "mozilla/ProfilerLabels.h"
     13 #include "mozilla/StaticPrefs_dom.h"
     14 #include "mozilla/dom/BrowserBridgeChild.h"
     15 #include "mozilla/dom/Document.h"
     16 #include "mozilla/dom/HTMLIFrameElement.h"
     17 #include "mozilla/dom/UnbindContext.h"
     18 #include "mozilla/dom/WindowProxyHolder.h"
     19 #include "mozilla/dom/XULFrameElement.h"
     20 #include "nsAttrValueInlines.h"
     21 #include "nsAttrValueOrString.h"
     22 #include "nsContentUtils.h"
     23 #include "nsIDocShell.h"
     24 #include "nsIFrame.h"
     25 #include "nsIInterfaceRequestorUtils.h"
     26 #include "nsIPermissionManager.h"
     27 #include "nsPresContext.h"
     28 #include "nsServiceManagerUtils.h"
     29 #include "nsSubDocumentFrame.h"
     30 
     31 using namespace mozilla;
     32 using namespace mozilla::dom;
     33 
     34 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
     35 
     36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
     37                                                  nsGenericHTMLElement)
     38  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
     39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     40 
     41 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement,
     42                                                nsGenericHTMLElement)
     43  if (tmp->mFrameLoader) {
     44    tmp->mFrameLoader->Destroy();
     45  }
     46 
     47  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader)
     48 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     49 
     50 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement,
     51                                             nsGenericHTMLElement,
     52                                             nsFrameLoaderOwner,
     53                                             nsGenericHTMLFrameElement)
     54 
     55 int32_t nsGenericHTMLFrameElement::TabIndexDefault() { return 0; }
     56 
     57 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement() {
     58  if (mFrameLoader) {
     59    mFrameLoader->Destroy();
     60  }
     61 }
     62 
     63 Document* nsGenericHTMLFrameElement::GetContentDocument(
     64    nsIPrincipal& aSubjectPrincipal) {
     65  RefPtr<BrowsingContext> bc = GetContentWindowInternal();
     66  if (!bc) {
     67    return nullptr;
     68  }
     69 
     70  nsPIDOMWindowOuter* window = bc->GetDOMWindow();
     71  if (!window) {
     72    // Either our browsing context contents are out-of-process (in which case
     73    // clearly this is a cross-origin call and we should return null), or our
     74    // browsing context is torn-down enough to no longer have a window or a
     75    // document, and we should still return null.
     76    return nullptr;
     77  }
     78  Document* doc = window->GetDoc();
     79  if (!doc) {
     80    return nullptr;
     81  }
     82 
     83  // Return null for cross-origin contentDocument.
     84  if (!aSubjectPrincipal.SubsumesConsideringDomain(doc->NodePrincipal())) {
     85    return nullptr;
     86  }
     87  return doc;
     88 }
     89 
     90 BrowsingContext* nsGenericHTMLFrameElement::GetContentWindowInternal() {
     91  EnsureFrameLoader();
     92 
     93  if (!mFrameLoader) {
     94    return nullptr;
     95  }
     96 
     97  if (mFrameLoader->DepthTooGreat()) {
     98    // Claim to have no contentWindow
     99    return nullptr;
    100  }
    101 
    102  RefPtr<BrowsingContext> bc = mFrameLoader->GetBrowsingContext();
    103  return bc;
    104 }
    105 
    106 Nullable<WindowProxyHolder> nsGenericHTMLFrameElement::GetContentWindow() {
    107  RefPtr<BrowsingContext> bc = GetContentWindowInternal();
    108  if (!bc) {
    109    return nullptr;
    110  }
    111  return WindowProxyHolder(bc);
    112 }
    113 
    114 void nsGenericHTMLFrameElement::EnsureFrameLoader() {
    115  if (!IsInComposedDoc() || mFrameLoader || OwnerDoc()->IsStaticDocument()) {
    116    // If frame loader is there, we just keep it around, cached
    117    return;
    118  }
    119 
    120  // Strangely enough, this method doesn't actually ensure that the
    121  // frameloader exists.  It's more of a best-effort kind of thing.
    122  mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
    123 }
    124 
    125 void nsGenericHTMLFrameElement::SwapFrameLoaders(
    126    HTMLIFrameElement& aOtherLoaderOwner, ErrorResult& rv) {
    127  if (&aOtherLoaderOwner == this) {
    128    // nothing to do
    129    return;
    130  }
    131 
    132  aOtherLoaderOwner.SwapFrameLoaders(this, rv);
    133 }
    134 
    135 void nsGenericHTMLFrameElement::SwapFrameLoaders(
    136    XULFrameElement& aOtherLoaderOwner, ErrorResult& rv) {
    137  aOtherLoaderOwner.SwapFrameLoaders(this, rv);
    138 }
    139 
    140 void nsGenericHTMLFrameElement::SwapFrameLoaders(
    141    nsFrameLoaderOwner* aOtherLoaderOwner, mozilla::ErrorResult& rv) {
    142  if (RefPtr<Document> doc = GetComposedDoc()) {
    143    // SwapWithOtherLoader relies on frames being up-to-date.
    144    doc->FlushPendingNotifications(FlushType::Frames);
    145  }
    146 
    147  RefPtr<nsFrameLoader> loader = GetFrameLoader();
    148  RefPtr<nsFrameLoader> otherLoader = aOtherLoaderOwner->GetFrameLoader();
    149  if (!loader || !otherLoader) {
    150    rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
    151    return;
    152  }
    153 
    154  rv = loader->SwapWithOtherLoader(otherLoader, this, aOtherLoaderOwner);
    155 }
    156 
    157 void nsGenericHTMLFrameElement::LoadSrc() {
    158  EnsureFrameLoader();
    159 
    160  if (!mFrameLoader) {
    161    return;
    162  }
    163 
    164  if (mLazyLoading) {
    165    // Waiting for lazy load, do nothing.
    166    if (!mFrameLoader->GetExtantBrowsingContext()) {
    167      // We still want to initialize the frame loader for the browsing
    168      // context to exist, so that it can be found by name and such.
    169      nsContentUtils::AddScriptRunner(
    170          NewRunnableMethod("InitializeLazyFrameLoader", mFrameLoader.get(),
    171                            &nsFrameLoader::GetBrowsingContext));
    172    }
    173    return;
    174  }
    175 
    176  bool origSrc = !mSrcLoadHappened;
    177  mSrcLoadHappened = true;
    178  mFrameLoader->LoadFrame(origSrc, /* aShouldCheckForRecursion */ true);
    179 }
    180 
    181 nsresult nsGenericHTMLFrameElement::BindToTree(BindContext& aContext,
    182                                               nsINode& aParent) {
    183  nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
    184  NS_ENSURE_SUCCESS(rv, rv);
    185 
    186  if (IsInComposedDoc() && !mFrameLoader) {
    187    NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
    188                 "Missing a script blocker!");
    189 
    190    AUTO_PROFILER_LABEL("nsGenericHTMLFrameElement::BindToTree", OTHER);
    191 
    192    // We're in a document now.  Kick off the frame load.
    193    LoadSrc();
    194  }
    195 
    196  // We're now in document and scripts may move us, so clear
    197  // the mNetworkCreated flag.
    198  mNetworkCreated = false;
    199  return rv;
    200 }
    201 
    202 void nsGenericHTMLFrameElement::UnbindFromTree(UnbindContext& aContext) {
    203  if (mFrameLoader && !aContext.IsMove()) {
    204    // This iframe is being taken out of the document, destroy the
    205    // iframe's frame loader (doing that will tear down the window in
    206    // this iframe).
    207    // XXXbz we really want to only partially destroy the frame
    208    // loader... we don't want to tear down the docshell.  Food for
    209    // later bug.
    210    mFrameLoader->Destroy();
    211    mFrameLoader = nullptr;
    212  }
    213 
    214  nsGenericHTMLElement::UnbindFromTree(aContext);
    215 }
    216 
    217 /* static */
    218 ScrollbarPreference nsGenericHTMLFrameElement::MapScrollingAttribute(
    219    const nsAttrValue* aValue) {
    220  if (aValue && aValue->Type() == nsAttrValue::eEnum) {
    221    auto scrolling = static_cast<ScrollingAttribute>(aValue->GetEnumValue());
    222    if (scrolling == ScrollingAttribute::Off ||
    223        scrolling == ScrollingAttribute::Noscroll ||
    224        scrolling == ScrollingAttribute::No) {
    225      return ScrollbarPreference::Never;
    226    }
    227  }
    228  return ScrollbarPreference::Auto;
    229 }
    230 
    231 /* virtual */
    232 void nsGenericHTMLFrameElement::AfterSetAttr(
    233    int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aValue,
    234    const nsAttrValue* aOldValue, nsIPrincipal* aMaybeScriptedPrincipal,
    235    bool aNotify) {
    236  if (aValue) {
    237    nsAttrValueOrString value(aValue);
    238    AfterMaybeChangeAttr(aNameSpaceID, aName, &value, aMaybeScriptedPrincipal,
    239                         aNotify);
    240  } else {
    241    AfterMaybeChangeAttr(aNameSpaceID, aName, nullptr, aMaybeScriptedPrincipal,
    242                         aNotify);
    243  }
    244 
    245  if (aNameSpaceID == kNameSpaceID_None) {
    246    if (aName == nsGkAtoms::scrolling) {
    247      if (mFrameLoader) {
    248        ScrollbarPreference pref = MapScrollingAttribute(aValue);
    249        if (nsDocShell* docshell = mFrameLoader->GetExistingDocShell()) {
    250          docshell->SetScrollbarPreference(pref);
    251        } else if (auto* child = mFrameLoader->GetBrowserBridgeChild()) {
    252          // NOTE(emilio): We intentionally don't deal with the
    253          // GetBrowserParent() case, and only deal with the fission iframe
    254          // case. We could make it work, but it's a bit of boilerplate for
    255          // something that we don't use, and we'd need to think how it
    256          // interacts with the scrollbar window flags...
    257          child->SendScrollbarPreferenceChanged(pref);
    258        }
    259      }
    260    }
    261  }
    262 
    263  return nsGenericHTMLElement::AfterSetAttr(
    264      aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
    265 }
    266 
    267 void nsGenericHTMLFrameElement::OnAttrSetButNotChanged(
    268    int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString& aValue,
    269    bool aNotify) {
    270  AfterMaybeChangeAttr(aNamespaceID, aName, &aValue, nullptr, aNotify);
    271 
    272  return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
    273                                                      aValue, aNotify);
    274 }
    275 
    276 void nsGenericHTMLFrameElement::AfterMaybeChangeAttr(
    277    int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString* aValue,
    278    nsIPrincipal* aMaybeScriptedPrincipal, bool aNotify) {
    279  if (aNamespaceID == kNameSpaceID_None) {
    280    if (aName == nsGkAtoms::src) {
    281      mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
    282          this, aValue ? aValue->String() : u""_ns, aMaybeScriptedPrincipal);
    283      if (!IsHTMLElement(nsGkAtoms::iframe) || !HasAttr(nsGkAtoms::srcdoc)) {
    284        // Don't propagate error here. The attribute was successfully
    285        // set or removed; that's what we should reflect.
    286        LoadSrc();
    287      }
    288    } else if (aName == nsGkAtoms::name) {
    289      // Propagate "name" to the browsing context per HTML5.
    290      RefPtr<BrowsingContext> bc =
    291          mFrameLoader ? mFrameLoader->GetExtantBrowsingContext() : nullptr;
    292      if (bc) {
    293        MOZ_ALWAYS_SUCCEEDS(bc->SetName(aValue ? aValue->String() : u""_ns));
    294      }
    295    }
    296  }
    297 }
    298 
    299 void nsGenericHTMLFrameElement::DestroyContent() {
    300  if (mFrameLoader) {
    301    mFrameLoader->Destroy();
    302    mFrameLoader = nullptr;
    303  }
    304 
    305  nsGenericHTMLElement::DestroyContent();
    306 }
    307 
    308 nsresult nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest) {
    309  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
    310  NS_ENSURE_SUCCESS(rv, rv);
    311 
    312  Document* doc = aDest->OwnerDoc();
    313  if (doc->IsStaticDocument() && mFrameLoader) {
    314    nsGenericHTMLFrameElement* dest =
    315        static_cast<nsGenericHTMLFrameElement*>(aDest);
    316    doc->AddPendingFrameStaticClone(dest, mFrameLoader);
    317  }
    318 
    319  return rv;
    320 }
    321 
    322 bool nsGenericHTMLFrameElement::IsHTMLFocusable(IsFocusableFlags aFlags,
    323                                                bool* aIsFocusable,
    324                                                int32_t* aTabIndex) {
    325  if (nsGenericHTMLElement::IsHTMLFocusable(aFlags, aIsFocusable, aTabIndex)) {
    326    return true;
    327  }
    328 
    329  *aIsFocusable = true;
    330  return false;
    331 }