blob: 3d4f48a46d82954387d978f4c392b521bb8ec874 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/editing/markers/spell_check_marker_list_impl.h"
#include "third_party/blink/renderer/core/editing/markers/sorted_document_marker_list_editor.h"
namespace blink {
bool SpellCheckMarkerListImpl::IsEmpty() const {
return markers_.IsEmpty();
}
void SpellCheckMarkerListImpl::Add(DocumentMarker* marker) {
DCHECK_EQ(MarkerType(), marker->GetType());
if (markers_.IsEmpty() ||
markers_.back()->EndOffset() < marker->StartOffset()) {
markers_.push_back(marker);
return;
}
// Find first marker that ends after the one being inserted starts. If any
// markers overlap the one being inserted, this is the first one.
auto* const first_overlapping = std::lower_bound(
markers_.begin(), markers_.end(), marker,
[](const Member<DocumentMarker>& marker_in_list,
const DocumentMarker* marker_to_insert) {
return marker_in_list->EndOffset() < marker_to_insert->StartOffset();
});
// If this marker does not overlap the one being inserted, insert before it
// and we are done.
if (marker->EndOffset() < (*first_overlapping)->StartOffset()) {
markers_.insert(
static_cast<wtf_size_t>(first_overlapping - markers_.begin()), marker);
return;
}
// Otherwise, find the last overlapping marker, replace the first marker with
// the newly-inserted marker (to get the new description), set its start and
// end offsets to include all the overlapped markers, and erase the rest of
// the old markers.
auto* const last_overlapping = std::upper_bound(
first_overlapping, markers_.end(), marker,
[](const DocumentMarker* marker_to_insert,
const Member<DocumentMarker>& marker_in_list) {
return marker_to_insert->EndOffset() < marker_in_list->StartOffset();
});
marker->SetStartOffset(
std::min(marker->StartOffset(), (*first_overlapping)->StartOffset()));
marker->SetEndOffset(
std::max(marker->EndOffset(), (*(last_overlapping - 1))->EndOffset()));
*first_overlapping = marker;
wtf_size_t num_to_erase =
static_cast<wtf_size_t>(last_overlapping - (first_overlapping + 1));
markers_.EraseAt(
static_cast<wtf_size_t>(first_overlapping + 1 - markers_.begin()),
num_to_erase);
}
void SpellCheckMarkerListImpl::Clear() {
markers_.clear();
}
const HeapVector<Member<DocumentMarker>>& SpellCheckMarkerListImpl::GetMarkers()
const {
return markers_;
}
DocumentMarker* SpellCheckMarkerListImpl::FirstMarkerIntersectingRange(
unsigned start_offset,
unsigned end_offset) const {
return SortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
markers_, start_offset, end_offset);
}
HeapVector<Member<DocumentMarker>>
SpellCheckMarkerListImpl::MarkersIntersectingRange(unsigned start_offset,
unsigned end_offset) const {
return SortedDocumentMarkerListEditor::MarkersIntersectingRange(
markers_, start_offset, end_offset);
}
bool SpellCheckMarkerListImpl::MoveMarkers(int length,
DocumentMarkerList* dst_list) {
return SortedDocumentMarkerListEditor::MoveMarkers(&markers_, length,
dst_list);
}
bool SpellCheckMarkerListImpl::RemoveMarkers(unsigned start_offset,
int length) {
return SortedDocumentMarkerListEditor::RemoveMarkers(&markers_, start_offset,
length);
}
bool SpellCheckMarkerListImpl::ShiftMarkers(const String&,
unsigned offset,
unsigned old_length,
unsigned new_length) {
return SortedDocumentMarkerListEditor::ShiftMarkersContentDependent(
&markers_, offset, old_length, new_length);
}
void SpellCheckMarkerListImpl::Trace(Visitor* visitor) const {
visitor->Trace(markers_);
DocumentMarkerList::Trace(visitor);
}
bool SpellCheckMarkerListImpl::RemoveMarkersUnderWords(
const String& node_text,
const Vector<String>& words) {
bool removed_markers = false;
for (wtf_size_t j = markers_.size(); j > 0; --j) {
const DocumentMarker& marker = *markers_[j - 1];
const unsigned start = marker.StartOffset();
const unsigned length = marker.EndOffset() - marker.StartOffset();
const String& marker_text = node_text.Substring(start, length);
if (words.Contains(marker_text)) {
markers_.EraseAt(j - 1);
removed_markers = true;
}
}
return removed_markers;
}
} // namespace blink