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..e066912213179841d0c11228a9e5692da8d33413 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp |
@@ -0,0 +1,222 @@ |
+// 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(); |
+ }); |
+} |
+ |
+bool DocumentMarkerListEditor::MoveUnsortedMarkers( |
+ DocumentMarkerVector* marker_list, |
+ int length, |
+ DocumentMarkerList* dst_list) { |
+ DCHECK_GT(length, 0); |
+ bool didMoveMarker = false; |
+ unsigned end_offset = length - 1; |
+ |
+ DocumentMarkerVector marker_list_after_move; |
+ |
+ for (Member<DocumentMarker> marker : *marker_list) { |
+ if (marker->StartOffset() > end_offset) { |
+ marker_list_after_move.push_back(marker); |
+ continue; |
+ } |
+ |
+ // pin the marker to the specified range |
+ if (marker->EndOffset() > end_offset) |
+ marker->SetEndOffset(end_offset); |
+ |
+ dst_list->Add(marker); |
+ didMoveMarker = true; |
+ } |
+ |
+ std::swap(*marker_list, marker_list_after_move); |
+ |
+ return didMoveMarker; |
+} |
+ |
+bool DocumentMarkerListEditor::MoveSortedMarkers( |
+ DocumentMarkerVector* marker_list, |
+ int length, |
+ DocumentMarkerList* dst_list) { |
+ DCHECK_GT(length, 0); |
+ bool didMoveMarker = false; |
+ unsigned end_offset = length - 1; |
+ |
+ DocumentMarkerVector::iterator it; |
+ for (it = marker_list->begin(); it != marker_list->end(); ++it) { |
+ DocumentMarker& marker = **it; |
+ if (marker.StartOffset() > end_offset) |
+ break; |
+ |
+ // pin the marker to the specified range |
+ if (marker.EndOffset() > end_offset) |
+ marker.SetEndOffset(end_offset); |
+ |
+ dst_list->Add(&marker); |
+ didMoveMarker = true; |
+ } |
+ |
+ // Remove the range of markers that were moved to dstNode |
+ marker_list->erase(0, it - marker_list->begin()); |
+ |
+ return didMoveMarker; |
+} |
+ |
+bool DocumentMarkerListEditor::RemoveUnsortedMarkers( |
+ DocumentMarkerVector* marker_list, |
+ unsigned start_offset, |
+ int length) { |
+ unsigned end_offset = start_offset + length; |
+ bool didRemoveMarker = false; |
+ |
+ 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 = true; |
+ } |
+ } |
+ |
+ return didRemoveMarker; |
+} |
+ |
+bool 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 false; |
+ |
+ return true; |
+} |
+ |
+bool DocumentMarkerListEditor::ShiftUnsortedMarkers( |
+ DocumentMarkerVector* marker_list, |
+ unsigned offset, |
+ unsigned old_length, |
+ unsigned new_length) { |
+ bool didShiftMarker = false; |
+ 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) { |
+ didShiftMarker = true; |
+ // 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); |
+ |
+ didShiftMarker = true; |
+ } |
+ } |
+ |
+ return didShiftMarker; |
+} |
+ |
+bool DocumentMarkerListEditor::ShiftSortedMarkers( |
+ DocumentMarkerVector* marker_list, |
+ unsigned offset, |
+ unsigned old_length, |
+ unsigned new_length) { |
+ DocumentMarkerVector newMarkerList; |
+ bool didShiftMarker = false; |
+ for (Member<DocumentMarker> marker : *marker_list) { |
+ Optional<DocumentMarker::MarkerOffsets> result = |
+ marker->ComputeOffsetsAfterShift(offset, old_length, new_length); |
+ |
+ if (result == WTF::kNullopt) { |
+ didShiftMarker = true; |
+ 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); |
+ |
+ didShiftMarker = true; |
+ } |
+ |
+ newMarkerList.push_back(marker); |
+ } |
+ |
+ swap(*marker_list, newMarkerList); |
+ return didShiftMarker; |
+} |
+ |
+bool DocumentMarkerListEditor::MoveMarkersHelper( |
+ DocumentMarkerVector* marker_list, |
+ int length, |
+ DocumentMarkerList* dst_list, |
+ bool is_sorted) { |
+ DCHECK_GT(length, 0); |
+ bool didMoveMarker = false; |
+ unsigned end_offset = length - 1; |
+ |
+ DocumentMarkerVector::iterator it; |
+ for (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 |
+ didMoveMarker = true; |
+ |
+ if (marker.EndOffset() > end_offset) |
+ marker.SetEndOffset(end_offset); |
+ |
+ dst_list->Add(&marker); |
+ } |
+ |
+ // Remove the range of markers that were moved to dstNode |
+ marker_list->erase(0, it - marker_list->begin()); |
+ |
+ return didMoveMarker; |
+} |
+ |
+} // namespace blink |