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()) {
75 return do_AddRef(new StaticRange(aNode
));
77 RefPtr
<StaticRange
> staticRange
= sCachedRanges
->PopLastElement().forget();
78 staticRange
->Init(aNode
);
79 return staticRange
.forget();
83 template <typename SPT
, typename SRT
, typename EPT
, typename ERT
>
84 already_AddRefed
<StaticRange
> StaticRange::Create(
85 const RangeBoundaryBase
<SPT
, SRT
>& aStartBoundary
,
86 const RangeBoundaryBase
<EPT
, ERT
>& aEndBoundary
, ErrorResult
& aRv
) {
87 RefPtr
<StaticRange
> staticRange
=
88 StaticRange::Create(aStartBoundary
.Container());
89 staticRange
->DoSetRange(aStartBoundary
, aEndBoundary
, nullptr);
91 return staticRange
.forget();
94 StaticRange::~StaticRange() {
95 DoSetRange(RawRangeBoundary(), RawRangeBoundary(), nullptr);
98 bool StaticRange::IsValid() const {
99 if (!mStart
.IsSetAndValid() || !mEnd
.IsSetAndValid()) {
103 MOZ_ASSERT(mAreStartAndEndInSameTree
==
104 (RangeUtils::ComputeRootNode(mStart
.Container()) ==
105 RangeUtils::ComputeRootNode(mEnd
.Container())));
106 if (!mAreStartAndEndInSameTree
) {
110 const Maybe
<int32_t> pointOrder
= nsContentUtils::ComparePoints(mStart
, mEnd
);
111 return pointOrder
.isSome() && *pointOrder
<= 0;
114 template <typename SPT
, typename SRT
, typename EPT
, typename ERT
>
115 void StaticRange::DoSetRange(const RangeBoundaryBase
<SPT
, SRT
>& aStartBoundary
,
116 const RangeBoundaryBase
<EPT
, ERT
>& aEndBoundary
,
117 nsINode
* aRootNode
) {
118 bool checkCommonAncestor
=
119 IsInAnySelection() && (mStart
.Container() != aStartBoundary
.Container() ||
120 mEnd
.Container() != aEndBoundary
.Container());
121 mStart
.CopyFrom(aStartBoundary
, RangeBoundaryIsMutationObserved::No
);
122 mEnd
.CopyFrom(aEndBoundary
, RangeBoundaryIsMutationObserved::No
);
123 MOZ_ASSERT(mStart
.IsSet() == mEnd
.IsSet());
124 mIsPositioned
= mStart
.IsSet() && mEnd
.IsSet();
126 if (checkCommonAncestor
) {
127 UpdateCommonAncestorIfNecessary();
130 mAreStartAndEndInSameTree
= RangeUtils::ComputeRootNode(mStart
.Container()) ==
131 RangeUtils::ComputeRootNode(mEnd
.Container());
135 already_AddRefed
<StaticRange
> StaticRange::Constructor(
136 const GlobalObject
& global
, const StaticRangeInit
& init
, ErrorResult
& aRv
) {
137 if (init
.mStartContainer
->NodeType() == nsINode::DOCUMENT_TYPE_NODE
||
138 init
.mStartContainer
->NodeType() == nsINode::ATTRIBUTE_NODE
||
139 init
.mEndContainer
->NodeType() == nsINode::DOCUMENT_TYPE_NODE
||
140 init
.mEndContainer
->NodeType() == nsINode::ATTRIBUTE_NODE
) {
141 aRv
.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR
);
145 return Create(init
.mStartContainer
, init
.mStartOffset
, init
.mEndContainer
,
146 init
.mEndOffset
, aRv
);
149 JSObject
* StaticRange::WrapObject(JSContext
* aCx
,
150 JS::Handle
<JSObject
*> aGivenProto
) {
151 return StaticRange_Binding::Wrap(aCx
, this, aGivenProto
);
154 } // namespace mozilla::dom