Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsTextNode.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "mozilla/dom/TextBinding.h"
13
#include "nsContentUtils.h"
14
#include "mozilla/dom/DirectionalityUtils.h"
15
#include "nsIDOMEventListener.h"
16
#include "nsIDocument.h"
17
#include "nsThreadUtils.h"
18
#include "nsStubMutationObserver.h"
19
#include "mozilla/IntegerPrintfMacros.h"
20
#ifdef DEBUG
21
#include "nsRange.h"
22
#endif
23
#include "nsDocument.h"
24
25
using namespace mozilla;
26
using namespace mozilla::dom;
27
28
/**
29
 * class used to implement attr() generated content
30
 */
31
class nsAttributeTextNode final : public nsTextNode,
32
                                  public nsStubMutationObserver
33
{
34
public:
35
  NS_DECL_ISUPPORTS_INHERITED
36
37
  nsAttributeTextNode(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
38
                      int32_t aNameSpaceID,
39
                      nsAtom* aAttrName) :
40
    nsTextNode(std::move(aNodeInfo)),
41
    mGrandparent(nullptr),
42
    mNameSpaceID(aNameSpaceID),
43
    mAttrName(aAttrName)
44
0
  {
45
0
    NS_ASSERTION(mNameSpaceID != kNameSpaceID_Unknown, "Must know namespace");
46
0
    NS_ASSERTION(mAttrName, "Must have attr name");
47
0
  }
48
49
  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
50
                              nsIContent* aBindingParent) override;
51
  virtual void UnbindFromTree(bool aDeep = true,
52
                              bool aNullParent = true) override;
53
54
  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
55
  NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
56
57
  virtual already_AddRefed<CharacterData>
58
    CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
59
                  bool aCloneText) const override
60
0
  {
61
0
    RefPtr<nsAttributeTextNode> it =
62
0
      new nsAttributeTextNode(do_AddRef(aNodeInfo), mNameSpaceID, mAttrName);
63
0
    if (aCloneText) {
64
0
      it->mText = mText;
65
0
    }
66
0
67
0
    return it.forget();
68
0
  }
69
70
  // Public method for the event to run
71
0
  void UpdateText() {
72
0
    UpdateText(true);
73
0
  }
74
75
private:
76
0
  virtual ~nsAttributeTextNode() {
77
0
    NS_ASSERTION(!mGrandparent, "We were not unbound!");
78
0
  }
79
80
  // Update our text to our parent's current attr value
81
  void UpdateText(bool aNotify);
82
83
  // This doesn't need to be a strong pointer because it's only non-null
84
  // while we're bound to the document tree, and it points to an ancestor
85
  // so the ancestor must be bound to the document tree the whole time
86
  // and can't be deleted.
87
  Element* mGrandparent;
88
  // What attribute we're showing
89
  int32_t mNameSpaceID;
90
  RefPtr<nsAtom> mAttrName;
91
};
92
93
nsTextNode::~nsTextNode()
94
0
{
95
0
}
96
97
// Use the CC variant of this, even though this class does not define
98
// a new CC participant, to make QIing to the CC interfaces faster.
99
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(nsTextNode, CharacterData)
100
101
JSObject*
102
nsTextNode::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
103
0
{
104
0
  return Text_Binding::Wrap(aCx, this, aGivenProto);
105
0
}
106
107
bool
108
nsTextNode::IsNodeOfType(uint32_t aFlags) const
109
0
{
110
0
  return false;
111
0
}
112
113
already_AddRefed<CharacterData>
114
nsTextNode::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo, bool aCloneText) const
115
0
{
116
0
  RefPtr<nsTextNode> it = new nsTextNode(do_AddRef(aNodeInfo));
117
0
  if (aCloneText) {
118
0
    it->mText = mText;
119
0
  }
120
0
121
0
  return it.forget();
122
0
}
123
124
nsresult
125
nsTextNode::AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength,
126
                                   bool aNotify, nsIContent* aNextSibling)
127
0
{
128
0
  CharacterDataChangeInfo::Details details = {
129
0
    CharacterDataChangeInfo::Details::eMerge, aNextSibling
130
0
  };
131
0
  return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify, &details);
132
0
}
133
134
nsresult
135
nsTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
136
                       nsIContent* aBindingParent)
