content/base/src/nsTextNode.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsTextNode.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,299 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 + * Implementation of DOM Core's nsIDOMText node.
    1.11 + */
    1.12 +
    1.13 +#include "nsTextNode.h"
    1.14 +#include "mozilla/dom/TextBinding.h"
    1.15 +#include "nsContentUtils.h"
    1.16 +#include "mozilla/dom/DirectionalityUtils.h"
    1.17 +#include "nsIDOMEventListener.h"
    1.18 +#include "nsIDOMMutationEvent.h"
    1.19 +#include "nsIDocument.h"
    1.20 +#include "nsThreadUtils.h"
    1.21 +#include "nsStubMutationObserver.h"
    1.22 +#include "mozilla/IntegerPrintfMacros.h"
    1.23 +#ifdef DEBUG
    1.24 +#include "nsRange.h"
    1.25 +#endif
    1.26 +
    1.27 +using namespace mozilla;
    1.28 +using namespace mozilla::dom;
    1.29 +
    1.30 +/**
    1.31 + * class used to implement attr() generated content
    1.32 + */
    1.33 +class nsAttributeTextNode MOZ_FINAL : public nsTextNode,
    1.34 +                                      public nsStubMutationObserver
    1.35 +{
    1.36 +public:
    1.37 +  NS_DECL_ISUPPORTS_INHERITED
    1.38 +  
    1.39 +  nsAttributeTextNode(already_AddRefed<nsINodeInfo>& aNodeInfo,
    1.40 +                      int32_t aNameSpaceID,
    1.41 +                      nsIAtom* aAttrName) :
    1.42 +    nsTextNode(aNodeInfo),
    1.43 +    mGrandparent(nullptr),
    1.44 +    mNameSpaceID(aNameSpaceID),
    1.45 +    mAttrName(aAttrName)
    1.46 +  {
    1.47 +    NS_ASSERTION(mNameSpaceID != kNameSpaceID_Unknown, "Must know namespace");
    1.48 +    NS_ASSERTION(mAttrName, "Must have attr name");
    1.49 +  }
    1.50 +
    1.51 +  virtual ~nsAttributeTextNode() {
    1.52 +    NS_ASSERTION(!mGrandparent, "We were not unbound!");
    1.53 +  }
    1.54 +
    1.55 +  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
    1.56 +                              nsIContent* aBindingParent,
    1.57 +                              bool aCompileEventHandlers);
    1.58 +  virtual void UnbindFromTree(bool aDeep = true,
    1.59 +                              bool aNullParent = true);
    1.60 +
    1.61 +  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
    1.62 +  NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
    1.63 +
    1.64 +  virtual nsGenericDOMDataNode *CloneDataNode(nsINodeInfo *aNodeInfo,
    1.65 +                                              bool aCloneText) const
    1.66 +  {
    1.67 +    already_AddRefed<nsINodeInfo> ni =
    1.68 +      nsCOMPtr<nsINodeInfo>(aNodeInfo).forget();
    1.69 +    nsAttributeTextNode *it = new nsAttributeTextNode(ni,
    1.70 +                                                      mNameSpaceID,
    1.71 +                                                      mAttrName);
    1.72 +    if (it && aCloneText) {
    1.73 +      it->mText = mText;
    1.74 +    }
    1.75 +
    1.76 +    return it;
    1.77 +  }
    1.78 +
    1.79 +  // Public method for the event to run
    1.80 +  void UpdateText() {
    1.81 +    UpdateText(true);
    1.82 +  }
    1.83 +
    1.84 +private:
    1.85 +  // Update our text to our parent's current attr value
    1.86 +  void UpdateText(bool aNotify);
    1.87 +
    1.88 +  // This doesn't need to be a strong pointer because it's only non-null
    1.89 +  // while we're bound to the document tree, and it points to an ancestor
    1.90 +  // so the ancestor must be bound to the document tree the whole time
    1.91 +  // and can't be deleted.
    1.92 +  nsIContent* mGrandparent;
    1.93 +  // What attribute we're showing
    1.94 +  int32_t mNameSpaceID;
    1.95 +  nsCOMPtr<nsIAtom> mAttrName;
    1.96 +};
    1.97 +
    1.98 +nsTextNode::~nsTextNode()
    1.99 +{
   1.100 +}
   1.101 +
   1.102 +NS_IMPL_ISUPPORTS_INHERITED(nsTextNode, nsGenericDOMDataNode, nsIDOMNode,
   1.103 +                            nsIDOMText, nsIDOMCharacterData)
   1.104 +
   1.105 +JSObject*
   1.106 +nsTextNode::WrapNode(JSContext *aCx)
   1.107 +{
   1.108 +  return TextBinding::Wrap(aCx, this);
   1.109 +}
   1.110 +
   1.111 +bool
   1.112 +nsTextNode::IsNodeOfType(uint32_t aFlags) const
   1.113 +{
   1.114 +  return !(aFlags & ~(eCONTENT | eTEXT | eDATA_NODE));
   1.115 +}
   1.116 +
   1.117 +nsGenericDOMDataNode*
   1.118 +nsTextNode::CloneDataNode(nsINodeInfo *aNodeInfo, bool aCloneText) const
   1.119 +{
   1.120 +  already_AddRefed<nsINodeInfo> ni = nsCOMPtr<nsINodeInfo>(aNodeInfo).forget();
   1.121 +  nsTextNode *it = new nsTextNode(ni);
   1.122 +  if (aCloneText) {
   1.123 +    it->mText = mText;
   1.124 +  }
   1.125 +
   1.126 +  return it;
   1.127 +}
   1.128 +
   1.129 +nsresult
   1.130 +nsTextNode::AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength,
   1.131 +                                   bool aNotify, nsIContent* aNextSibling)
   1.132 +{
   1.133 +  CharacterDataChangeInfo::Details details = {
   1.134 +    CharacterDataChangeInfo::Details::eMerge, aNextSibling
   1.135 +  };
   1.136 +  return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify, &details);
   1.137 +}
   1.138 +
   1.139 +nsresult
   1.140 +nsTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
   1.141 +                       nsIContent* aBindingParent, bool aCompileEventHandlers)
   1.142 +{
   1.143 +  nsresult rv = nsGenericDOMDataNode::BindToTree(aDocument, aParent,
   1.144 +                                                 aBindingParent,
   1.145 +                                                 aCompileEventHandlers);
   1.146 +  NS_ENSURE_SUCCESS(rv, rv);
   1.147 +
   1.148 +  SetDirectionFromNewTextNode(this);
   1.149 +
   1.150 +  return NS_OK;
   1.151 +}
   1.152 +
   1.153 +void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
   1.154 +{
   1.155 +  ResetDirectionSetByTextNode(this, aNullParent);
   1.156 +
   1.157 +  nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent);
   1.158 +}
   1.159 +
   1.160 +#ifdef DEBUG
   1.161 +void
   1.162 +nsTextNode::List(FILE* out, int32_t aIndent) const
   1.163 +{
   1.164 +  int32_t index;
   1.165 +  for (index = aIndent; --index >= 0; ) fputs("  ", out);
   1.166 +
   1.167 +  fprintf(out, "Text@%p", static_cast<const void*>(this));
   1.168 +  fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
   1.169 +  if (IsCommonAncestorForRangeInSelection()) {
   1.170 +    typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
   1.171 +    RangeHashTable* ranges =
   1.172 +      static_cast<RangeHashTable*>(GetProperty(nsGkAtoms::range));
   1.173 +    fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
   1.174 +  }
   1.175 +  fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   1.176 +  fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
   1.177 +
   1.178 +  nsAutoString tmp;
   1.179 +  ToCString(tmp, 0, mText.GetLength());
   1.180 +  fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
   1.181 +
   1.182 +  fputs(">\n", out);
   1.183 +}
   1.184 +
   1.185 +void
   1.186 +nsTextNode::DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const
   1.187 +{
   1.188 +  if(aDumpAll) {
   1.189 +    int32_t index;
   1.190 +    for (index = aIndent; --index >= 0; ) fputs("  ", out);
   1.191 +
   1.192 +    nsAutoString tmp;
   1.193 +    ToCString(tmp, 0, mText.GetLength());
   1.194 +
   1.195 +    if(!tmp.EqualsLiteral("\\n")) {
   1.196 +      fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
   1.197 +      if(aIndent) fputs("\n", out);
   1.198 +    }
   1.199 +  }
   1.200 +}
   1.201 +#endif
   1.202 +
   1.203 +nsresult
   1.204 +NS_NewAttributeContent(nsNodeInfoManager *aNodeInfoManager,
   1.205 +                       int32_t aNameSpaceID, nsIAtom* aAttrName,
   1.206 +                       nsIContent** aResult)
   1.207 +{
   1.208 +  NS_PRECONDITION(aNodeInfoManager, "Missing nodeInfoManager");
   1.209 +  NS_PRECONDITION(aAttrName, "Must have an attr name");
   1.210 +  NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "Must know namespace");
   1.211 +  
   1.212 +  *aResult = nullptr;
   1.213 +
   1.214 +  already_AddRefed<nsINodeInfo> ni = aNodeInfoManager->GetTextNodeInfo();
   1.215 +
   1.216 +  nsAttributeTextNode* textNode = new nsAttributeTextNode(ni,
   1.217 +                                                          aNameSpaceID,
   1.218 +                                                          aAttrName);
   1.219 +  if (!textNode) {
   1.220 +    return NS_ERROR_OUT_OF_MEMORY;
   1.221 +  }
   1.222 +
   1.223 +  NS_ADDREF(*aResult = textNode);
   1.224 +
   1.225 +  return NS_OK;
   1.226 +}
   1.227 +
   1.228 +NS_IMPL_ISUPPORTS_INHERITED(nsAttributeTextNode, nsTextNode,
   1.229 +                            nsIMutationObserver)
   1.230 +
   1.231 +nsresult
   1.232 +nsAttributeTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
   1.233 +                                nsIContent* aBindingParent,
   1.234 +                                bool aCompileEventHandlers)
   1.235 +{
   1.236 +  NS_PRECONDITION(aParent && aParent->GetParent(),
   1.237 +                  "This node can't be a child of the document or of the document root");
   1.238 +
   1.239 +  nsresult rv = nsTextNode::BindToTree(aDocument, aParent,
   1.240 +                                       aBindingParent, aCompileEventHandlers);
   1.241 +  NS_ENSURE_SUCCESS(rv, rv);
   1.242 +
   1.243 +  NS_ASSERTION(!mGrandparent, "We were already bound!");
   1.244 +  mGrandparent = aParent->GetParent();
   1.245 +  mGrandparent->AddMutationObserver(this);
   1.246 +
   1.247 +  // Note that there is no need to notify here, since we have no
   1.248 +  // frame yet at this point.
   1.249 +  UpdateText(false);
   1.250 +
   1.251 +  return NS_OK;
   1.252 +}
   1.253 +
   1.254 +void
   1.255 +nsAttributeTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
   1.256 +{
   1.257 +  // UnbindFromTree can be called anytime so we have to be safe.
   1.258 +  if (mGrandparent) {
   1.259 +    // aNullParent might not be true here, but we want to remove the
   1.260 +    // mutation observer anyway since we only need it while we're
   1.261 +    // in the document.
   1.262 +    mGrandparent->RemoveMutationObserver(this);
   1.263 +    mGrandparent = nullptr;
   1.264 +  }
   1.265 +  nsTextNode::UnbindFromTree(aDeep, aNullParent);
   1.266 +}
   1.267 +
   1.268 +void
   1.269 +nsAttributeTextNode::AttributeChanged(nsIDocument* aDocument,
   1.270 +                                      Element* aElement,
   1.271 +                                      int32_t aNameSpaceID,
   1.272 +                                      nsIAtom* aAttribute,
   1.273 +                                      int32_t aModType)
   1.274 +{
   1.275 +  if (aNameSpaceID == mNameSpaceID && aAttribute == mAttrName &&
   1.276 +      aElement == mGrandparent) {
   1.277 +    // Since UpdateText notifies, do it when it's safe to run script.  Note
   1.278 +    // that if we get unbound while the event is up that's ok -- we'll just
   1.279 +    // have no grandparent when it fires, and will do nothing.
   1.280 +    void (nsAttributeTextNode::*update)() = &nsAttributeTextNode::UpdateText;
   1.281 +    nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this, update);
   1.282 +    nsContentUtils::AddScriptRunner(ev);
   1.283 +  }
   1.284 +}
   1.285 +
   1.286 +void
   1.287 +nsAttributeTextNode::NodeWillBeDestroyed(const nsINode* aNode)
   1.288 +{
   1.289 +  NS_ASSERTION(aNode == static_cast<nsINode*>(mGrandparent), "Wrong node!");
   1.290 +  mGrandparent = nullptr;
   1.291 +}
   1.292 +
   1.293 +void
   1.294 +nsAttributeTextNode::UpdateText(bool aNotify)
   1.295 +{
   1.296 +  if (mGrandparent) {
   1.297 +    nsAutoString attrValue;
   1.298 +    mGrandparent->GetAttr(mNameSpaceID, mAttrName, attrValue);
   1.299 +    SetText(attrValue, aNotify);
   1.300 +  }  
   1.301 +}
   1.302 +

mercurial