Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp

Issue 2755013004: Improve how DocumentMarkerController updates markers in response to text edits (Closed)
Patch Set: Rebase (Vector::remove() => Vector::erase()) Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org) 5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights
7 * reserved. 7 * reserved.
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/) 9 * (http://www.torchmobile.com/)
10 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 10 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 TextIterator markedText(range.startPosition(), range.endPosition()); 170 TextIterator markedText(range.startPosition(), range.endPosition());
171 DocumentMarkerController::removeMarkers( 171 DocumentMarkerController::removeMarkers(
172 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); 172 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
173 } 173 }
174 174
175 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, 175 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv,
176 const DocumentMarker* rhv) { 176 const DocumentMarker* rhv) {
177 return lhv->startOffset() < rhv->startOffset(); 177 return lhv->startOffset() < rhv->startOffset();
178 } 178 }
179 179
180 static bool startsAfter(const Member<RenderedDocumentMarker>& marker,
181 size_t startOffset) {
182 return marker->startOffset() < startOffset;
183 }
184
185 static bool endsBefore(size_t startOffset, 180 static bool endsBefore(size_t startOffset,
186 const Member<RenderedDocumentMarker>& rhv) { 181 const Member<RenderedDocumentMarker>& rhv) {
187 return startOffset < rhv->endOffset(); 182 return startOffset < rhv->endOffset();
188 } 183 }
189 184
190 static bool compareByStart(const Member<DocumentMarker>& lhv, 185 static bool compareByStart(const Member<DocumentMarker>& lhv,
191 const Member<DocumentMarker>& rhv) { 186 const Member<DocumentMarker>& rhv) {
192 return lhv->startOffset() < rhv->startOffset(); 187 return lhv->startOffset() < rhv->startOffset();
193 } 188 }
194 189
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 297
303 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 298 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
304 return; 299 return;
305 DCHECK(!m_markers.isEmpty()); 300 DCHECK(!m_markers.isEmpty());
306 301
307 MarkerLists* markers = m_markers.at(srcNode); 302 MarkerLists* markers = m_markers.at(srcNode);
308 if (!markers) 303 if (!markers)
309 return; 304 return;
310 305
311 bool docDirty = false; 306 bool docDirty = false;
312 for (size_t markerListIndex = 0; 307 for (Member<MarkerList> list : *markers) {
313 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
314 ++markerListIndex) {
315 Member<MarkerList>& list = (*markers)[markerListIndex];
316 if (!list) 308 if (!list)
317 continue; 309 continue;
318 310
319 unsigned endOffset = startOffset + length - 1; 311 unsigned endOffset = startOffset + length - 1;
320 MarkerList::iterator startPos = std::lower_bound( 312 MarkerList::iterator startPos = std::lower_bound(
321 list->begin(), list->end(), startOffset, doesNotInclude); 313 list->begin(), list->end(), startOffset, doesNotInclude);
322 for (MarkerList::iterator i = startPos; i != list->end(); ++i) { 314 for (MarkerList::iterator i = startPos; i != list->end(); ++i) {
323 DocumentMarker* marker = i->get(); 315 DocumentMarker* marker = i->get();
324 316
325 // stop if we are now past the specified range 317 // stop if we are now past the specified range
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 unsigned size = nodesWithMarkers.size(); 639 unsigned size = nodesWithMarkers.size();
648 for (unsigned i = 0; i < size; ++i) { 640 for (unsigned i = 0; i < size; ++i) {
649 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]); 641 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]);
650 if (iterator != m_markers.end()) 642 if (iterator != m_markers.end())
651 removeMarkersFromList(iterator, markerTypes); 643 removeMarkersFromList(iterator, markerTypes);
652 } 644 }
653 645
654 m_possiblyExistingMarkerTypes.remove(markerTypes); 646 m_possiblyExistingMarkerTypes.remove(markerTypes);
655 } 647 }
656 648
649 bool DocumentMarkerController::relocateMarkerIfNeeded(
Xiaocheng 2017/03/29 18:35:19 Can we implement this function directly in Documen
650 RenderedDocumentMarker* marker,
651 unsigned offset,
652 unsigned oldLength,
653 unsigned newLength) {
654 bool didShiftMarker = false;
655
656 // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace
657 // but with some changes
658
659 // Deviation from the concept-cd-replace algorithm: second condition in the
660 // next line (don't include text inserted immediately before a marker in the
661 // marked range, but do include the new text if it's replacing text in the
662 // marked range)
663 if (marker->startOffset() > offset ||
664 (marker->startOffset() == offset && oldLength == 0)) {
665 if (marker->startOffset() <= offset + oldLength) {
666 // Marker start was in the replaced text. Move to end of new text
667 // (Deviation from the concept-cd-replace algorithm: that algorithm
668 // would move to the beginning of the new text here)
669 marker->setStartOffset(offset + newLength);
670 } else {
671 // Marker start was after the replaced text. Shift by length
672 // difference
673 unsigned oldStartOffset = marker->startOffset();
674 marker->setStartOffset(oldStartOffset + newLength - oldLength);
675 }
676 didShiftMarker = true;
677 }
678
679 if (marker->endOffset() > offset) {
680 // Deviation from the concept-cd-replace algorithm: < instead of <= in
681 // the next line
682 if (marker->endOffset() < offset + oldLength) {
683 // Marker end was in the replaced text. Move to beginning of new text
684 marker->setEndOffset(offset);
685 } else {
686 // Marker end was after the replaced text. Shift by length difference
687 unsigned oldEndOffset = marker->endOffset();
688 marker->setEndOffset(oldEndOffset + newLength - oldLength);
689 }
690 didShiftMarker = true;
691 }
692
693 return didShiftMarker;
694 }
695
657 void DocumentMarkerController::removeMarkersFromList( 696 void DocumentMarkerController::removeMarkersFromList(
658 MarkerMap::iterator iterator, 697 MarkerMap::iterator iterator,
659 DocumentMarker::MarkerTypes markerTypes) { 698 DocumentMarker::MarkerTypes markerTypes) {
660 bool needsRepainting = false; 699 bool needsRepainting = false;
661 bool nodeCanBeRemoved; 700 bool nodeCanBeRemoved;
662 701
663 size_t emptyListsCount = 0; 702 size_t emptyListsCount = 0;
664 if (markerTypes == DocumentMarker::AllMarkers()) { 703 if (markerTypes == DocumentMarker::AllMarkers()) {
665 needsRepainting = true; 704 needsRepainting = true;
666 nodeCanBeRemoved = true; 705 nodeCanBeRemoved = true;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 // cause the node to be redrawn 768 // cause the node to be redrawn
730 if (LayoutObject* layoutObject = node->layoutObject()) { 769 if (LayoutObject* layoutObject = node->layoutObject()) {
731 layoutObject->setShouldDoFullPaintInvalidation( 770 layoutObject->setShouldDoFullPaintInvalidation(
732 PaintInvalidationDocumentMarkerChange); 771 PaintInvalidationDocumentMarkerChange);
733 break; 772 break;
734 } 773 }
735 } 774 }
736 } 775 }
737 } 776 }
738 777
739 void DocumentMarkerController::shiftMarkers(Node* node,
740 unsigned startOffset,
741 int delta) {
742 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
743 return;
744 DCHECK(!m_markers.isEmpty());
745
746 MarkerLists* markers = m_markers.at(node);
747 if (!markers)
748 return;
749
750 bool didShiftMarker = false;
751 for (size_t markerListIndex = 0;
752 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
753 ++markerListIndex) {
754 Member<MarkerList>& list = (*markers)[markerListIndex];
755 if (!list)
756 continue;
757 MarkerList::iterator startPos =
758 std::lower_bound(list->begin(), list->end(), startOffset, startsAfter);
759 for (MarkerList::iterator marker = startPos; marker != list->end();
760 ++marker) {
761 #if DCHECK_IS_ON()
762 int startOffset = (*marker)->startOffset();
763 DCHECK_GE(startOffset + delta, 0);
764 #endif
765 (*marker)->shiftOffsets(delta);
766 didShiftMarker = true;
767 }
768 }
769
770 if (didShiftMarker) {
771 invalidateRectsForMarkersInNode(*node);
772 // repaint the affected node
773 if (node->layoutObject()) {
774 node->layoutObject()->setShouldDoFullPaintInvalidation(
775 PaintInvalidationDocumentMarkerChange);
776 }
777 }
778 }
779
780 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, 778 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
781 bool active) { 779 bool active) {
782 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 780 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
783 return false; 781 return false;
784 782
785 DCHECK(!m_markers.isEmpty()); 783 DCHECK(!m_markers.isEmpty());
786 784
787 Node* const startContainer = range.startPosition().computeContainerNode(); 785 Node* const startContainer = range.startPosition().computeContainerNode();
788 DCHECK(startContainer); 786 DCHECK(startContainer);
789 Node* const endContainer = range.endPosition().computeContainerNode(); 787 Node* const endContainer = range.endPosition().computeContainerNode();
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
869 LOG(INFO) << m_markers.size() << " nodes have markers:\n" 867 LOG(INFO) << m_markers.size() << " nodes have markers:\n"
870 << builder.toString().utf8().data(); 868 << builder.toString().utf8().data();
871 } 869 }
872 #endif 870 #endif
873 871
874 // SynchronousMutationObserver 872 // SynchronousMutationObserver
875 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, 873 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
876 unsigned offset, 874 unsigned offset,
877 unsigned oldLength, 875 unsigned oldLength,
878 unsigned newLength) { 876 unsigned newLength) {
879 // Shift markers as if we first remove the old text, then insert the new text 877 // If we're doing a pure remove operation, remove the markers in the range
880 removeMarkers(node, offset, oldLength); 878 // being removed (markers containing, but larger than, the range, will be
881 shiftMarkers(node, offset + oldLength, 0 - oldLength); 879 // split)
882 shiftMarkers(node, offset, newLength); 880 if (newLength == 0)
881 removeMarkers(node, offset, oldLength);
882
883 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
884 return;
885 DCHECK(!m_markers.isEmpty());
886
887 MarkerLists* markers = m_markers.at(node);
888 if (!markers)
889 return;
890
891 bool didShiftMarker = false;
892 for (MarkerList* list : *markers) {
893 if (!list)
894 continue;
895
896 for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) {
897 RenderedDocumentMarker& marker = **it;
898 if (relocateMarkerIfNeeded(&marker, offset, oldLength, newLength)) {
899 didShiftMarker = true;
900
901 if (marker.startOffset() < marker.endOffset())
902 continue;
903 list->erase(it - list->begin());
904 --it;
905 }
906 }
907 }
908
909 if (!didShiftMarker)
910 return;
911 if (!node->layoutObject())
912 return;
913 invalidateRectsForMarkersInNode(*node);
914 // repaint the affected node
915 node->layoutObject()->setShouldDoFullPaintInvalidation();
883 } 916 }
884 917
885 } // namespace blink 918 } // namespace blink
886 919
887 #ifndef NDEBUG 920 #ifndef NDEBUG
888 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { 921 void showDocumentMarkers(const blink::DocumentMarkerController* controller) {
889 if (controller) 922 if (controller)
890 controller->showMarkers(); 923 controller->showMarkers();
891 } 924 }
892 #endif 925 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698