137
0
{
138
0
  nsresult rv = CharacterData::BindToTree(aDocument, aParent,
139
0
                                          aBindingParent);
140
0
  NS_ENSURE_SUCCESS(rv, rv);
141
0
142
0
  SetDirectionFromNewTextNode(this);
143
0
144
0
  return NS_OK;
145
0
}
146
147
void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
148
0
{
149
0
  ResetDirectionSetByTextNode(this);
150
0
151
0
  CharacterData::UnbindFromTree(aDeep, aNullParent);
152
0
}
153
154
bool
155
nsTextNode::IsShadowDOMEnabled(JSContext* aCx, JSObject* aObject)
156
0
{
157
0
  return nsDocument::IsShadowDOMEnabled(aCx, aObject);
158
0
}
159
160
#ifdef DEBUG
161
void
162
nsTextNode::List(FILE* out, int32_t aIndent) const
163
{
164
  int32_t index;
165
  for (index = aIndent; --index >= 0; ) fputs("  ", out);
166
167
  fprintf(out, "Text@%p", static_cast<const void*>(this));
168
  fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
169
  if (IsCommonAncestorForRangeInSelection()) {
170
    const LinkedList<nsRange>* ranges = GetExistingCommonAncestorRanges();
171
    int32_t count = 0;
172
    if (ranges) {
173
      // Can't use range-based iteration on a const LinkedList, unfortunately.
174
      for (const nsRange* r = ranges->getFirst(); r; r = r->getNext()) {
175
        ++count;
176
      }
177
    }
178
    fprintf(out, " ranges:%d", count);
179
  }
180
  fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
181
  fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
182
183
  nsAutoString tmp;
184
  ToCString(tmp, 0, mText.GetLength());
185
  fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
186
187
  fputs(">\n", out);
188
}
189
190
void
191
nsTextNode::DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const
192
{
193
  if(aDumpAll) {
194
    int32_t index;
195
    for (index = aIndent; --index >= 0; ) fputs("  ", out);
196
197
    nsAutoString tmp;
198
    ToCString(tmp, 0, mText.GetLength());
199
200
    if(!tmp.EqualsLiteral("\\n")) {
201
      fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
202
      if(aIndent) fputs("\n", out);
203
    }
204
  }
205
}
206
#endif
207
208
nsresult
209
NS_NewAttributeContent(nsNodeInfoManager *aNodeInfoManager,
210
                       int32_t aNameSpaceID, nsAtom* aAttrName,
211
                       nsIContent** aResult)
212
0
{
213
0
  MOZ_ASSERT(aNodeInfoManager, "Missing nodeInfoManager");
214
0
  MOZ_ASSERT(aAttrName, "Must have an attr name");
215
0
  MOZ_ASSERT(aNameSpaceID != kNameSpaceID_Unknown, "Must know namespace");
216
0
217
0
  *aResult = nullptr;
218
0
219
0
  RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfoManager->GetTextNodeInfo();
220
0
221
0
  RefPtr<nsAttributeTextNode> textNode = new nsAttributeTextNode(ni.forget(),
222
0
                                                                 aNameSpaceID,
223
0
                                                                 aAttrName);
224
0
  textNode.forget(aResult);
225
0
226
0
  return NS_OK;
227
0
}
228
229
NS_IMPL_ISUPPORTS_INHERITED(nsAttributeTextNode, nsTextNode,
230
                            nsIMutationObserver)
231
232
nsresult
233
nsAttributeTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
234
                                nsIContent* aBindingParent)
235
0
{
236
0
  MOZ_ASSERT(aParent && aParent->GetParent(),
237
0
             "This node can't be a child of the document or of the document root");
238
0
239
0
  nsresult rv = nsTextNode::BindToTree(aDocument, aParent,
240
0
                                       aBindingParent);
241
0
  NS_ENSURE_SUCCESS(rv, rv);
242
0
243
0
  NS_ASSERTION(!mGrandparent, "We were already bound!");
244
0
  mGrandparent = aParent->GetParent()->AsElement();
245
0
  mGrandparent->AddMutationObserver(this);
246
0
247
0
  // Note that there is no need to notify here, since we have no
248
0
  // frame yet at this point.
249
0
  UpdateText(false);
250
0
251
0
  return NS_OK;
252
0
}
253
254
void
255
nsAttributeTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
256
0
{
257
0
  // UnbindFromTree can be called anytime so we have to be safe.
258
0
  if (mGrandparent) {
259
0
    // aNullParent might not be true here, but we want to remove the
260
0
    // mutation observer anyway since we only need it while we're
261
0
    // in the document.
262
0
    mGrandparent->RemoveMutationObserver(this);
263
0
    mGrandparent = nullptr;
264
0
  }
265
0
  nsTextNode::UnbindFromTree(aDeep, aNullParent);
266
0
}
267
268
void
269
nsAttributeTextNode::AttributeChanged(Element* aElement,
270
                                      int32_t aNameSpaceID,
271
                                      nsAtom* aAttribute,
272
                                      int32_t aModType,
273
                                      const nsAttrValue* aOldValue)
274
0
{
275
0
  if (aNameSpaceID == mNameSpaceID && aAttribute == mAttrName &&
276
0
      aElement == mGrandparent) {
277
0
    // Since UpdateText notifies, do it when it's safe to run script.  Note
278
0
    // that if we get unbound while the event is up that's ok -- we'll just
279
0
    // have no grandparent when it fires, and will do nothing.
280
0
    void (nsAttributeTextNode::*update)() = &nsAttributeTextNode::UpdateText;
281
0
    nsContentUtils::AddScriptRunner(
282
0
      NewRunnableMethod("nsAttributeTextNode::AttributeChanged", this, update));
283
0
  }
284
0
}
285
286
void
287
nsAttributeTextNode::NodeWillBeDestroyed(const nsINode* aNode)
288
0
{
289
0
  NS_ASSERTION(aNode == static_cast<nsINode*>(mGrandparent), "Wrong node!");
290
0
  mGrandparent = nullptr;
291
0
}
292
293
void
294
nsAttributeTextNode::UpdateText(bool aNotify)
295
0
{
296
0
  if (mGrandparent) {
297
0
    nsAutoString attrValue;
298
0
    mGrandparent->GetAttr(mNameSpaceID, mAttrName, attrValue);
299
0
    SetText(attrValue, aNotify);
300
0
  }
301
0
}