Chromium Code Reviews| Index: third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp |
| diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp |
| index 41afe11c85185d22f509ddc551141887d1ae33c5..987f73f5546fb15ec77b757743b3060fc39a891c 100644 |
| --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp |
| +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp |
| @@ -84,8 +84,10 @@ inline bool DocumentMarkerController::possiblyHasMarkers( |
| return m_possiblyExistingMarkerTypes.intersects(types); |
| } |
| -DocumentMarkerController::DocumentMarkerController(const Document& document) |
| - : m_possiblyExistingMarkerTypes(0), m_document(&document) {} |
| +DocumentMarkerController::DocumentMarkerController(Document& document) |
| + : m_possiblyExistingMarkerTypes(0), m_document(&document) { |
| + setContext(&document); |
| +} |
| void DocumentMarkerController::clear() { |
| m_markers.clear(); |
| @@ -178,11 +180,6 @@ static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, |
| return lhv->startOffset() < rhv->startOffset(); |
| } |
| -static bool startsAfter(const Member<RenderedDocumentMarker>& marker, |
| - size_t startOffset) { |
| - return marker->startOffset() < startOffset; |
| -} |
| - |
| static bool endsBefore(size_t startOffset, |
| const Member<RenderedDocumentMarker>& rhv) { |
| return startOffset < rhv->endOffset(); |
| @@ -588,6 +585,7 @@ void DocumentMarkerController::invalidateRectsForAllMarkers() { |
| DEFINE_TRACE(DocumentMarkerController) { |
| visitor->trace(m_markers); |
| visitor->trace(m_document); |
| + SynchronousMutationObserver::trace(visitor); |
| } |
| void DocumentMarkerController::removeMarkers( |
| @@ -697,6 +695,30 @@ void DocumentMarkerController::removeMarkersFromList( |
| } |
| } |
| +void DocumentMarkerController::removeZeroLengthMarkers() { |
| + for (auto& nodeMarkers : m_markers) { |
| + const Node& node = *nodeMarkers.key; |
| + MarkerLists& markers = *nodeMarkers.value; |
| + for (size_t markerListIndex = 0; |
| + markerListIndex < DocumentMarker::MarkerTypeIndexesCount; |
| + ++markerListIndex) { |
| + Member<MarkerList>& list = markers[markerListIndex]; |
| + if (!list) |
| + continue; |
| + bool removedMarkers = false; |
| + for (size_t j = list->size(); j > 0; --j) { |
| + if (list->at(j - 1)->startOffset() == list->at(j - 1)->endOffset()) { |
| + list->remove(j - 1); |
| + removedMarkers = true; |
| + } |
| + } |
| + if (removedMarkers && |
| + markerListIndex == DocumentMarker::TextMatchMarkerIndex) |
| + invalidatePaintForTickmarks(node); |
| + } |
| + } |
| +} |
| + |
| void DocumentMarkerController::repaintMarkers( |
| DocumentMarker::MarkerTypes markerTypes) { |
| if (!possiblyHasMarkers(markerTypes)) |
| @@ -728,8 +750,20 @@ void DocumentMarkerController::repaintMarkers( |
| } |
| void DocumentMarkerController::shiftMarkers(Node* node, |
|
yosin_UTC9
2017/02/15 02:23:25
Let's make this function as didUpdateCharacterData
|
| - unsigned startOffset, |
| - int delta) { |
| + int startOffset, |
| + int prevLength, |
| + int newLength) { |
| + DCHECK_GE(startOffset, 0); |
| + DCHECK_GE(prevLength, 0); |
| + DCHECK_GE(newLength, 0); |
| + |
| + // If we're doing a pure remove operation, remove the markers in the range |
| + // being removed (markers containing, but larger than, the range, will be |
| + // split) |
| + if (newLength == 0) { |
| + removeMarkers(node, startOffset, prevLength); |
| + } |
| + |
| if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) |
| return; |
| DCHECK(!m_markers.isEmpty()); |
| @@ -745,20 +779,56 @@ void DocumentMarkerController::shiftMarkers(Node* node, |
| Member<MarkerList>& list = (*markers)[markerListIndex]; |
| if (!list) |
| continue; |
| - MarkerList::iterator startPos = |
| - std::lower_bound(list->begin(), list->end(), startOffset, startsAfter); |
| - for (MarkerList::iterator marker = startPos; marker != list->end(); |
| + |
| + for (MarkerList::iterator marker = list->begin(); marker != list->end(); |
| ++marker) { |
| -#if DCHECK_IS_ON() |
| - int startOffset = (*marker)->startOffset(); |
| - DCHECK_GE(startOffset + delta, 0); |
| -#endif |
| - (*marker)->shiftOffsets(delta); |
| + // if marker is contained by but not equal to the replaced range, remove |
| + // the marker |
| + if (((unsigned)startOffset <= (*marker)->startOffset() && |
| + (*marker)->endOffset() < (unsigned)(startOffset + prevLength)) || |
| + ((unsigned)startOffset < (*marker)->startOffset() && |
| + (*marker)->endOffset() <= (unsigned)(startOffset + prevLength))) { |
| + list->remove(marker - list->begin()); |
| + marker--; |
| + continue; |
| + } |
| + |
| + // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace |
| + // but with some changes |
| + if ((*marker)->startOffset() > (unsigned)startOffset) { |
| + // Deviation from the concept-cd-replace algorithm: < instead of <= in |
| + // the next line |
| + if ((*marker)->startOffset() < (unsigned)(startOffset + prevLength)) { |
| + // Marker start was in the replaced text. Move to beginning of new |
| + // text |
| + (*marker)->setStartOffset(startOffset); |
| + } else { |
| + // Marker start was after the replaced text. Shift by length |
| + // difference |
| + unsigned oldStartOffset = (*marker)->startOffset(); |
| + (*marker)->setStartOffset(oldStartOffset + newLength - prevLength); |
| + } |
| + } |
| + |
| + if ((*marker)->endOffset() > (unsigned)startOffset) { |
| + // Deviation from the concept-cd-replace algorithm: < instead of <= in |
| + // the next line |
| + if ((*marker)->endOffset() < (unsigned)(startOffset + prevLength)) { |
| + // Marker end was in the replaced text. Move to beginning of new text |
| + (*marker)->setEndOffset(startOffset); |
| + } else { |
| + // Marker end was after the replaced text. Shift by length difference |
| + unsigned oldEndOffset = (*marker)->endOffset(); |
| + (*marker)->setEndOffset(oldEndOffset + newLength - prevLength); |
| + } |
| + } |
| + |
| didShiftMarker = true; |
| } |
| } |
| if (didShiftMarker) { |
| + removeZeroLengthMarkers(); |
| invalidateRectsForMarkersInNode(*node); |
| // repaint the affected node |
| if (node->layoutObject()) |
| @@ -858,6 +928,14 @@ void DocumentMarkerController::showMarkers() const { |
| } |
| #endif |
| +// SynchronousMutationObserver |
| +void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, |
| + unsigned offset, |
| + unsigned oldLength, |
| + unsigned newLength) { |
| + shiftMarkers(node, offset, oldLength, newLength); |
| +} |
| + |
| } // namespace blink |
| #ifndef NDEBUG |