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

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 Created 3 years, 9 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
« no previous file with comments | « third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 403 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 // cause the node to be redrawn 721 // cause the node to be redrawn
730 if (LayoutObject* layoutObject = node->layoutObject()) { 722 if (LayoutObject* layoutObject = node->layoutObject()) {
731 layoutObject->setShouldDoFullPaintInvalidation( 723 layoutObject->setShouldDoFullPaintInvalidation(
732 PaintInvalidationDocumentMarkerChange); 724 PaintInvalidationDocumentMarkerChange);
733 break; 725 break;
734 } 726 }
735 } 727 }
736 } 728 }
737 } 729 }
738 730
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, 731 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
781 bool active) { 732 bool active) {
782 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 733 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
783 return false; 734 return false;
784 735
785 DCHECK(!m_markers.isEmpty()); 736 DCHECK(!m_markers.isEmpty());
786 737
787 Node* const startContainer = range.startPosition().computeContainerNode(); 738 Node* const startContainer = range.startPosition().computeContainerNode();
788 DCHECK(startContainer); 739 DCHECK(startContainer);
789 Node* const endContainer = range.endPosition().computeContainerNode(); 740 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" 820 LOG(INFO) << m_markers.size() << " nodes have markers:\n"
870 << builder.toString().utf8().data(); 821 << builder.toString().utf8().data();
871 } 822 }
872 #endif 823 #endif
873 824
874 // SynchronousMutationObserver 825 // SynchronousMutationObserver
875 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, 826 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
876 unsigned offset, 827 unsigned offset,
877 unsigned oldLength, 828 unsigned oldLength,
878 unsigned newLength) { 829 unsigned newLength) {
879 // Shift markers as if we first remove the old text, then insert the new text 830 // If we're doing a pure remove operation, remove the markers in the range
880 removeMarkers(node, offset, oldLength); 831 // being removed (markers containing, but larger than, the range, will be
881 shiftMarkers(node, offset + oldLength, 0 - oldLength); 832 // split)
882 shiftMarkers(node, offset, newLength); 833 if (newLength == 0)
834 removeMarkers(node, offset, oldLength);
835
836 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
837 return;
838 DCHECK(!m_markers.isEmpty());
839
840 MarkerLists* markers = m_markers.at(node);
841 if (!markers)
842 return;
843
844 bool didShiftMarker = false;
845 for (MarkerList* list : *markers) {
846 if (!list)
847 continue;
848
849 for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) {
850 RenderedDocumentMarker& marker = **it;
851 // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace
852 // but with some changes
853 if (marker.startOffset() > offset) {
yosin_UTC9 2017/03/23 04:10:26 It is nice if we can move this logic into function
854 // Deviation from the concept-cd-replace algorithm: < instead of <= in
855 // the next line
856 if (marker.startOffset() < offset + oldLength) {
857 // Marker start was in the replaced text. Move to end of new text
858 // (Deviation from the concept-cd-replace algorithm: that algorithm
859 // would move to the beginning of the new text here)
860 marker.setStartOffset(offset + newLength);
861 } else {
862 // Marker start was after the replaced text. Shift by length
863 // difference
864 unsigned oldStartOffset = marker.startOffset();
865 marker.setStartOffset(oldStartOffset + newLength - oldLength);
866 }
867 didShiftMarker = true;
868 }
869
870 if (marker.endOffset() > offset) {
871 // Deviation from the concept-cd-replace algorithm: < instead of <= in
872 // the next line
873 if (marker.endOffset() < offset + oldLength) {
874 // Marker end was in the replaced text. Move to beginning of new text
875 marker.setEndOffset(offset);
876 } else {
877 // Marker end was after the replaced text. Shift by length difference
878 unsigned oldEndOffset = marker.endOffset();
879 marker.setEndOffset(oldEndOffset + newLength - oldLength);
880 }
881 didShiftMarker = true;
882 }
883
884 if (marker.startOffset() < marker.endOffset())
885 continue;
886 list->remove(it - list->begin());
887 --it;
888 }
889 }
890
891 if (!didShiftMarker)
892 return;
893 if (!node->layoutObject())
894 return;
895 invalidateRectsForMarkersInNode(*node);
896 // repaint the affected node
897 node->layoutObject()->setShouldDoFullPaintInvalidation();
883 } 898 }
884 899
885 } // namespace blink 900 } // namespace blink
886 901
887 #ifndef NDEBUG 902 #ifndef NDEBUG
888 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { 903 void showDocumentMarkers(const blink::DocumentMarkerController* controller) {
889 if (controller) 904 if (controller)
890 controller->showMarkers(); 905 controller->showMarkers();
891 } 906 }
892 #endif 907 #endif
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698