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

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

Issue 2692093003: Rewrite DocumentMarkerController to use SynchronousMutationObserver (Closed)
Patch Set: Fx tests to match current behavior of master 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 return DocumentMarker::SpellingMarkerIndex; 75 return DocumentMarker::SpellingMarkerIndex;
76 } 76 }
77 77
78 } // namespace 78 } // namespace
79 79
80 inline bool DocumentMarkerController::possiblyHasMarkers( 80 inline bool DocumentMarkerController::possiblyHasMarkers(
81 DocumentMarker::MarkerTypes types) { 81 DocumentMarker::MarkerTypes types) {
82 return m_possiblyExistingMarkerTypes.intersects(types); 82 return m_possiblyExistingMarkerTypes.intersects(types);
83 } 83 }
84 84
85 DocumentMarkerController::DocumentMarkerController(const Document& document) 85 DocumentMarkerController::DocumentMarkerController(Document& document)
86 : m_possiblyExistingMarkerTypes(0), m_document(&document) {} 86 : m_possiblyExistingMarkerTypes(0), m_document(&document) {
87 setContext(&document);
88 }
87 89
88 void DocumentMarkerController::clear() { 90 void DocumentMarkerController::clear() {
89 m_markers.clear(); 91 m_markers.clear();
90 m_possiblyExistingMarkerTypes = 0; 92 m_possiblyExistingMarkerTypes = 0;
91 } 93 }
92 94
93 void DocumentMarkerController::addMarker(const Position& start, 95 void DocumentMarkerController::addMarker(const Position& start,
94 const Position& end, 96 const Position& end,
95 DocumentMarker::MarkerType type, 97 DocumentMarker::MarkerType type,
96 const String& description) { 98 const String& description) {
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 TextIterator markedText(range.startPosition(), range.endPosition()); 170 TextIterator markedText(range.startPosition(), range.endPosition());
169 DocumentMarkerController::removeMarkers( 171 DocumentMarkerController::removeMarkers(
170 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); 172 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
171 } 173 }
172 174
173 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, 175 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv,
174 const DocumentMarker* rhv) { 176 const DocumentMarker* rhv) {
175 return lhv->startOffset() < rhv->startOffset(); 177 return lhv->startOffset() < rhv->startOffset();
176 } 178 }
177 179
178 static bool startsAfter(const Member<RenderedDocumentMarker>& marker,
179 size_t startOffset) {
180 return marker->startOffset() < startOffset;
181 }
182
183 static bool endsBefore(size_t startOffset, 180 static bool endsBefore(size_t startOffset,
184 const Member<RenderedDocumentMarker>& rhv) { 181 const Member<RenderedDocumentMarker>& rhv) {
185 return startOffset < rhv->endOffset(); 182 return startOffset < rhv->endOffset();
186 } 183 }
187 184
188 static bool compareByStart(const Member<DocumentMarker>& lhv, 185 static bool compareByStart(const Member<DocumentMarker>& lhv,
189 const Member<DocumentMarker>& rhv) { 186 const Member<DocumentMarker>& rhv) {
190 return lhv->startOffset() < rhv->startOffset(); 187 return lhv->startOffset() < rhv->startOffset();
191 } 188 }
192 189
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 295
299 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 296 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
300 return; 297 return;
301 DCHECK(!m_markers.isEmpty()); 298 DCHECK(!m_markers.isEmpty());
302 299
303 MarkerLists* markers = m_markers.at(srcNode); 300 MarkerLists* markers = m_markers.at(srcNode);
304 if (!markers) 301 if (!markers)
305 return; 302 return;
306 303
307 bool docDirty = false; 304 bool docDirty = false;
308 for (size_t markerListIndex = 0; 305 for (Member<MarkerList> list : *markers) {
309 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
310 ++markerListIndex) {
311 Member<MarkerList>& list = (*markers)[markerListIndex];
312 if (!list) 306 if (!list)
313 continue; 307 continue;
314 308
315 unsigned endOffset = startOffset + length - 1; 309 unsigned endOffset = startOffset + length - 1;
316 MarkerList::iterator startPos = std::lower_bound( 310 MarkerList::iterator startPos = std::lower_bound(
317 list->begin(), list->end(), startOffset, doesNotInclude); 311 list->begin(), list->end(), startOffset, doesNotInclude);
318 for (MarkerList::iterator i = startPos; i != list->end(); ++i) { 312 for (MarkerList::iterator i = startPos; i != list->end(); ++i) {
319 DocumentMarker* marker = i->get(); 313 DocumentMarker* marker = i->get();
320 314
321 // stop if we are now past the specified range 315 // stop if we are now past the specified range
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 572
579 if (markerList->front()->type() == DocumentMarker::TextMatch) 573 if (markerList->front()->type() == DocumentMarker::TextMatch)
580 invalidatePaintForTickmarks(node); 574 invalidatePaintForTickmarks(node);
581 } 575 }
582 } 576 }
583 } 577 }
584 578
585 DEFINE_TRACE(DocumentMarkerController) { 579 DEFINE_TRACE(DocumentMarkerController) {
586 visitor->trace(m_markers); 580 visitor->trace(m_markers);
587 visitor->trace(m_document); 581 visitor->trace(m_document);
582 SynchronousMutationObserver::trace(visitor);
588 } 583 }
589 584
590 void DocumentMarkerController::removeMarkers( 585 void DocumentMarkerController::removeMarkers(
591 Node* node, 586 Node* node,
592 DocumentMarker::MarkerTypes markerTypes) { 587 DocumentMarker::MarkerTypes markerTypes) {
593 if (!possiblyHasMarkers(markerTypes)) 588 if (!possiblyHasMarkers(markerTypes))
594 return; 589 return;
595 DCHECK(!m_markers.isEmpty()); 590 DCHECK(!m_markers.isEmpty());
596 591
597 MarkerMap::iterator iterator = m_markers.find(node); 592 MarkerMap::iterator iterator = m_markers.find(node);
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
717 712
718 // cause the node to be redrawn 713 // cause the node to be redrawn
719 if (LayoutObject* layoutObject = node->layoutObject()) { 714 if (LayoutObject* layoutObject = node->layoutObject()) {
720 layoutObject->setShouldDoFullPaintInvalidation(); 715 layoutObject->setShouldDoFullPaintInvalidation();
721 break; 716 break;
722 } 717 }
723 } 718 }
724 } 719 }
725 } 720 }
726 721
727 void DocumentMarkerController::shiftMarkers(Node* node,
728 unsigned startOffset,
729 int delta) {
730 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
731 return;
732 DCHECK(!m_markers.isEmpty());
733
734 MarkerLists* markers = m_markers.at(node);
735 if (!markers)
736 return;
737
738 bool didShiftMarker = false;
739 for (size_t markerListIndex = 0;
740 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
741 ++markerListIndex) {
742 Member<MarkerList>& list = (*markers)[markerListIndex];
743 if (!list)
744 continue;
745 MarkerList::iterator startPos =
746 std::lower_bound(list->begin(), list->end(), startOffset, startsAfter);
747 for (MarkerList::iterator marker = startPos; marker != list->end();
748 ++marker) {
749 #if DCHECK_IS_ON()
750 int startOffset = (*marker)->startOffset();
751 DCHECK_GE(startOffset + delta, 0);
752 #endif
753 (*marker)->shiftOffsets(delta);
754 didShiftMarker = true;
755 }
756 }
757
758 if (didShiftMarker) {
759 invalidateRectsForMarkersInNode(*node);
760 // repaint the affected node
761 if (node->layoutObject())
762 node->layoutObject()->setShouldDoFullPaintInvalidation();
763 }
764 }
765
766 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, 722 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
767 bool active) { 723 bool active) {
768 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 724 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
769 return false; 725 return false;
770 726
771 DCHECK(!m_markers.isEmpty()); 727 DCHECK(!m_markers.isEmpty());
772 728
773 Node* const startContainer = range.startPosition().computeContainerNode(); 729 Node* const startContainer = range.startPosition().computeContainerNode();
774 DCHECK(startContainer); 730 DCHECK(startContainer);
775 Node* const endContainer = range.endPosition().computeContainerNode(); 731 Node* const endContainer = range.endPosition().computeContainerNode();
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 builder.append(")"); 804 builder.append(")");
849 } 805 }
850 } 806 }
851 builder.append("\n"); 807 builder.append("\n");
852 } 808 }
853 LOG(INFO) << m_markers.size() << " nodes have markers:\n" 809 LOG(INFO) << m_markers.size() << " nodes have markers:\n"
854 << builder.toString().utf8().data(); 810 << builder.toString().utf8().data();
855 } 811 }
856 #endif 812 #endif
857 813
814 // SynchronousMutationObserver
815 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
816 unsigned offset,
817 unsigned oldLength,
818 unsigned newLength) {
819 // If we're doing a pure remove operation, remove the markers in the range
820 // being removed (markers containing, but larger than, the range, will be
821 // split)
822 if (newLength == 0)
823 removeMarkers(node, offset, oldLength);
824
825 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
826 return;
827 DCHECK(!m_markers.isEmpty());
828
829 MarkerLists* markers = m_markers.at(node);
830 if (!markers)
831 return;
832
833 bool didShiftMarker = false;
834 for (MarkerList* list : *markers) {
835 if (!list)
836 continue;
837
838 for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) {
839 RenderedDocumentMarker& marker = **it;
840 // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace
841 // but with some changes
842 if (marker.startOffset() > offset) {
843 // Deviation from the concept-cd-replace algorithm: < instead of <= in
844 // the next line
845 if (marker.startOffset() < offset + oldLength) {
846 // Marker start was in the replaced text. Move to end of new text
847 // (Deviation from the concept-cd-replace algorithm: that algorithm
848 // would move to the beginning of the new text here)
849 marker.setStartOffset(offset + newLength);
850 } else {
851 // Marker start was after the replaced text. Shift by length
852 // difference
853 unsigned oldStartOffset = marker.startOffset();
854 marker.setStartOffset(oldStartOffset + newLength - oldLength);
855 }
856 didShiftMarker = true;
857 }
858
859 if (marker.endOffset() > offset) {
860 // Deviation from the concept-cd-replace algorithm: < instead of <= in
861 // the next line
862 if (marker.endOffset() < offset + oldLength) {
863 // Marker end was in the replaced text. Move to beginning of new text
864 marker.setEndOffset(offset);
865 } else {
866 // Marker end was after the replaced text. Shift by length difference
867 unsigned oldEndOffset = marker.endOffset();
868 marker.setEndOffset(oldEndOffset + newLength - oldLength);
869 }
870 didShiftMarker = true;
871 }
872
873 if (marker.startOffset() < marker.endOffset())
874 continue;
875 list->remove(it - list->begin());
876 --it;
877 }
878 }
879
880 if (!didShiftMarker)
881 return;
882 if (!node->layoutObject())
883 return;
884 invalidateRectsForMarkersInNode(*node);
885 // repaint the affected node
886 node->layoutObject()->setShouldDoFullPaintInvalidation();
887 }
888
858 } // namespace blink 889 } // namespace blink
859 890
860 #ifndef NDEBUG 891 #ifndef NDEBUG
861 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { 892 void showDocumentMarkers(const blink::DocumentMarkerController* controller) {
862 if (controller) 893 if (controller)
863 controller->showMarkers(); 894 controller->showMarkers();
864 } 895 }
865 #endif 896 #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