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