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/. */
7 #ifndef mozilla_RangeUtils_h
8 #define mozilla_RangeUtils_h
10 #include "mozilla/Maybe.h"
11 #include "mozilla/RangeBoundary.h"
12 #include "nsIContent.h"
21 * ShadowDOMSelectionHelpers contains the static methods to help extra values
22 * based on whether or not the iterator allows to iterate nodes cross the shadow
25 struct ShadowDOMSelectionHelpers
{
26 ShadowDOMSelectionHelpers() = delete;
28 static nsINode
* GetStartContainer(const AbstractRange
* aRange
,
29 bool aAllowCrossShadowBoundary
);
31 static uint32_t StartOffset(const AbstractRange
* aRange
,
32 bool aAllowCrossShadowBoundary
);
34 static nsINode
* GetEndContainer(const AbstractRange
* aRange
,
35 bool aAllowCrossShadowBoundary
);
37 static uint32_t EndOffset(const AbstractRange
* aRange
,
38 bool aAllowCrossShadowBoundary
);
40 static nsINode
* GetParentNode(nsINode
& aNode
, bool aAllowCrossShadowBoundary
);
42 static ShadowRoot
* GetShadowRoot(const nsINode
* aNode
,
43 bool aAllowCrossShadowBoundary
);
47 class RangeUtils final
{
48 typedef dom::AbstractRange AbstractRange
;
52 * GetRawRangeBoundaryBefore() and GetRawRangeBoundaryAfter() retrieve
53 * RawRangeBoundary which points before or after aNode.
55 static const RawRangeBoundary
GetRawRangeBoundaryAfter(nsINode
* aNode
) {
58 if (NS_WARN_IF(!aNode
->IsContent())) {
59 return RawRangeBoundary();
62 nsINode
* parentNode
= aNode
->GetParentNode();
64 return RawRangeBoundary();
66 RawRangeBoundary
afterNode(parentNode
, aNode
->AsContent());
67 // If aNode isn't in the child nodes of its parent node, we hit this case.
68 // This may occur when we're called by a mutation observer while aNode is
69 // removed from the parent node.
71 !afterNode
.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets
))) {
72 return RawRangeBoundary();
77 static const RawRangeBoundary
GetRawRangeBoundaryBefore(nsINode
* aNode
) {
80 if (NS_WARN_IF(!aNode
->IsContent())) {
81 return RawRangeBoundary();
84 nsINode
* parentNode
= aNode
->GetParentNode();
86 return RawRangeBoundary();
88 // If aNode isn't in the child nodes of its parent node, we hit this case.
89 // This may occur when we're called by a mutation observer while aNode is
90 // removed from the parent node.
91 const Maybe
<uint32_t> indexInParent
= parentNode
->ComputeIndexOf(aNode
);
92 if (MOZ_UNLIKELY(NS_WARN_IF(indexInParent
.isNothing()))) {
93 return RawRangeBoundary();
95 return RawRangeBoundary(parentNode
, *indexInParent
);
99 * Compute the root node of aNode for initializing range classes.
100 * When aNode is in an anonymous subtree, this returns the shadow root or
101 * binding parent. Otherwise, the root node of the document or document
102 * fragment. If this returns nullptr, that means aNode can be neither the
103 * start container nor end container of any range.
105 static nsINode
* ComputeRootNode(nsINode
* aNode
);
108 * XXX nsRange should accept 0 - UINT32_MAX as offset. However, users of
109 * nsRange treat offset as int32_t. Additionally, some other internal
110 * APIs like nsINode::ComputeIndexOf_Deprecated() use int32_t. Therefore,
111 * nsRange should accept only 0 - INT32_MAX as valid offset for now.
113 static bool IsValidOffset(uint32_t aOffset
) { return aOffset
<= INT32_MAX
; }
116 * Return true if aStartContainer/aStartOffset and aEndContainer/aEndOffset
117 * are valid start and end points for a range. Otherwise, return false.
119 static bool IsValidPoints(nsINode
* aStartContainer
, uint32_t aStartOffset
,
120 nsINode
* aEndContainer
, uint32_t aEndOffset
) {
121 return IsValidPoints(RawRangeBoundary(aStartContainer
, aStartOffset
),
122 RawRangeBoundary(aEndContainer
, aEndOffset
));
124 template <typename SPT
, typename SRT
, typename EPT
, typename ERT
>
125 static bool IsValidPoints(const RangeBoundaryBase
<SPT
, SRT
>& aStartBoundary
,
126 const RangeBoundaryBase
<EPT
, ERT
>& aEndBoundary
);
129 * The caller needs to ensure aNode is in the same doc like aAbstractRange.
131 static Maybe
<bool> IsNodeContainedInRange(nsINode
& aNode
,
132 AbstractRange
* aAbstractRange
);
135 * Utility routine to detect if a content node starts before a range and/or
136 * ends after a range. If neither it is contained inside the range.
137 * Note that callers responsibility to ensure node in same doc as range.
139 static nsresult
CompareNodeToRange(nsINode
* aNode
,
140 AbstractRange
* aAbstractRange
,
141 bool* aNodeIsBeforeRange
,
142 bool* aNodeIsAfterRange
);
144 template <typename SPT
, typename SRT
, typename EPT
, typename ERT
>
145 static nsresult
CompareNodeToRangeBoundaries(
146 nsINode
* aNode
, const RangeBoundaryBase
<SPT
, SRT
>& aStartBoundary
,
147 const RangeBoundaryBase
<EPT
, ERT
>& aEndBoundary
, bool* aNodeIsBeforeRange
,
148 bool* aNodeIsAfterRange
);
151 } // namespace mozilla
153 #endif // #ifndef mozilla_RangeUtils_h