Skip to content

Commit

Permalink
Bug 1836013: Order highlight selections by insertion order. r=masayuki
Browse files Browse the repository at this point in the history
  • Loading branch information
jnjaeschke committed May 31, 2023
1 parent 6f49fe6 commit 1817114
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 26 deletions.
63 changes: 50 additions & 13 deletions layout/generic/nsFrameSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameSelection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDomSelections[i])
}

for (const auto& value : tmp->mHighlightSelections.Values()) {
CycleCollectionNoteChild(cb, value.get(), "mHighlightSelections[]");
for (const auto& value : tmp->mHighlightSelections) {
CycleCollectionNoteChild(cb, value.second().get(),
"mHighlightSelections[]");
}

NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
Expand Down Expand Up @@ -1559,8 +1560,16 @@ UniquePtr<SelectionDetails> nsFrameSelection::LookUpSelection(
kPresentSelectionTypes[j], aSlowCheck);
}
}
for (auto const& highlightSelection : mHighlightSelections.Values()) {
details = highlightSelection->LookUpSelection(

// This may seem counter intuitive at first. Highlight selections need to be
// iterated from back to front:
//
// - `mHighlightSelections` is ordered by insertion, i.e. if two or more
// highlights overlap, the latest must take precedence.
// - however, the `LookupSelection()` algorithm reverses the order by setting
// the current `details` as `mNext`.
for (const auto& iter : Reversed(mHighlightSelections)) {
details = iter.second()->LookUpSelection(
aContent, static_cast<uint32_t>(aContentOffset),
static_cast<uint32_t>(aContentLength), std::move(details),
SelectionType::eHighlight, aSlowCheck);
Expand Down Expand Up @@ -1600,36 +1609,64 @@ void nsFrameSelection::AddHighlightSelection(
const nsAtom* aHighlightName, const mozilla::dom::Highlight& aHighlight) {
RefPtr<Selection> selection =
aHighlight.CreateHighlightSelection(aHighlightName, this);
mHighlightSelections.InsertOrUpdate(aHighlightName, std::move(selection));
if (auto iter =
std::find_if(mHighlightSelections.begin(), mHighlightSelections.end(),
[&aHighlightName](auto const& aElm) {
return aElm.first() == aHighlightName;
});
iter != mHighlightSelections.end()) {
iter->second() = std::move(selection);
} else {
mHighlightSelections.AppendElement(
CompactPair<RefPtr<const nsAtom>, RefPtr<Selection>>(
aHighlightName, std::move(selection)));
}
}

void nsFrameSelection::RemoveHighlightSelection(const nsAtom* aHighlightName) {
if (auto maybeSelection = mHighlightSelections.MaybeGet(aHighlightName)) {
RefPtr<Selection> selection = *maybeSelection;
if (auto iter =
std::find_if(mHighlightSelections.begin(), mHighlightSelections.end(),
[&aHighlightName](auto const& aElm) {
return aElm.first() == aHighlightName;
});
iter != mHighlightSelections.end()) {
RefPtr<Selection> selection = iter->second();
selection->RemoveAllRanges(IgnoreErrors());
mHighlightSelections.Remove(aHighlightName);
mHighlightSelections.RemoveElementAt(iter);
}
}

void nsFrameSelection::AddHighlightSelectionRange(
const nsAtom* aHighlightName, const mozilla::dom::Highlight& aHighlight,
mozilla::dom::AbstractRange& aRange) {
if (auto lookupResult = mHighlightSelections.Lookup(aHighlightName)) {
RefPtr<Selection> selection = lookupResult.Data();
if (auto iter =
std::find_if(mHighlightSelections.begin(), mHighlightSelections.end(),
[&aHighlightName](auto const& aElm) {
return aElm.first() == aHighlightName;
});
iter != mHighlightSelections.end()) {
RefPtr<Selection> selection = iter->second();
selection->AddHighlightRangeAndSelectFramesAndNotifyListeners(aRange);
} else {
// if the selection does not exist yet, add all of its ranges and exit.
RefPtr<Selection> selection =
aHighlight.CreateHighlightSelection(aHighlightName, this);
lookupResult.Data() = selection;
mHighlightSelections.AppendElement(
CompactPair<RefPtr<const nsAtom>, RefPtr<Selection>>(
aHighlightName, std::move(selection)));
}
}

void nsFrameSelection::RemoveHighlightSelectionRange(
const nsAtom* aHighlightName, mozilla::dom::AbstractRange& aRange) {
if (const auto lookupResult = mHighlightSelections.Lookup(aHighlightName)) {
if (auto iter =
std::find_if(mHighlightSelections.begin(), mHighlightSelections.end(),
[&aHighlightName](auto const& aElm) {
return aElm.first() == aHighlightName;
});
iter != mHighlightSelections.end()) {
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
RefPtr<Selection> selection = lookupResult.Data();
RefPtr<Selection> selection = iter->second();
selection->RemoveRangeAndUnselectFramesAndNotifyListeners(aRange,
IgnoreErrors());
}
Expand Down
4 changes: 3 additions & 1 deletion layout/generic/nsFrameSelection.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "mozilla/intl/BidiEmbeddingLevel.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/CompactPair.h"
#include "mozilla/EnumSet.h"
#include "mozilla/EventForwards.h"
#include "mozilla/dom/Selection.h"
Expand Down Expand Up @@ -983,7 +984,8 @@ class nsFrameSelection final {
mDomSelections[sizeof(mozilla::kPresentSelectionTypes) /
sizeof(mozilla::SelectionType)];

nsTHashMap<RefPtr<const nsAtom>, RefPtr<mozilla::dom::Selection>>
nsTArray<mozilla::CompactPair<RefPtr<const nsAtom>,
RefPtr<mozilla::dom::Selection>>>
mHighlightSelections;

struct TableSelection {
Expand Down

This file was deleted.

0 comments on commit 1817114

Please sign in to comment.