tor-browser

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

nsTextNode.cpp (8285B)


      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 /*
      8 * Implementation of DOM Core's Text node.
      9 */
     10 
     11 #include "nsTextNode.h"
     12 
     13 #include "mozilla/IntegerPrintfMacros.h"
     14 #include "mozilla/dom/Document.h"
     15 #include "mozilla/dom/TextBinding.h"
     16 #include "nsContentUtils.h"
     17 #include "nsStubMutationObserver.h"
     18 #include "nsThreadUtils.h"
     19 #ifdef MOZ_DOM_LIST
     20 #  include "nsRange.h"
     21 #endif
     22 
     23 using namespace mozilla;
     24 using namespace mozilla::dom;
     25 
     26 /**
     27 * class used to implement attr() generated content
     28 */
     29 class nsAttributeTextNode final : public nsTextNode,
     30                                  public nsStubMutationObserver {
     31 public:
     32  NS_DECL_ISUPPORTS_INHERITED
     33 
     34  nsAttributeTextNode(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
     35                      int32_t aNameSpaceID, nsAtom* aAttrName,
     36                      nsAtom* aFallback)
     37      : nsTextNode(std::move(aNodeInfo)),
     38        mGrandparent(nullptr),
     39        mNameSpaceID(aNameSpaceID),
     40        mAttrName(aAttrName),
     41        mFallback(aFallback) {
     42    NS_ASSERTION(mNameSpaceID != kNameSpaceID_Unknown, "Must know namespace");
     43    NS_ASSERTION(mAttrName, "Must have attr name");
     44  }
     45 
     46  nsresult BindToTree(BindContext&, nsINode& aParent) override;
     47  void UnbindFromTree(UnbindContext&) override;
     48 
     49  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
     50  NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
     51 
     52  already_AddRefed<CharacterData> CloneDataNode(
     53      mozilla::dom::NodeInfo* aNodeInfo, bool aCloneText) const override {
     54    RefPtr<nsAttributeTextNode> it =
     55        new (aNodeInfo->NodeInfoManager()) nsAttributeTextNode(
     56            do_AddRef(aNodeInfo), mNameSpaceID, mAttrName, mFallback);
     57    if (aCloneText) {
     58      it->mBuffer = mBuffer;
     59    }
     60 
     61    return it.forget();
     62  }
     63 
     64  // Public method for the event to run
     65  void UpdateText() { UpdateText(true); }
     66 
     67 private:
     68  virtual ~nsAttributeTextNode() {
     69    NS_ASSERTION(!mGrandparent, "We were not unbound!");
     70  }
     71 
     72  // Update our text to our parent's current attr value
     73  void UpdateText(bool aNotify);
     74 
     75  // This doesn't need to be a strong pointer because it's only non-null
     76  // while we're bound to the document tree, and it points to an ancestor
     77  // so the ancestor must be bound to the document tree the whole time
     78  // and can't be deleted.
     79  Element* mGrandparent;
     80  // What attribute we're showing
     81  int32_t mNameSpaceID;
     82  RefPtr<nsAtom> mAttrName;
     83  RefPtr<nsAtom> mFallback;
     84 };
     85 
     86 nsTextNode::~nsTextNode() = default;
     87 
     88 // Use the CC variant of this, even though this class does not define
     89 // a new CC participant, to make QIing to the CC interfaces faster.
     90 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(nsTextNode, CharacterData)
     91 
     92 JSObject* nsTextNode::WrapNode(JSContext* aCx,
     93                               JS::Handle<JSObject*> aGivenProto) {
     94  return Text_Binding::Wrap(aCx, this, aGivenProto);
     95 }
     96 
     97 already_AddRefed<CharacterData> nsTextNode::CloneDataNode(
     98    mozilla::dom::NodeInfo* aNodeInfo, bool aCloneText) const {
     99  RefPtr<nsTextNode> it =
    100      new (aNodeInfo->NodeInfoManager()) nsTextNode(do_AddRef(aNodeInfo));
    101  if (aCloneText) {
    102    it->mBuffer = mBuffer;
    103  }
    104 
    105  return it.forget();
    106 }
    107 
    108 nsresult nsTextNode::AppendTextForNormalize(const char16_t* aBuffer,
    109                                            uint32_t aLength, bool aNotify,
    110                                            nsIContent* aNextSibling) {
    111  CharacterDataChangeInfo::Details details = {
    112      CharacterDataChangeInfo::Details::eMerge, aNextSibling};
    113  return SetTextInternal(mBuffer.GetLength(), 0, aBuffer, aLength, aNotify,
    114                         MutationEffectOnScript::KeepTrustWorthiness, &details);
    115 }
    116 
    117 #ifdef MOZ_DOM_LIST
    118 void nsTextNode::List(FILE* out, int32_t aIndent) const {
    119  int32_t index;
    120  for (index = aIndent; --index >= 0;) fputs("  ", out);
    121 
    122  fprintf(out, "Text@%p", static_cast<const void*>(this));
    123  fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
    124  if (IsClosestCommonInclusiveAncestorForRangeInSelection()) {
    125    const LinkedList<AbstractRange>* ranges =
    126        GetExistingClosestCommonInclusiveAncestorRanges();
    127    uint32_t count = ranges ? ranges->length() : 0;
    128    fprintf(out, " ranges:%d", count);
    129  }
    130  fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
    131  fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
    132 
    133  nsAutoString tmp;
    134  ToCString(tmp, 0, mBuffer.GetLength());
    135  fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
    136 
    137  fputs(">\n", out);
    138 }
    139 
    140 void nsTextNode::DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const {
    141  if (aDumpAll) {
    142    int32_t index;
    143    for (index = aIndent; --index >= 0;) fputs("  ", out);
    144 
    145    nsAutoString tmp;
    146    ToCString(tmp, 0, mBuffer.GetLength());
    147 
    148    if (!tmp.EqualsLiteral("\\n")) {
    149      fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
    150      if (aIndent) fputs("\n", out);
    151    }
    152  }
    153 }
    154 #endif
    155 
    156 nsresult NS_NewAttributeContent(nsNodeInfoManager* aNodeInfoManager,
    157                                int32_t aNameSpaceID, nsAtom* aAttrName,
    158                                nsAtom* aFallback, nsIContent** aResult) {
    159  MOZ_ASSERT(aNodeInfoManager, "Missing nodeInfoManager");
    160  MOZ_ASSERT(aAttrName, "Must have an attr name");
    161  MOZ_ASSERT(aNameSpaceID != kNameSpaceID_Unknown, "Must know namespace");
    162 
    163  *aResult = nullptr;
    164 
    165  RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfoManager->GetTextNodeInfo();
    166 
    167  RefPtr<nsAttributeTextNode> textNode = new (aNodeInfoManager)
    168      nsAttributeTextNode(ni.forget(), aNameSpaceID, aAttrName, aFallback);
    169  textNode.forget(aResult);
    170 
    171  return NS_OK;
    172 }
    173 
    174 NS_IMPL_ISUPPORTS_INHERITED(nsAttributeTextNode, nsTextNode,
    175                            nsIMutationObserver)
    176 
    177 nsresult nsAttributeTextNode::BindToTree(BindContext& aContext,
    178                                         nsINode& aParent) {
    179  MOZ_ASSERT(aParent.IsContent() && aParent.GetParent(),
    180             "This node can't be a child of the document or of "
    181             "the document root");
    182 
    183  nsresult rv = nsTextNode::BindToTree(aContext, aParent);
    184  NS_ENSURE_SUCCESS(rv, rv);
    185 
    186  NS_ASSERTION(!mGrandparent, "We were already bound!");
    187  mGrandparent = aParent.GetParent()->AsElement();
    188  mGrandparent->AddMutationObserver(this);
    189 
    190  // Note that there is no need to notify here, since we have no
    191  // frame yet at this point.
    192  UpdateText(false);
    193 
    194  return NS_OK;
    195 }
    196 
    197 void nsAttributeTextNode::UnbindFromTree(UnbindContext& aContext) {
    198  // UnbindFromTree can be called anytime so we have to be safe.
    199  if (mGrandparent) {
    200    // aContext might not be true here, but we want to remove the
    201    // mutation observer anyway since we only need it while we're
    202    // in the document.
    203    mGrandparent->RemoveMutationObserver(this);
    204    mGrandparent = nullptr;
    205  }
    206  nsTextNode::UnbindFromTree(aContext);
    207 }
    208 
    209 void nsAttributeTextNode::AttributeChanged(Element* aElement,
    210                                           int32_t aNameSpaceID,
    211                                           nsAtom* aAttribute, AttrModType,
    212                                           const nsAttrValue* aOldValue) {
    213  if (aNameSpaceID == mNameSpaceID && aAttribute == mAttrName &&
    214      aElement == mGrandparent) {
    215    // Since UpdateText notifies, do it when it's safe to run script.  Note
    216    // that if we get unbound while the event is up that's ok -- we'll just
    217    // have no grandparent when it fires, and will do nothing.
    218    void (nsAttributeTextNode::*update)() = &nsAttributeTextNode::UpdateText;
    219    nsContentUtils::AddScriptRunner(NewRunnableMethod(
    220        "nsAttributeTextNode::AttributeChanged", this, update));
    221  }
    222 }
    223 
    224 void nsAttributeTextNode::NodeWillBeDestroyed(nsINode* aNode) {
    225  NS_ASSERTION(aNode == static_cast<nsINode*>(mGrandparent), "Wrong node!");
    226  mGrandparent = nullptr;
    227 }
    228 
    229 void nsAttributeTextNode::UpdateText(bool aNotify) {
    230  if (mGrandparent) {
    231    nsAutoString attrValue;
    232 
    233    if (!mGrandparent->GetAttr(mNameSpaceID, mAttrName, attrValue)) {
    234      // Attr value does not exist, use fallback instead
    235      mFallback->ToString(attrValue);
    236    }
    237 
    238    SetText(attrValue, aNotify);
    239  }
    240 }