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 |
index f7477a830e2b6833b6e1bf447a0dae49c2ea66ec..26347fa59109a6b5e21900991a190f1c9a7852a0 100644 |
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp |
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp |
@@ -72,25 +72,30 @@ bool DocumentMarkerListEditor::RemoveMarkers(MarkerList* list, |
return start_pos != end_pos; |
} |
-// TODO(rlanday): make this not take O(n^2) time when all the markers are |
-// removed |
bool DocumentMarkerListEditor::ShiftMarkersContentDependent( |
MarkerList* list, |
unsigned offset, |
unsigned old_length, |
unsigned new_length) { |
+ // Find first marker that ends after the start of the region being edited. |
+ // Markers before this one can be left untouched. This saves us some time over |
+ // scanning the entire list linearly if the edit region is near the end of the |
+ // text node. |
+ const MarkerList::iterator& shift_range_begin = |
+ std::upper_bound(list->begin(), list->end(), offset, |
+ [](size_t offset, const Member<DocumentMarker>& marker) { |
+ return offset < marker->EndOffset(); |
+ }); |
+ |
+ MarkerList::iterator erase_range_end = shift_range_begin; |
+ |
bool did_shift_marker = false; |
- for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) { |
+ for (MarkerList::iterator it = shift_range_begin; it != list->end(); ++it) { |
DocumentMarker& marker = **it; |
- // marked text is neither changed nor shifted |
- if (marker.EndOffset() <= offset) |
- continue; |
- |
// marked text is (potentially) changed by edit, remove marker |
if (marker.StartOffset() < offset + old_length) { |
- list->erase(it - list->begin()); |
- --it; |
+ erase_range_end = std::next(it); |
did_shift_marker = true; |
continue; |
} |
@@ -100,24 +105,41 @@ bool DocumentMarkerListEditor::ShiftMarkersContentDependent( |
did_shift_marker = true; |
} |
+ // Note: shift_range_begin could point at a marker being shifted instead of |
+ // deleted, but if this is the case, we don't need to delete any markers, and |
+ // erase() will get 0 for the length param |
+ list->erase(shift_range_begin - list->begin(), |
+ erase_range_end - shift_range_begin); |
return did_shift_marker; |
} |
-// TODO(rlanday): make this not take O(n^2) time when all the markers are |
-// removed |
bool DocumentMarkerListEditor::ShiftMarkersContentIndependent( |
MarkerList* list, |
unsigned offset, |
unsigned old_length, |
unsigned new_length) { |
+ // Find first marker that ends after the start of the region being edited. |
+ // Markers before this one can be left untouched. This saves us some time over |
+ // scanning the entire list linearly if the edit region is near the end of the |
+ // text node. |
+ const MarkerList::iterator& shift_range_begin = |
+ std::upper_bound(list->begin(), list->end(), offset, |
+ [](size_t offset, const Member<DocumentMarker>& marker) { |
+ return offset < marker->EndOffset(); |
+ }); |
+ |
+ MarkerList::iterator erase_range_begin = list->end(); |
+ MarkerList::iterator erase_range_end = list->end(); |
+ |
bool did_shift_marker = false; |
- for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) { |
+ for (MarkerList::iterator it = shift_range_begin; it != list->end(); ++it) { |
DocumentMarker& marker = **it; |
Optional<DocumentMarker::MarkerOffsets> result = |
marker.ComputeOffsetsAfterShift(offset, old_length, new_length); |
if (result == WTF::nullopt) { |
- list->erase(it - list->begin()); |
- --it; |
+ if (erase_range_begin == list->end()) |
+ erase_range_begin = it; |
+ erase_range_end = std::next(it); |
did_shift_marker = true; |
continue; |
} |
@@ -130,6 +152,8 @@ bool DocumentMarkerListEditor::ShiftMarkersContentIndependent( |
} |
} |
+ list->erase(erase_range_begin - list->begin(), |
+ erase_range_end - erase_range_begin); |
return did_shift_marker; |
} |