1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 "HighlightRegistry.h"
9 #include "mozilla/ErrorResult.h"
10 #include "mozilla/CompactPair.h"
13 #include "Highlight.h"
14 #include "mozilla/dom/HighlightBinding.h"
15 #include "PresShell.h"
18 #include "nsCycleCollectionParticipant.h"
19 #include "nsFrameSelection.h"
21 namespace mozilla::dom
{
23 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(HighlightRegistry
)
25 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HighlightRegistry
)
26 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument
)
27 for (auto const& iter
: tmp
->mHighlightsOrdered
) {
28 iter
.second()->RemoveFromHighlightRegistry(*tmp
, *iter
.first());
30 NS_IMPL_CYCLE_COLLECTION_UNLINK(mHighlightsOrdered
)
31 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
32 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HighlightRegistry
)
35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument
)
36 for (size_t i
= 0; i
< tmp
->mHighlightsOrdered
.Length(); ++i
) {
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHighlightsOrdered
[i
].second())
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
41 NS_IMPL_CYCLE_COLLECTING_ADDREF(HighlightRegistry
)
42 NS_IMPL_CYCLE_COLLECTING_RELEASE(HighlightRegistry
)
43 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HighlightRegistry
)
44 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
45 NS_INTERFACE_MAP_ENTRY(nsISupports
)
48 HighlightRegistry::HighlightRegistry(Document
* aDocument
)
49 : mDocument(aDocument
) {}
51 HighlightRegistry::~HighlightRegistry() {
52 for (auto const& iter
: mHighlightsOrdered
) {
53 iter
.second()->RemoveFromHighlightRegistry(*this, *iter
.first());
57 JSObject
* HighlightRegistry::WrapObject(JSContext
* aCx
,
58 JS::Handle
<JSObject
*> aGivenProto
) {
59 return HighlightRegistry_Binding::Wrap(aCx
, this, aGivenProto
);
62 void HighlightRegistry::MaybeAddRangeToHighlightSelection(
63 AbstractRange
& aRange
, Highlight
& aHighlight
) {
64 RefPtr
<nsFrameSelection
> frameSelection
= GetFrameSelection();
65 if (!frameSelection
) {
68 MOZ_ASSERT(frameSelection
->GetPresShell());
69 if (!frameSelection
->GetPresShell()->GetDocument() ||
70 frameSelection
->GetPresShell()->GetDocument() !=
71 aRange
.GetComposedDocOfContainers()) {
72 // ranges that belong to a different document must not be added.
75 for (auto const& iter
: mHighlightsOrdered
) {
76 if (iter
.second() != &aHighlight
) {
80 const RefPtr
<nsAtom
> highlightName
= iter
.first();
81 frameSelection
->AddHighlightSelectionRange(highlightName
, aHighlight
,
86 void HighlightRegistry::MaybeRemoveRangeFromHighlightSelection(
87 AbstractRange
& aRange
, Highlight
& aHighlight
) {
88 RefPtr
<nsFrameSelection
> frameSelection
= GetFrameSelection();
89 if (!frameSelection
) {
92 MOZ_ASSERT(frameSelection
->GetPresShell());
94 for (auto const& iter
: mHighlightsOrdered
) {
95 if (iter
.second() != &aHighlight
) {
99 const RefPtr
<nsAtom
> highlightName
= iter
.first();
100 frameSelection
->RemoveHighlightSelectionRange(highlightName
, aRange
);
104 void HighlightRegistry::RemoveHighlightSelection(Highlight
& aHighlight
) {
105 RefPtr
<nsFrameSelection
> frameSelection
= GetFrameSelection();
106 if (!frameSelection
) {
109 for (auto const& iter
: mHighlightsOrdered
) {
110 if (iter
.second() != &aHighlight
) {
114 const RefPtr
<nsAtom
> highlightName
= iter
.first();
115 frameSelection
->RemoveHighlightSelection(highlightName
);
119 void HighlightRegistry::AddHighlightSelectionsToFrameSelection() {
120 if (mHighlightsOrdered
.IsEmpty()) {
123 RefPtr
<nsFrameSelection
> frameSelection
= GetFrameSelection();
124 if (!frameSelection
) {
127 for (auto const& iter
: mHighlightsOrdered
) {
128 RefPtr
<nsAtom
> highlightName
= iter
.first();
129 RefPtr
<Highlight
> highlight
= iter
.second();
130 frameSelection
->AddHighlightSelection(highlightName
, *highlight
);
134 void HighlightRegistry::Set(const nsAString
& aKey
, Highlight
& aValue
,
136 HighlightRegistry_Binding::MaplikeHelpers::Set(this, aKey
, aValue
, aRv
);
140 RefPtr
<nsFrameSelection
> frameSelection
= GetFrameSelection();
141 RefPtr
<nsAtom
> highlightNameAtom
= NS_AtomizeMainThread(aKey
);
143 std::find_if(mHighlightsOrdered
.begin(), mHighlightsOrdered
.end(),
144 [&highlightNameAtom
](auto const& aElm
) {
145 return aElm
.first() == highlightNameAtom
;
147 if (foundIter
!= mHighlightsOrdered
.end()) {
148 foundIter
->second()->RemoveFromHighlightRegistry(*this, *highlightNameAtom
);
149 if (frameSelection
) {
150 frameSelection
->RemoveHighlightSelection(highlightNameAtom
);
152 foundIter
->second() = &aValue
;
154 mHighlightsOrdered
.AppendElement(
155 CompactPair
<RefPtr
<nsAtom
>, RefPtr
<Highlight
>>(highlightNameAtom
,
158 aValue
.AddToHighlightRegistry(*this, *highlightNameAtom
);
159 if (frameSelection
) {
160 frameSelection
->AddHighlightSelection(highlightNameAtom
, aValue
);
164 void HighlightRegistry::Clear(ErrorResult
& aRv
) {
165 HighlightRegistry_Binding::MaplikeHelpers::Clear(this, aRv
);
169 auto frameSelection
= GetFrameSelection();
170 AutoFrameSelectionBatcher
batcher(__FUNCTION__
);
171 batcher
.AddFrameSelection(frameSelection
);
172 for (auto const& iter
: mHighlightsOrdered
) {
173 const RefPtr
<nsAtom
>& highlightName
= iter
.first();
174 const RefPtr
<Highlight
>& highlight
= iter
.second();
175 highlight
->RemoveFromHighlightRegistry(*this, *highlightName
);
176 if (frameSelection
) {
177 // The selection batcher makes sure that no script is run in this call.
178 // However, `nsFrameSelection::RemoveHighlightSelection` is marked
179 // `MOZ_CAN_RUN_SCRIPT`, therefore `MOZ_KnownLive` is needed regardless.
180 frameSelection
->RemoveHighlightSelection(MOZ_KnownLive(highlightName
));
184 mHighlightsOrdered
.Clear();
187 bool HighlightRegistry::Delete(const nsAString
& aKey
, ErrorResult
& aRv
) {
188 if (!HighlightRegistry_Binding::MaplikeHelpers::Delete(this, aKey
, aRv
)) {
191 RefPtr
<nsAtom
> highlightNameAtom
= NS_AtomizeMainThread(aKey
);
193 std::find_if(mHighlightsOrdered
.cbegin(), mHighlightsOrdered
.cend(),
194 [&highlightNameAtom
](auto const& aElm
) {
195 return aElm
.first() == highlightNameAtom
;
197 MOZ_ASSERT(foundIter
!= mHighlightsOrdered
.cend(),
198 "HighlightRegistry: maplike and internal data are out of sync!");
200 RefPtr
<Highlight
> highlight
= foundIter
->second();
201 mHighlightsOrdered
.RemoveElementAt(foundIter
);
203 if (auto frameSelection
= GetFrameSelection()) {
204 frameSelection
->RemoveHighlightSelection(highlightNameAtom
);
206 highlight
->RemoveFromHighlightRegistry(*this, *highlightNameAtom
);
210 RefPtr
<nsFrameSelection
> HighlightRegistry::GetFrameSelection() {
211 return RefPtr
<nsFrameSelection
>(
212 mDocument
->GetPresShell() ? mDocument
->GetPresShell()->FrameSelection()
216 } // namespace mozilla::dom