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 #ifndef mozilla_RangeUtils_h
8 #define mozilla_RangeUtils_h
9 
10 #include "mozilla/Maybe.h"
11 #include "mozilla/RangeBoundary.h"
12 #include "nsIContent.h"
13 #include "nsINode.h"
14 
15 namespace mozilla {
16 
17 namespace dom {
18 class AbstractRange;
19 }  // namespace dom
20 
21 class RangeUtils final {
22   typedef dom::AbstractRange AbstractRange;
23 
24  public:
25   /**
26    * GetRawRangeBoundaryBefore() and GetRawRangeBoundaryAfter() retrieve
27    * RawRangeBoundary which points before or after aNode.
28    */
GetRawRangeBoundaryAfter(nsINode * aNode)29   static const RawRangeBoundary GetRawRangeBoundaryAfter(nsINode* aNode) {
30     MOZ_ASSERT(aNode);
31 
32     if (NS_WARN_IF(!aNode->IsContent())) {
33       return RawRangeBoundary();
34     }
35 
36     nsINode* parentNode = aNode->GetParentNode();
37     if (!parentNode) {
38       return RawRangeBoundary();
39     }
40     RawRangeBoundary afterNode(parentNode, aNode->AsContent());
41     // If aNode isn't in the child nodes of its parent node, we hit this case.
42     // This may occur when we're called by a mutation observer while aNode is
43     // removed from the parent node.
44     if (NS_WARN_IF(
45             !afterNode.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets))) {
46       return RawRangeBoundary();
47     }
48     return afterNode;
49   }
50 
GetRawRangeBoundaryBefore(nsINode * aNode)51   static const RawRangeBoundary GetRawRangeBoundaryBefore(nsINode* aNode) {
52     MOZ_ASSERT(aNode);
53 
54     if (NS_WARN_IF(!aNode->IsContent())) {
55       return RawRangeBoundary();
56     }
57 
58     nsINode* parentNode = aNode->GetParentNode();
59     if (!parentNode) {
60       return RawRangeBoundary();
61     }
62     // If aNode isn't in the child nodes of its parent node, we hit this case.
63     // This may occur when we're called by a mutation observer while aNode is
64     // removed from the parent node.
65     const Maybe<uint32_t> indexInParent = parentNode->ComputeIndexOf(aNode);
66     if (MOZ_UNLIKELY(NS_WARN_IF(indexInParent.isNothing()))) {
67       return RawRangeBoundary();
68     }
69     return RawRangeBoundary(parentNode, *indexInParent);
70   }
71 
72   /**
73    * Compute the root node of aNode for initializing range classes.
74    * When aNode is in an anonymous subtree, this returns the shadow root or
75    * binding parent.  Otherwise, the root node of the document or document
76    * fragment.  If this returns nullptr, that means aNode can be neither the
77    * start container nor end container of any range.
78    */
79   static nsINode* ComputeRootNode(nsINode* aNode);
80 
81   /**
82    * XXX nsRange should accept 0 - UINT32_MAX as offset.  However, users of
83    *     nsRange treat offset as int32_t.  Additionally, some other internal
84    *     APIs like nsINode::ComputeIndexOf_Deprecated() use int32_t.  Therefore,
85    *     nsRange should accept only 0 - INT32_MAX as valid offset for now.
86    */
IsValidOffset(uint32_t aOffset)87   static bool IsValidOffset(uint32_t aOffset) { return aOffset <= INT32_MAX; }
88 
89   /**
90    * Return true if aStartContainer/aStartOffset and aEndContainer/aEndOffset
91    * are valid start and end points for a range.  Otherwise, return false.
92    */
IsValidPoints(nsINode * aStartContainer,uint32_t aStartOffset,nsINode * aEndContainer,uint32_t aEndOffset)93   static bool IsValidPoints(nsINode* aStartContainer, uint32_t aStartOffset,
94                             nsINode* aEndContainer, uint32_t aEndOffset) {
95     return IsValidPoints(RawRangeBoundary(aStartContainer, aStartOffset),
96                          RawRangeBoundary(aEndContainer, aEndOffset));
97   }
98   template <typename SPT, typename SRT, typename EPT, typename ERT>
99   static bool IsValidPoints(const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
100                             const RangeBoundaryBase<EPT, ERT>& aEndBoundary);
101 
102   /**
103    * The caller needs to ensure aNode is in the same doc like aAbstractRange.
104    */
105   static Maybe<bool> IsNodeContainedInRange(nsINode& aNode,
106                                             AbstractRange* aAbstractRange);
107 
108   /**
109    * Utility routine to detect if a content node starts before a range and/or
110    * ends after a range.  If neither it is contained inside the range.
111    * Note that callers responsibility to ensure node in same doc as range.
112    */
113   static nsresult CompareNodeToRange(nsINode* aNode,
114                                      AbstractRange* aAbstractRange,
115                                      bool* aNodeIsBeforeRange,
116                                      bool* aNodeIsAfterRange);
117 };
118 
119 }  // namespace mozilla
120 
121 #endif  // #ifndef mozilla_RangeUtils_h
122