content/base/src/nsRange.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsRange.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,335 @@
     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 the DOM nsIDOMRange object.
    1.11 + */
    1.12 +
    1.13 +#ifndef nsRange_h___
    1.14 +#define nsRange_h___
    1.15 +
    1.16 +#include "nsIDOMRange.h"
    1.17 +#include "nsCOMPtr.h"
    1.18 +#include "nsINode.h"
    1.19 +#include "nsIDocument.h"
    1.20 +#include "nsIDOMNode.h"
    1.21 +#include "prmon.h"
    1.22 +#include "nsStubMutationObserver.h"
    1.23 +#include "nsWrapperCache.h"
    1.24 +#include "mozilla/Attributes.h"
    1.25 +
    1.26 +namespace mozilla {
    1.27 +class ErrorResult;
    1.28 +namespace dom {
    1.29 +class DocumentFragment;
    1.30 +class DOMRect;
    1.31 +class DOMRectList;
    1.32 +}
    1.33 +}
    1.34 +
    1.35 +class nsRange MOZ_FINAL : public nsIDOMRange,
    1.36 +                          public nsStubMutationObserver,
    1.37 +                          public nsWrapperCache
    1.38 +{
    1.39 +  typedef mozilla::ErrorResult ErrorResult;
    1.40 +  typedef mozilla::dom::DOMRect DOMRect;
    1.41 +  typedef mozilla::dom::DOMRectList DOMRectList;
    1.42 +
    1.43 +public:
    1.44 +  nsRange(nsINode* aNode)
    1.45 +    : mRoot(nullptr)
    1.46 +    , mStartOffset(0)
    1.47 +    , mEndOffset(0)
    1.48 +    , mIsPositioned(false)
    1.49 +    , mIsDetached(false)
    1.50 +    , mMaySpanAnonymousSubtrees(false)
    1.51 +    , mInSelection(false)
    1.52 +    , mStartOffsetWasIncremented(false)
    1.53 +    , mEndOffsetWasIncremented(false)
    1.54 +    , mEnableGravitationOnElementRemoval(true)
    1.55 +#ifdef DEBUG
    1.56 +    , mAssertNextInsertOrAppendIndex(-1)
    1.57 +    , mAssertNextInsertOrAppendNode(nullptr)
    1.58 +#endif
    1.59 +  {
    1.60 +    SetIsDOMBinding();
    1.61 +    MOZ_ASSERT(aNode, "range isn't in a document!");
    1.62 +    mOwner = aNode->OwnerDoc();
    1.63 +  }
    1.64 +  virtual ~nsRange();
    1.65 +
    1.66 +  static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
    1.67 +                              nsIDOMNode* aEndParent, int32_t aEndOffset,
    1.68 +                              nsRange** aRange);
    1.69 +  static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
    1.70 +                              nsIDOMNode* aEndParent, int32_t aEndOffset,
    1.71 +                              nsIDOMRange** aRange);
    1.72 +  static nsresult CreateRange(nsINode* aStartParent, int32_t aStartOffset,
    1.73 +                              nsINode* aEndParent, int32_t aEndOffset,
    1.74 +                              nsRange** aRange);
    1.75 +
    1.76 +  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    1.77 +  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsRange, nsIDOMRange)
    1.78 +
    1.79 +  /**
    1.80 +   * The DOM Range spec requires that when a node is removed from its parent,
    1.81 +   * and the node's subtree contains the start or end point of a range, that
    1.82 +   * start or end point is moved up to where the node was removed from its
    1.83 +   * parent.
    1.84 +   * For some internal uses of Ranges it's useful to disable that behavior,
    1.85 +   * so that a range of children within a single parent is preserved even if
    1.86 +   * that parent is removed from the document tree.
    1.87 +   */
    1.88 +  void SetEnableGravitationOnElementRemoval(bool aEnable)
    1.89 +  {
    1.90 +    mEnableGravitationOnElementRemoval = aEnable;
    1.91 +  }
    1.92 +
    1.93 +  // nsIDOMRange interface
    1.94 +  NS_DECL_NSIDOMRANGE
    1.95 +
    1.96 +  nsINode* GetRoot() const
    1.97 +  {
    1.98 +    return mRoot;
    1.99 +  }
   1.100 +
   1.101 +  nsINode* GetStartParent() const
   1.102 +  {
   1.103 +    return mStartParent;
   1.104 +  }
   1.105 +
   1.106 +  nsINode* GetEndParent() const
   1.107 +  {
   1.108 +    return mEndParent;
   1.109 +  }
   1.110 +
   1.111 +  int32_t StartOffset() const
   1.112 +  {
   1.113 +    return mStartOffset;
   1.114 +  }
   1.115 +
   1.116 +  int32_t EndOffset() const
   1.117 +  {
   1.118 +    return mEndOffset;
   1.119 +  }
   1.120 +  
   1.121 +  bool IsPositioned() const
   1.122 +  {
   1.123 +    return mIsPositioned;
   1.124 +  }
   1.125 +
   1.126 +  void SetMaySpanAnonymousSubtrees(bool aMaySpanAnonymousSubtrees)
   1.127 +  {
   1.128 +    mMaySpanAnonymousSubtrees = aMaySpanAnonymousSubtrees;
   1.129 +  }
   1.130 +  
   1.131 +  /**
   1.132 +   * Return true iff this range is part of at least one Selection object
   1.133 +   * and isn't detached.
   1.134 +   */
   1.135 +  bool IsInSelection() const
   1.136 +  {
   1.137 +    return mInSelection;
   1.138 +  }
   1.139 +
   1.140 +  /**
   1.141 +   * Called when the range is added/removed from a Selection.
   1.142 +   */
   1.143 +  void SetInSelection(bool aInSelection)
   1.144 +  {
   1.145 +    if (mInSelection == aInSelection) {
   1.146 +      return;
   1.147 +    }
   1.148 +    mInSelection = aInSelection;
   1.149 +    nsINode* commonAncestor = GetCommonAncestor();
   1.150 +    NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
   1.151 +    if (mInSelection) {
   1.152 +      RegisterCommonAncestor(commonAncestor);
   1.153 +    } else {
   1.154 +      UnregisterCommonAncestor(commonAncestor);
   1.155 +    }
   1.156 +  }
   1.157 +
   1.158 +  nsINode* GetCommonAncestor() const;
   1.159 +  void Reset();
   1.160 +  nsresult SetStart(nsINode* aParent, int32_t aOffset);
   1.161 +  nsresult SetEnd(nsINode* aParent, int32_t aOffset);
   1.162 +  already_AddRefed<nsRange> CloneRange() const;
   1.163 +
   1.164 +  nsresult Set(nsINode* aStartParent, int32_t aStartOffset,
   1.165 +               nsINode* aEndParent, int32_t aEndOffset)
   1.166 +  {
   1.167 +    // If this starts being hot, we may be able to optimize this a bit,
   1.168 +    // but for now just set start and end separately.
   1.169 +    nsresult rv = SetStart(aStartParent, aStartOffset);
   1.170 +    NS_ENSURE_SUCCESS(rv, rv);
   1.171 +
   1.172 +    return SetEnd(aEndParent, aEndOffset);
   1.173 +  }
   1.174 +
   1.175 +  NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult);
   1.176 +
   1.177 +  // nsIMutationObserver methods
   1.178 +  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   1.179 +  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   1.180 +  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   1.181 +  NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
   1.182 +  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   1.183 +
   1.184 +  // WebIDL
   1.185 +  static already_AddRefed<nsRange>
   1.186 +  Constructor(const mozilla::dom::GlobalObject& global,
   1.187 +              mozilla::ErrorResult& aRv);
   1.188 +
   1.189 +  bool Collapsed() const
   1.190 +  {
   1.191 +    return mIsPositioned && mStartParent == mEndParent &&
   1.192 +           mStartOffset == mEndOffset;
   1.193 +  }
   1.194 +  already_AddRefed<mozilla::dom::DocumentFragment>
   1.195 +  CreateContextualFragment(const nsAString& aString, ErrorResult& aError);
   1.196 +  already_AddRefed<mozilla::dom::DocumentFragment>
   1.197 +  CloneContents(ErrorResult& aErr);
   1.198 +  int16_t CompareBoundaryPoints(uint16_t aHow, nsRange& aOther,
   1.199 +                                ErrorResult& aErr);
   1.200 +  int16_t ComparePoint(nsINode& aParent, uint32_t aOffset, ErrorResult& aErr);
   1.201 +  void DeleteContents(ErrorResult& aRv);
   1.202 +  already_AddRefed<mozilla::dom::DocumentFragment>
   1.203 +    ExtractContents(ErrorResult& aErr);
   1.204 +  nsINode* GetCommonAncestorContainer(ErrorResult& aRv) const;
   1.205 +  nsINode* GetStartContainer(ErrorResult& aRv) const;
   1.206 +  uint32_t GetStartOffset(ErrorResult& aRv) const;
   1.207 +  nsINode* GetEndContainer(ErrorResult& aRv) const;
   1.208 +  uint32_t GetEndOffset(ErrorResult& aRv) const;
   1.209 +  void InsertNode(nsINode& aNode, ErrorResult& aErr);
   1.210 +  bool IntersectsNode(nsINode& aNode, ErrorResult& aRv);
   1.211 +  bool IsPointInRange(nsINode& aParent, uint32_t aOffset, ErrorResult& aErr);
   1.212 +  void SelectNode(nsINode& aNode, ErrorResult& aErr);
   1.213 +  void SelectNodeContents(nsINode& aNode, ErrorResult& aErr);
   1.214 +  void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
   1.215 +  void SetEndAfter(nsINode& aNode, ErrorResult& aErr);
   1.216 +  void SetEndBefore(nsINode& aNode, ErrorResult& aErr);
   1.217 +  void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
   1.218 +  void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
   1.219 +  void SetStartBefore(nsINode& aNode, ErrorResult& aErr);
   1.220 +  void SurroundContents(nsINode& aNode, ErrorResult& aErr);
   1.221 +  already_AddRefed<DOMRect> GetBoundingClientRect();
   1.222 +  already_AddRefed<DOMRectList> GetClientRects();
   1.223 +
   1.224 +  nsINode* GetParentObject() const { return mOwner; }
   1.225 +  virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE MOZ_FINAL;
   1.226 +
   1.227 +private:
   1.228 +  // no copy's or assigns
   1.229 +  nsRange(const nsRange&);
   1.230 +  nsRange& operator=(const nsRange&);
   1.231 +
   1.232 +  /**
   1.233 +   * Cut or delete the range's contents.
   1.234 +   *
   1.235 +   * @param aFragment nsIDOMDocumentFragment containing the nodes.
   1.236 +   *                  May be null to indicate the caller doesn't want a fragment.
   1.237 +   */
   1.238 +  nsresult CutContents(mozilla::dom::DocumentFragment** frag);
   1.239 +
   1.240 +  static nsresult CloneParentsBetween(nsINode* aAncestor,
   1.241 +                                      nsINode* aNode,
   1.242 +                                      nsINode** aClosestAncestor,
   1.243 +                                      nsINode** aFarthestAncestor);
   1.244 +
   1.245 +public:
   1.246 +/******************************************************************************
   1.247 + *  Utility routine to detect if a content node starts before a range and/or
   1.248 + *  ends after a range.  If neither it is contained inside the range.
   1.249 + *
   1.250 + *  XXX - callers responsibility to ensure node in same doc as range!
   1.251 + *
   1.252 + *****************************************************************************/
   1.253 +  static nsresult CompareNodeToRange(nsINode* aNode, nsRange* aRange,
   1.254 +                                     bool *outNodeBefore,
   1.255 +                                     bool *outNodeAfter);
   1.256 +
   1.257 +  static bool IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
   1.258 +                             uint32_t aEndOffset);
   1.259 +
   1.260 +  typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
   1.261 +protected:
   1.262 +  void RegisterCommonAncestor(nsINode* aNode);
   1.263 +  void UnregisterCommonAncestor(nsINode* aNode);
   1.264 +  nsINode* IsValidBoundary(nsINode* aNode);
   1.265 +
   1.266 +  // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
   1.267 +  // and suppress re-registering a range common ancestor node since
   1.268 +  // the new text node of a splitText hasn't been inserted yet.
   1.269 +  // CharacterDataChanged does the re-registering when needed.
   1.270 +  void DoSetRange(nsINode* aStartN, int32_t aStartOffset,
   1.271 +                  nsINode* aEndN, int32_t aEndOffset,
   1.272 +                  nsINode* aRoot, bool aNotInsertedYet = false);
   1.273 +
   1.274 +  /**
   1.275 +   * For a range for which IsInSelection() is true, return the common
   1.276 +   * ancestor for the range.  This method uses the selection bits and
   1.277 +   * nsGkAtoms::range property on the nodes to quickly find the ancestor.
   1.278 +   * That is, it's a faster version of GetCommonAncestor that only works
   1.279 +   * for ranges in a Selection.  The method will assert and the behavior
   1.280 +   * is undefined if called on a range where IsInSelection() is false.
   1.281 +   */
   1.282 +  nsINode* GetRegisteredCommonAncestor();
   1.283 +
   1.284 +  struct MOZ_STACK_CLASS AutoInvalidateSelection
   1.285 +  {
   1.286 +    AutoInvalidateSelection(nsRange* aRange) : mRange(aRange)
   1.287 +    {
   1.288 +#ifdef DEBUG
   1.289 +      mWasInSelection = mRange->IsInSelection();
   1.290 +#endif
   1.291 +      if (!mRange->IsInSelection() || mIsNested) {
   1.292 +        return;
   1.293 +      }
   1.294 +      mIsNested = true;
   1.295 +      mCommonAncestor = mRange->GetRegisteredCommonAncestor();
   1.296 +    }
   1.297 +    ~AutoInvalidateSelection();
   1.298 +    nsRange* mRange;
   1.299 +    nsRefPtr<nsINode> mCommonAncestor;
   1.300 +#ifdef DEBUG
   1.301 +    bool mWasInSelection;
   1.302 +#endif
   1.303 +    static bool mIsNested;
   1.304 +  };
   1.305 +
   1.306 +  nsCOMPtr<nsIDocument> mOwner;
   1.307 +  nsCOMPtr<nsINode> mRoot;
   1.308 +  nsCOMPtr<nsINode> mStartParent;
   1.309 +  nsCOMPtr<nsINode> mEndParent;
   1.310 +  int32_t mStartOffset;
   1.311 +  int32_t mEndOffset;
   1.312 +
   1.313 +  bool mIsPositioned;
   1.314 +  bool mIsDetached;
   1.315 +  bool mMaySpanAnonymousSubtrees;
   1.316 +  bool mInSelection;
   1.317 +  bool mStartOffsetWasIncremented;
   1.318 +  bool mEndOffsetWasIncremented;
   1.319 +  bool mEnableGravitationOnElementRemoval;
   1.320 +#ifdef DEBUG
   1.321 +  int32_t  mAssertNextInsertOrAppendIndex;
   1.322 +  nsINode* mAssertNextInsertOrAppendNode;
   1.323 +#endif
   1.324 +};
   1.325 +
   1.326 +inline nsISupports*
   1.327 +ToCanonicalSupports(nsRange* aRange)
   1.328 +{
   1.329 +  return static_cast<nsIDOMRange*>(aRange);
   1.330 +}
   1.331 +
   1.332 +inline nsISupports*
   1.333 +ToSupports(nsRange* aRange)
   1.334 +{
   1.335 +  return static_cast<nsIDOMRange*>(aRange);
   1.336 +}
   1.337 +
   1.338 +#endif /* nsRange_h___ */

mercurial