tor-browser

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

HTMLAnchorElement.cpp (7184B)


      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/HTMLAnchorElement.h"
      8 
      9 #include "mozilla/EventDispatcher.h"
     10 #include "mozilla/FocusModel.h"
     11 #include "mozilla/dom/BindContext.h"
     12 #include "mozilla/dom/Document.h"
     13 #include "mozilla/dom/HTMLAnchorElementBinding.h"
     14 #include "mozilla/dom/HTMLDNSPrefetch.h"
     15 #include "nsCOMPtr.h"
     16 #include "nsContentUtils.h"
     17 #include "nsGkAtoms.h"
     18 #include "nsIURI.h"
     19 #include "nsPresContext.h"
     20 #include "nsWindowSizes.h"
     21 
     22 NS_IMPL_NS_NEW_HTML_ELEMENT(Anchor)
     23 
     24 namespace mozilla::dom {
     25 
     26 HTMLAnchorElement::~HTMLAnchorElement() {
     27  SupportsDNSPrefetch::Destroyed(*this);
     28 }
     29 
     30 bool HTMLAnchorElement::IsInteractiveHTMLContent() const {
     31  return HasAttr(nsGkAtoms::href) ||
     32         nsGenericHTMLElement::IsInteractiveHTMLContent();
     33 }
     34 
     35 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement,
     36                                             nsGenericHTMLElement, Link)
     37 
     38 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement, nsGenericHTMLElement,
     39                                   mRelList)
     40 
     41 NS_IMPL_ELEMENT_CLONE(HTMLAnchorElement)
     42 
     43 JSObject* HTMLAnchorElement::WrapNode(JSContext* aCx,
     44                                      JS::Handle<JSObject*> aGivenProto) {
     45  return HTMLAnchorElement_Binding::Wrap(aCx, this, aGivenProto);
     46 }
     47 
     48 int32_t HTMLAnchorElement::TabIndexDefault() { return 0; }
     49 
     50 bool HTMLAnchorElement::Draggable() const {
     51  // links can be dragged as long as there is an href and the
     52  // draggable attribute isn't false
     53  if (!HasAttr(nsGkAtoms::href)) {
     54    // no href, so just use the same behavior as other elements
     55    return nsGenericHTMLElement::Draggable();
     56  }
     57 
     58  return !AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
     59                      nsGkAtoms::_false, eIgnoreCase);
     60 }
     61 
     62 nsresult HTMLAnchorElement::BindToTree(BindContext& aContext,
     63                                       nsINode& aParent) {
     64  nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
     65  NS_ENSURE_SUCCESS(rv, rv);
     66 
     67  Link::BindToTree(aContext);
     68 
     69  // Prefetch links
     70  MaybeTryDNSPrefetch();
     71  return rv;
     72 }
     73 
     74 void HTMLAnchorElement::UnbindFromTree(UnbindContext& aContext) {
     75  // Cancel any DNS prefetches
     76  // Note: Must come before ResetLinkState.  If called after, it will recreate
     77  // mCachedURI based on data that is invalid - due to a call to Link::GetURI()
     78  // via GetURIForDNSPrefetch().
     79  CancelDNSPrefetch(*this);
     80 
     81  nsGenericHTMLElement::UnbindFromTree(aContext);
     82 
     83  // Without removing the link state we risk a dangling pointer in the
     84  // mStyledLinks hashtable
     85  Link::UnbindFromTree();
     86 }
     87 
     88 bool HTMLAnchorElement::IsHTMLFocusable(IsFocusableFlags aFlags,
     89                                        bool* aIsFocusable,
     90                                        int32_t* aTabIndex) {
     91  if (nsGenericHTMLElement::IsHTMLFocusable(aFlags, aIsFocusable, aTabIndex)) {
     92    return true;
     93  }
     94 
     95  // cannot focus links if there is no link handler
     96  if (!OwnerDoc()->LinkHandlingEnabled()) {
     97    *aTabIndex = -1;
     98    *aIsFocusable = false;
     99    return false;
    100  }
    101 
    102  // Links that are in an editable region should never be focusable, even if
    103  // they are in a contenteditable="false" region.
    104  if (nsContentUtils::IsNodeInEditableRegion(this)) {
    105    *aTabIndex = -1;
    106    *aIsFocusable = false;
    107    return true;
    108  }
    109 
    110  if (GetTabIndexAttrValue().isNothing()) {
    111    // check whether we're actually a link
    112    if (!IsLink()) {
    113      // Not tabbable or focusable without href (bug 17605), unless
    114      // forced to be via presence of nonnegative tabindex attribute
    115      *aTabIndex = -1;
    116      *aIsFocusable = false;
    117      return false;
    118    }
    119  }
    120 
    121  if (!FocusModel::IsTabFocusable(TabFocusableType::Links)) {
    122    *aTabIndex = -1;
    123  }
    124  *aIsFocusable = true;
    125  return false;
    126 }
    127 
    128 void HTMLAnchorElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
    129  GetEventTargetParentForAnchors(aVisitor);
    130 }
    131 
    132 nsresult HTMLAnchorElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
    133  return PostHandleEventForAnchors(aVisitor);
    134 }
    135 
    136 void HTMLAnchorElement::GetLinkTargetImpl(nsAString& aTarget) {
    137  GetAttr(nsGkAtoms::target, aTarget);
    138  if (aTarget.IsEmpty()) {
    139    GetBaseTarget(aTarget);
    140  }
    141 }
    142 
    143 void HTMLAnchorElement::GetTarget(nsAString& aValue) const {
    144  if (!GetAttr(nsGkAtoms::target, aValue)) {
    145    GetBaseTarget(aValue);
    146  }
    147 }
    148 
    149 nsDOMTokenList* HTMLAnchorElement::RelList() {
    150  if (!mRelList) {
    151    mRelList =
    152        new nsDOMTokenList(this, nsGkAtoms::rel, sAnchorAndFormRelValues);
    153  }
    154  return mRelList;
    155 }
    156 
    157 void HTMLAnchorElement::GetText(nsAString& aText,
    158                                mozilla::ErrorResult& aRv) const {
    159  if (NS_WARN_IF(
    160          !nsContentUtils::GetNodeTextContent(this, true, aText, fallible))) {
    161    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    162  }
    163 }
    164 
    165 void HTMLAnchorElement::SetText(const nsAString& aText, ErrorResult& aRv) {
    166  aRv = nsContentUtils::SetNodeTextContent(this, aText, false);
    167 }
    168 
    169 already_AddRefed<nsIURI> HTMLAnchorElement::GetHrefURI() const {
    170  if (nsCOMPtr<nsIURI> uri = GetCachedURI()) {
    171    return uri.forget();
    172  }
    173  return GetHrefURIForAnchors();
    174 }
    175 
    176 void HTMLAnchorElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
    177                                      const nsAttrValue* aValue, bool aNotify) {
    178  if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::href) {
    179    CancelDNSPrefetch(*this);
    180  }
    181  return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName, aValue,
    182                                             aNotify);
    183 }
    184 
    185 void HTMLAnchorElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
    186                                     const nsAttrValue* aValue,
    187                                     const nsAttrValue* aOldValue,
    188                                     nsIPrincipal* aSubjectPrincipal,
    189                                     bool aNotify) {
    190  if (aNamespaceID == kNameSpaceID_None) {
    191    if (aName == nsGkAtoms::href) {
    192      Link::ResetLinkState(aNotify, !!aValue);
    193      if (aValue) {
    194        MaybeTryDNSPrefetch();
    195      }
    196    }
    197  }
    198 
    199  return nsGenericHTMLElement::AfterSetAttr(
    200      aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
    201 }
    202 
    203 void HTMLAnchorElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
    204                                               size_t* aNodeSize) const {
    205  nsGenericHTMLElement::AddSizeOfExcludingThis(aSizes, aNodeSize);
    206  *aNodeSize += Link::SizeOfExcludingThis(aSizes.mState);
    207 }
    208 
    209 void HTMLAnchorElement::MaybeTryDNSPrefetch() {
    210  if (IsInComposedDoc()) {
    211    nsIURI* docURI = OwnerDoc()->GetDocumentURI();
    212    if (!docURI) {
    213      return;
    214    }
    215 
    216    bool docIsHttps = docURI->SchemeIs("https");
    217    if ((docIsHttps &&
    218         StaticPrefs::dom_prefetch_dns_for_anchor_https_document()) ||
    219        (!docIsHttps &&
    220         StaticPrefs::dom_prefetch_dns_for_anchor_http_document())) {
    221      TryDNSPrefetch(
    222          *this, HTMLDNSPrefetch::PrefetchSource::AnchorSpeculativePrefetch);
    223    }
    224  }
    225 }
    226 
    227 }  // namespace mozilla::dom