Index: third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp |
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..28d592ccd0daf927f39a5eacd2804f1fb80b1128 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp |
@@ -0,0 +1,183 @@ |
+// 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/DocumentMarkerListEditor.h" |
+ |
+namespace blink { |
+ |
+DocumentMarkerVector::iterator |
+DocumentMarkerListEditor::GetPosOfFirstMarkerNotEndingBeforeInSortedList( |
+ DocumentMarkerVector* marker_list, |
+ size_t start_offset) { |
+ return std::upper_bound( |
+ marker_list->begin(), marker_list->end(), start_offset, |
+ [](size_t start_offset, const Member<DocumentMarker>& rhv) -> bool { |
+ return start_offset < rhv->EndOffset(); |
+ }); |
+} |
+ |
+DocumentMarkerList::DidMoveMarkerOrNot |
+DocumentMarkerListEditor::MoveUnsortedMarkers(DocumentMarkerVector* marker_list, |
+ int length, |
+ DocumentMarkerList* dst_list) { |
+ return MoveMarkersHelper(marker_list, length, dst_list, false); |
+} |
+ |
+DocumentMarkerList::DidMoveMarkerOrNot |
+DocumentMarkerListEditor::MoveSortedMarkers(DocumentMarkerVector* marker_list, |
+ int length, |
+ DocumentMarkerList* dst_list) { |
+ return MoveMarkersHelper(marker_list, length, dst_list, true); |
+} |
+ |
+DocumentMarkerList::DidRemoveMarkerOrNot |
+DocumentMarkerListEditor::RemoveUnsortedMarkers( |
+ DocumentMarkerVector* marker_list, |
+ unsigned start_offset, |
+ int length) { |
+ unsigned end_offset = start_offset + length; |
+ DocumentMarkerList::DidRemoveMarkerOrNot didRemoveMarker = |
+ DocumentMarkerList::DidRemoveMarkerOrNot::kDidNotRemoveMarker; |
+ |
+ for (auto it = marker_list->begin(); it != marker_list->end(); ++it) { |
+ const DocumentMarker& marker = **it; |
+ |
+ // markers have non-empty overlap |
+ if (marker.StartOffset() < end_offset && |
+ marker.EndOffset() > start_offset) { |
+ // Erase by doing a swap-and-shrink to get O(1) performance |
+ std::swap(*it, marker_list->back()); |
+ marker_list->Shrink(marker_list->size() - 1); |
+ --it; |
+ |
+ didRemoveMarker = |
+ DocumentMarkerList::DidRemoveMarkerOrNot::kDidRemoveMarker; |
+ } |
+ } |
+ |
+ return didRemoveMarker; |
+} |
+ |
+DocumentMarkerList::DocumentMarkerList::DidRemoveMarkerOrNot |
+DocumentMarkerListEditor::RemoveSortedMarkers(DocumentMarkerVector* marker_list, |
+ unsigned start_offset, |
+ int length) { |
+ unsigned end_offset = start_offset + length; |
+ |
+ const auto startPos = |
+ GetPosOfFirstMarkerNotEndingBeforeInSortedList(marker_list, start_offset); |
+ auto it = startPos; |
+ for (; it != marker_list->end(); ++it) { |
+ if ((*it)->StartOffset() >= end_offset) |
+ break; |
+ } |
+ |
+ // it should now point at the first marker *not* to be removed (or at |
+ // marker_list->end()) |
+ marker_list->erase(startPos - marker_list->begin(), it - startPos); |
+ |
+ if (it == startPos) |
+ return DocumentMarkerList::DidRemoveMarkerOrNot::kDidNotRemoveMarker; |
+ |
+ return DocumentMarkerList::DidRemoveMarkerOrNot::kDidRemoveMarker; |
+} |
+ |
+DocumentMarkerList::DidShiftMarkerOrNot |
+DocumentMarkerListEditor::ShiftUnsortedMarkers( |
+ DocumentMarkerVector* marker_list, |
+ unsigned offset, |
+ unsigned old_length, |
+ unsigned new_length) { |
+ DocumentMarkerList::DidShiftMarkerOrNot didShift = |
+ DocumentMarkerList::DidShiftMarkerOrNot::kDidNotShiftMarker; |
+ for (auto it = marker_list->begin(); it != marker_list->end(); ++it) { |
+ DocumentMarker& marker = **it; |
+ Optional<DocumentMarker::MarkerOffsets> result = |
+ marker.ComputeOffsetsAfterShift(offset, old_length, new_length); |
+ |
+ if (result == WTF::kNullopt) { |
+ didShift = DocumentMarkerList::DidShiftMarkerOrNot::kDidShiftMarker; |
+ // Erase by doing a swap-and-shrink to get O(1) performance |
+ std::swap(*it, marker_list->back()); |
+ marker_list->Shrink(marker_list->size() - 1); |
+ --it; |
+ continue; |
+ } |
+ |
+ if (result.value().start_offset != marker.StartOffset() || |
+ result.value().end_offset != marker.EndOffset()) { |
+ marker.SetStartOffset(result.value().start_offset); |
+ marker.SetEndOffset(result.value().end_offset); |
+ |
+ didShift = DocumentMarkerList::DidShiftMarkerOrNot::kDidShiftMarker; |
+ } |
+ } |
+ |
+ return didShift; |
+} |
+ |
+DocumentMarkerList::DidShiftMarkerOrNot |
+DocumentMarkerListEditor::ShiftSortedMarkers(DocumentMarkerVector* marker_list, |
+ unsigned offset, |
+ unsigned old_length, |
+ unsigned new_length) { |
+ DocumentMarkerVector newMarkerList; |
+ DocumentMarkerList::DidShiftMarkerOrNot didShift = |
+ DocumentMarkerList::DidShiftMarkerOrNot::kDidNotShiftMarker; |
+ for (Member<DocumentMarker> marker : *marker_list) { |
+ Optional<DocumentMarker::MarkerOffsets> result = |
+ marker->ComputeOffsetsAfterShift(offset, old_length, new_length); |
+ |
+ if (result == WTF::kNullopt) { |
+ didShift = DocumentMarkerList::DidShiftMarkerOrNot::kDidShiftMarker; |
+ continue; |
+ } |
+ |
+ if (result.value().start_offset != marker->StartOffset() || |
+ result.value().end_offset != marker->EndOffset()) { |
+ marker->SetStartOffset(result.value().start_offset); |
+ marker->SetEndOffset(result.value().end_offset); |
+ |
+ didShift = DocumentMarkerList::DidShiftMarkerOrNot::kDidShiftMarker; |
+ } |
+ |
+ newMarkerList.push_back(marker); |
+ } |
+ |
+ swap(*marker_list, newMarkerList); |
+ return didShift; |
+} |
+ |
+DocumentMarkerList::DidMoveMarkerOrNot |
+DocumentMarkerListEditor::MoveMarkersHelper(DocumentMarkerVector* marker_list, |
+ int length, |
+ DocumentMarkerList* dst_list, |
+ bool is_sorted) { |
+ DocumentMarkerList::DidMoveMarkerOrNot didMoveMarker = |
+ DocumentMarkerList::DidMoveMarkerOrNot::kDidNotMoveMarker; |
+ unsigned end_offset = length - 1; |
+ |
+ for (auto it = marker_list->begin(); it != marker_list->end(); ++it) { |
+ DocumentMarker& marker = **it; |
+ if (marker.StartOffset() > end_offset) { |
+ if (is_sorted) |
+ break; |
+ continue; |
+ } |
+ |
+ // pin the marker to the specified range and apply the shift delta |
+ if (marker.StartOffset() <= end_offset) { |
rlanday
2017/04/11 02:59:09
This is redundant, I will remove
|
+ didMoveMarker = DocumentMarkerList::DidMoveMarkerOrNot::kDidMoveMarker; |
+ |
+ if (marker.EndOffset() > end_offset) |
+ marker.SetEndOffset(end_offset); |
+ |
+ dst_list->Add(&marker); |
+ } |
+ } |
+ |
+ return didMoveMarker; |
+} |
+ |
+} // namespace blink |