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 #include "mozilla/dom/StaticRange.h"
8 #include "mozilla/dom/StaticRangeBinding.h"
9 #include "nsContentUtils.h"
12 namespace mozilla::dom
{
14 template already_AddRefed
<StaticRange
> StaticRange::Create(
15 const RangeBoundary
& aStartBoundary
, const RangeBoundary
& aEndBoundary
,
17 template already_AddRefed
<StaticRange
> StaticRange::Create(
18 const RangeBoundary
& aStartBoundary
, const RawRangeBoundary
& aEndBoundary
,
20 template already_AddRefed
<StaticRange
> StaticRange::Create(
21 const RawRangeBoundary
& aStartBoundary
, const RangeBoundary
& aEndBoundary
,
23 template already_AddRefed
<StaticRange
> StaticRange::Create(
24 const RawRangeBoundary
& aStartBoundary
,
25 const RawRangeBoundary
& aEndBoundary
, ErrorResult
& aRv
);
26 template nsresult
StaticRange::SetStartAndEnd(
27 const RangeBoundary
& aStartBoundary
, const RangeBoundary
& aEndBoundary
);
28 template nsresult
StaticRange::SetStartAndEnd(
29 const RangeBoundary
& aStartBoundary
, const RawRangeBoundary
& aEndBoundary
);
30 template nsresult
StaticRange::SetStartAndEnd(
31 const RawRangeBoundary
& aStartBoundary
, const RangeBoundary
& aEndBoundary
);
32 template nsresult
StaticRange::SetStartAndEnd(
33 const RawRangeBoundary
& aStartBoundary
,
34 const RawRangeBoundary
& aEndBoundary
);
35 template void StaticRange::DoSetRange(const RangeBoundary
& aStartBoundary
,
36 const RangeBoundary
& aEndBoundary
,
38 template void StaticRange::DoSetRange(const RangeBoundary
& aStartBoundary
,
39 const RawRangeBoundary
& aEndBoundary
,
41 template void StaticRange::DoSetRange(const RawRangeBoundary
& aStartBoundary
,
42 const RangeBoundary
& aEndBoundary
,
44 template void StaticRange::DoSetRange(const RawRangeBoundary
& aStartBoundary
,
45 const RawRangeBoundary
& aEndBoundary
,
48 nsTArray
<RefPtr
<StaticRange
>>* StaticRange::sCachedRanges
= nullptr;
50 NS_IMPL_CYCLE_COLLECTING_ADDREF(StaticRange
)
51 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_INTERRUPTABLE_LAST_RELEASE(
52 StaticRange
, DoSetRange(RawRangeBoundary(), RawRangeBoundary(), nullptr),
53 AbstractRange::MaybeCacheToReuse(*this))
55 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StaticRange
)
56 NS_INTERFACE_MAP_END_INHERITING(AbstractRange
)
58 NS_IMPL_CYCLE_COLLECTION_CLASS(StaticRange
)
60 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(StaticRange
, AbstractRange
)
61 NS_IMPL_CYCLE_COLLECTION_UNLINK(mStart
)
62 NS_IMPL_CYCLE_COLLECTION_UNLINK(mEnd
)
63 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
65 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(StaticRange
, AbstractRange
)
66 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
68 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(StaticRange
, AbstractRange
)
69 NS_IMPL_CYCLE_COLLECTION_TRACE_END
72 already_AddRefed
<StaticRange
> StaticRange::Create(nsINode
* aNode
) {
74 if (!sCachedRanges
|| sCachedRanges
->IsEmpty()) {
76 new StaticRange(aNode
, RangeBoundaryIsMutationObserved::No
));
78 RefPtr
<StaticRange
> staticRange
= sCachedRanges
->PopLastElement().forget();
79 staticRange
->Init(aNode
);
80 return staticRange
.forget();
84 template <typename SPT
, typename SRT
, typename EPT
, typename ERT
>
85 already_AddRefed
<StaticRange
> StaticRange::Create(
86 const RangeBoundaryBase
<SPT
, SRT
>& aStartBoundary
,
87 const RangeBoundaryBase
<EPT
, ERT
>& aEndBoundary
, ErrorResult
& aRv
) {
88 RefPtr
<StaticRange
> staticRange
=
89 StaticRange::Create(aStartBoundary
.Container());
90 staticRange
->DoSetRange(aStartBoundary
, aEndBoundary
, nullptr);
92 return staticRange
.forget();
95 StaticRange::~StaticRange() {
96 DoSetRange(RawRangeBoundary(), RawRangeBoundary(), nullptr);
99 bool StaticRange::IsValid() const {
100 if (!mStart
.IsSetAndValid() || !mEnd
.IsSetAndValid()) {
104 MOZ_ASSERT(mAreStartAndEndInSameTree
==
105 (RangeUtils::ComputeRootNode(mStart
.Container()) ==
106 RangeUtils::ComputeRootNode(mEnd
.Container())));
107 if (!mAreStartAndEndInSameTree
) {
111 const Maybe
<int32_t> pointOrder
= nsContentUtils::ComparePoints(mStart
, mEnd
);
112 return pointOrder
.isSome() && *pointOrder
<= 0;
115 template <typename SPT
, typename SRT
, typename EPT
, typename ERT
>
116 void StaticRange::DoSetRange(const RangeBoundaryBase
<SPT
, SRT
>& aStartBoundary
,
117 const RangeBoundaryBase
<EPT
, ERT
>& aEndBoundary
,
118 nsINode
* aRootNode
) {
119 bool checkCommonAncestor
=
120 IsInAnySelection() && (mStart
.Container() != aStartBoundary
.Container() ||
121 mEnd
.Container() != aEndBoundary
.Container());
122 mStart
.CopyFrom(aStartBoundary
, mIsMutationObserved
);
123 mEnd
.CopyFrom(aEndBoundary
, mIsMutationObserved
);
124 MOZ_ASSERT(mStart
.IsSet() == mEnd
.IsSet());
125 mIsPositioned
= mStart
.IsSet() && mEnd
.IsSet();
127 if (checkCommonAncestor
) {
128 UpdateCommonAncestorIfNecessary();
131 mAreStartAndEndInSameTree
= RangeUtils::ComputeRootNode(mStart
.Container()) ==
132 RangeUtils::ComputeRootNode(mEnd
.Container());
136 already_AddRefed
<StaticRange
> StaticRange::Constructor(
137 const GlobalObject
& global
, const StaticRangeInit
& init
, ErrorResult
& aRv
) {
138 if (init
.mStartContainer
->NodeType() == nsINode::DOCUMENT_TYPE_NODE
||
139 init
.mStartContainer
->NodeType() == nsINode::ATTRIBUTE_NODE
||
140 init
.mEndContainer
->NodeType() == nsINode::DOCUMENT_TYPE_NODE
||
141 init
.mEndContainer
->NodeType() == nsINode::ATTRIBUTE_NODE
) {
142 aRv
.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR
);
146 return Create(init
.mStartContainer
, init
.mStartOffset
, init
.mEndContainer
,
147 init
.mEndOffset
, aRv
);
150 JSObject
* StaticRange::WrapObject(JSContext
* aCx
,
151 JS::Handle
<JSObject
*> aGivenProto
) {
152 return StaticRange_Binding::Wrap(aCx
, this, aGivenProto
);
155 } // namespace mozilla::dom