Index: third_party/WebKit/Source/core/editing/markers/SpellCheckMarkerList.cpp |
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellCheckMarkerList.cpp b/third_party/WebKit/Source/core/editing/markers/SpellCheckMarkerList.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a30726a144d3f0c1ef3cbf53268c394f2afeab8c |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/editing/markers/SpellCheckMarkerList.cpp |
@@ -0,0 +1,115 @@ |
+// 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 "core/editing/markers/SpellCheckMarkerList.h" |
+ |
+#include "core/editing/markers/DocumentMarkerListEditor.h" |
+ |
+namespace blink { |
+ |
+SpellCheckMarkerList::SpellCheckMarkerList(DocumentMarker::MarkerType type) |
+ : type_(type) {} |
+ |
+DocumentMarker::MarkerType SpellCheckMarkerList::GetAllowedMarkerType() const { |
+ return type_; |
+} |
+ |
+bool SpellCheckMarkerList::Empty() const { |
+ return markers_.IsEmpty(); |
+} |
+ |
+DocumentMarker* SpellCheckMarkerList::At(size_t index) { |
+ return markers_[index].Get(); |
+} |
+ |
+void SpellCheckMarkerList::Add(DocumentMarker* marker) { |
+ DCHECK_EQ(marker->GetType(), GetAllowedMarkerType()) |
+ << "Marker of type " << marker->GetType() << " added; should be of type " |
+ << GetAllowedMarkerType(); |
+ // Optimize case where (non-merging) markers are being added in order so we |
+ // can add n markers in O(n) time instead of O(n log n) |
+ if (markers_.IsEmpty() || |
+ markers_.back()->EndOffset() < marker->StartOffset()) { |
+ markers_.push_back(marker); |
+ return; |
+ } |
+ |
+ const auto& firstOverlappingIt = std::lower_bound( |
+ markers_.begin(), markers_.end(), marker, |
+ [](const Member<DocumentMarker>& lhv, const DocumentMarker* rhv) { |
+ return lhv->EndOffset() < rhv->StartOffset(); |
+ }); |
+ |
+ size_t index = firstOverlappingIt - markers_.begin(); |
+ markers_.insert(index, marker); |
+ const auto& insertedIt = markers_.begin() + index; |
+ |
+ unsigned newStart = marker->StartOffset(); |
+ unsigned newEnd = marker->EndOffset(); |
+ |
+ DocumentMarkerVector::iterator it; |
+ for (it = insertedIt + 1; |
+ it != markers_.end() && (*it)->StartOffset() <= newEnd; ++it) { |
+ newStart = std::min(newStart, (*it)->StartOffset()); |
+ newEnd = std::max(newEnd, (*it)->EndOffset()); |
+ } |
+ markers_.erase(index + 1, it - (insertedIt + 1)); |
+ |
+ (*insertedIt)->SetStartOffset(newStart); |
+ (*insertedIt)->SetEndOffset(newEnd); |
+} |
+ |
+void SpellCheckMarkerList::Clear() { |
+ markers_.Clear(); |
+} |
+ |
+void SpellCheckMarkerList::AppendMarkersToInputList( |
+ DocumentMarkerVector* list) const { |
+ list->AppendVector(markers_); |
+} |
+ |
+DocumentMarkerList::DidMoveMarkerOrNot SpellCheckMarkerList::MoveMarkers( |
+ int length, |
+ DocumentMarkerList* dst_list) { |
+ return DocumentMarkerListEditor::MoveSortedMarkers(&markers_, length, |
+ dst_list); |
+} |
+ |
+DocumentMarkerList::DidRemoveMarkerOrNot SpellCheckMarkerList::RemoveMarkers( |
+ unsigned start_offset, |
+ int length) { |
+ return DocumentMarkerListEditor::RemoveSortedMarkers(&markers_, start_offset, |
+ length); |
+} |
+ |
+DocumentMarkerList::DidShiftMarkerOrNot SpellCheckMarkerList::ShiftMarkers( |
+ unsigned offset, |
+ unsigned old_length, |
+ unsigned new_length) { |
+ return DocumentMarkerListEditor::ShiftSortedMarkers(&markers_, offset, |
+ old_length, new_length); |
+} |
+ |
+DEFINE_TRACE(SpellCheckMarkerList) { |
+ visitor->Trace(markers_); |
+ DocumentMarkerList::Trace(visitor); |
+} |
+ |
+void SpellCheckMarkerList::RemoveMarkersForWords(const String& node_text, |
+ const Vector<String>& words) { |
+ // Build a second vector and swap with markers_ to avoid O(n^2) performance |
+ HeapVector<Member<DocumentMarker>> new_marker_list; |
+ std::copy_if(markers_.begin(), markers_.end(), |
+ std::back_inserter(new_marker_list), |
+ [&node_text, &words](Member<DocumentMarker> marker) { |
+ unsigned start = marker->StartOffset(); |
+ unsigned length = marker->EndOffset() - marker->StartOffset(); |
+ const String& marker_text = node_text.Substring(start, length); |
+ return !words.Contains(marker_text); |
+ }); |
+ |
+ std::swap(markers_, new_marker_list); |
+} |
+ |
+} // namespace blink |