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

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

Issue 2692093003: Rewrite DocumentMarkerController to use SynchronousMutationObserver (Closed)
Patch Set: Introduce SetCharacterDataCommand Created 3 years, 10 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 return DocumentMarker::SpellingMarkerIndex; 77 return DocumentMarker::SpellingMarkerIndex;
78 } 78 }
79 79
80 } // namespace 80 } // namespace
81 81
82 inline bool DocumentMarkerController::possiblyHasMarkers( 82 inline bool DocumentMarkerController::possiblyHasMarkers(
83 DocumentMarker::MarkerTypes types) { 83 DocumentMarker::MarkerTypes types) {
84 return m_possiblyExistingMarkerTypes.intersects(types); 84 return m_possiblyExistingMarkerTypes.intersects(types);
85 } 85 }
86 86
87 DocumentMarkerController::DocumentMarkerController(const Document& document) 87 DocumentMarkerController::DocumentMarkerController(Document& document)
88 : m_possiblyExistingMarkerTypes(0), m_document(&document) {} 88 : m_possiblyExistingMarkerTypes(0), m_document(&document) {
89 setContext(&document);
90 }
89 91
90 void DocumentMarkerController::clear() { 92 void DocumentMarkerController::clear() {
91 m_markers.clear(); 93 m_markers.clear();
92 m_possiblyExistingMarkerTypes = 0; 94 m_possiblyExistingMarkerTypes = 0;
93 } 95 }
94 96
95 void DocumentMarkerController::addMarker(const Position& start, 97 void DocumentMarkerController::addMarker(const Position& start,
96 const Position& end, 98 const Position& end,
97 DocumentMarker::MarkerType type, 99 DocumentMarker::MarkerType type,
98 const String& description, 100 const String& description,
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 TextIterator markedText(range.startPosition(), range.endPosition()); 173 TextIterator markedText(range.startPosition(), range.endPosition());
172 DocumentMarkerController::removeMarkers( 174 DocumentMarkerController::removeMarkers(
173 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); 175 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
174 } 176 }
175 177
176 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, 178 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv,
177 const DocumentMarker* rhv) { 179 const DocumentMarker* rhv) {
178 return lhv->startOffset() < rhv->startOffset(); 180 return lhv->startOffset() < rhv->startOffset();
179 } 181 }
180 182
181 static bool startsAfter(const Member<RenderedDocumentMarker>& marker,
182 size_t startOffset) {
183 return marker->startOffset() < startOffset;
184 }
185
186 static bool endsBefore(size_t startOffset, 183 static bool endsBefore(size_t startOffset,
187 const Member<RenderedDocumentMarker>& rhv) { 184 const Member<RenderedDocumentMarker>& rhv) {
188 return startOffset < rhv->endOffset(); 185 return startOffset < rhv->endOffset();
189 } 186 }
190 187
191 static bool compareByStart(const Member<DocumentMarker>& lhv, 188 static bool compareByStart(const Member<DocumentMarker>& lhv,
192 const Member<DocumentMarker>& rhv) { 189 const Member<DocumentMarker>& rhv) {
193 return lhv->startOffset() < rhv->startOffset(); 190 return lhv->startOffset() < rhv->startOffset();
194 } 191 }
195 192
(...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 578
582 if (markerList->front()->type() == DocumentMarker::TextMatch) 579 if (markerList->front()->type() == DocumentMarker::TextMatch)
583 invalidatePaintForTickmarks(node); 580 invalidatePaintForTickmarks(node);
584 } 581 }
585 } 582 }
586 } 583 }
587 584
588 DEFINE_TRACE(DocumentMarkerController) { 585 DEFINE_TRACE(DocumentMarkerController) {
589 visitor->trace(m_markers); 586 visitor->trace(m_markers);
590 visitor->trace(m_document); 587 visitor->trace(m_document);
588 SynchronousMutationObserver::trace(visitor);
591 } 589 }
592 590
593 void DocumentMarkerController::removeMarkers( 591 void DocumentMarkerController::removeMarkers(
594 Node* node, 592 Node* node,
595 DocumentMarker::MarkerTypes markerTypes) { 593 DocumentMarker::MarkerTypes markerTypes) {
596 if (!possiblyHasMarkers(markerTypes)) 594 if (!possiblyHasMarkers(markerTypes))
597 return; 595 return;
598 DCHECK(!m_markers.isEmpty()); 596 DCHECK(!m_markers.isEmpty());
599 597
600 MarkerMap::iterator iterator = m_markers.find(node); 598 MarkerMap::iterator iterator = m_markers.find(node);
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
690 invalidatePaintForTickmarks(node); 688 invalidatePaintForTickmarks(node);
691 } 689 }
692 690
693 if (nodeCanBeRemoved) { 691 if (nodeCanBeRemoved) {
694 m_markers.remove(iterator); 692 m_markers.remove(iterator);
695 if (m_markers.isEmpty()) 693 if (m_markers.isEmpty())
696 m_possiblyExistingMarkerTypes = 0; 694 m_possiblyExistingMarkerTypes = 0;
697 } 695 }
698 } 696 }
699 697
698 void DocumentMarkerController::removeZeroLengthMarkers() {
699 for (auto& nodeMarkers : m_markers) {
700 const Node& node = *nodeMarkers.key;
701 MarkerLists& markers = *nodeMarkers.value;
702 for (size_t markerListIndex = 0;
703 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
704 ++markerListIndex) {
705 Member<MarkerList>& list = markers[markerListIndex];
yosin_UTC9 2017/02/20 07:26:27 nit: s/&//
706 if (!list)
707 continue;
708 bool removedMarkers = false;
709 for (size_t j = list->size(); j > 0; --j) {
710 if (list->at(j - 1)->startOffset() == list->at(j - 1)->endOffset()) {
711 list->remove(j - 1);
712 removedMarkers = true;
713 }
714 }
715 if (removedMarkers &&
yosin_UTC9 2017/02/20 07:26:27 We prefer early-return-style. if (!removeMarkers)
716 markerListIndex == DocumentMarker::TextMatchMarkerIndex)
717 invalidatePaintForTickmarks(node);
718 }
719 }
720 }
721
700 void DocumentMarkerController::repaintMarkers( 722 void DocumentMarkerController::repaintMarkers(
701 DocumentMarker::MarkerTypes markerTypes) { 723 DocumentMarker::MarkerTypes markerTypes) {
702 if (!possiblyHasMarkers(markerTypes)) 724 if (!possiblyHasMarkers(markerTypes))
703 return; 725 return;
704 DCHECK(!m_markers.isEmpty()); 726 DCHECK(!m_markers.isEmpty());
705 727
706 // outer loop: process each markered node in the document 728 // outer loop: process each markered node in the document
707 MarkerMap::iterator end = m_markers.end(); 729 MarkerMap::iterator end = m_markers.end();
708 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { 730 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
709 const Node* node = i->key; 731 const Node* node = i->key;
(...skipping 10 matching lines...) Expand all
720 742
721 // cause the node to be redrawn 743 // cause the node to be redrawn
722 if (LayoutObject* layoutObject = node->layoutObject()) { 744 if (LayoutObject* layoutObject = node->layoutObject()) {
723 layoutObject->setShouldDoFullPaintInvalidation(); 745 layoutObject->setShouldDoFullPaintInvalidation();
724 break; 746 break;
725 } 747 }
726 } 748 }
727 } 749 }
728 } 750 }
729 751
730 void DocumentMarkerController::shiftMarkers(Node* node,
731 unsigned startOffset,
732 int delta) {
733 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
734 return;
735 DCHECK(!m_markers.isEmpty());
736
737 MarkerLists* markers = m_markers.get(node);
738 if (!markers)
739 return;
740
741 bool didShiftMarker = false;
742 for (size_t markerListIndex = 0;
743 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
744 ++markerListIndex) {
745 Member<MarkerList>& list = (*markers)[markerListIndex];
746 if (!list)
747 continue;
748 MarkerList::iterator startPos =
749 std::lower_bound(list->begin(), list->end(), startOffset, startsAfter);
750 for (MarkerList::iterator marker = startPos; marker != list->end();
751 ++marker) {
752 #if DCHECK_IS_ON()
753 int startOffset = (*marker)->startOffset();
754 DCHECK_GE(startOffset + delta, 0);
755 #endif
756 (*marker)->shiftOffsets(delta);
757 didShiftMarker = true;
758 }
759 }
760
761 if (didShiftMarker) {
762 invalidateRectsForMarkersInNode(*node);
763 // repaint the affected node
764 if (node->layoutObject())
765 node->layoutObject()->setShouldDoFullPaintInvalidation();
766 }
767 }
768
769 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, 752 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
770 bool active) { 753 bool active) {
771 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 754 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
772 return false; 755 return false;
773 756
774 DCHECK(!m_markers.isEmpty()); 757 DCHECK(!m_markers.isEmpty());
775 758
776 Node* const startContainer = range.startPosition().computeContainerNode(); 759 Node* const startContainer = range.startPosition().computeContainerNode();
777 DCHECK(startContainer); 760 DCHECK(startContainer);
778 Node* const endContainer = range.endPosition().computeContainerNode(); 761 Node* const endContainer = range.endPosition().computeContainerNode();
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 builder.append(")"); 834 builder.append(")");
852 } 835 }
853 } 836 }
854 builder.append("\n"); 837 builder.append("\n");
855 } 838 }
856 LOG(INFO) << m_markers.size() << " nodes have markers:\n" 839 LOG(INFO) << m_markers.size() << " nodes have markers:\n"
857 << builder.toString().utf8().data(); 840 << builder.toString().utf8().data();
858 } 841 }
859 #endif 842 #endif
860 843
844 // SynchronousMutationObserver
845 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
846 unsigned offset,
847 unsigned oldLength,
848 unsigned newLength) {
849 // If we're doing a pure remove operation, remove the markers in the range
850 // being removed (markers containing, but larger than, the range, will be
851 // split)
852 if (newLength == 0) {
yosin_UTC9 2017/02/20 07:26:27 nit: no need to have "{}"
853 removeMarkers(node, offset, oldLength);
854 }
855
856 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
857 return;
858 DCHECK(!m_markers.isEmpty());
859
860 MarkerLists* markers = m_markers.get(node);
861 if (!markers)
862 return;
863
864 bool didShiftMarker = false;
865 for (size_t markerListIndex = 0;
866 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
867 ++markerListIndex) {
868 Member<MarkerList>& list = (*markers)[markerListIndex];
yosin_UTC9 2017/02/20 07:26:27 nit: s/&//
869 if (!list)
870 continue;
871
872 for (MarkerList::iterator marker = list->begin(); marker != list->end();
873 ++marker) {
874 // if marker is contained by but not equal to the replaced range, remove
875 // the marker
876 if ((offset <= (*marker)->startOffset() &&
877 (*marker)->endOffset() < offset + oldLength) ||
878 (offset < (*marker)->startOffset() &&
879 (*marker)->endOffset() <= offset + oldLength)) {
880 list->remove(marker - list->begin());
881 marker--;
882 continue;
883 }
884
885 // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace
886 // but with some changes
887 if ((*marker)->startOffset() > offset) {
888 // Deviation from the concept-cd-replace algorithm: < instead of <= in
889 // the next line
890 if ((*marker)->startOffset() < offset + oldLength) {
891 // Marker start was in the replaced text. Move to beginning of new
892 // text
893 (*marker)->setStartOffset(offset);
894 } else {
895 // Marker start was after the replaced text. Shift by length
896 // difference
897 unsigned oldStartOffset = (*marker)->startOffset();
898 (*marker)->setStartOffset(oldStartOffset + newLength - oldLength);
899 }
900 }
901
902 if ((*marker)->endOffset() > offset) {
903 // Deviation from the concept-cd-replace algorithm: < instead of <= in
904 // the next line
905 if ((*marker)->endOffset() < offset + oldLength) {
906 // Marker end was in the replaced text. Move to beginning of new text
907 (*marker)->setEndOffset(offset);
908 } else {
909 // Marker end was after the replaced text. Shift by length difference
910 unsigned oldEndOffset = (*marker)->endOffset();
911 (*marker)->setEndOffset(oldEndOffset + newLength - oldLength);
912 }
913 }
914
915 didShiftMarker = true;
916 }
917 }
918
919 if (didShiftMarker) {
920 removeZeroLengthMarkers();
921 invalidateRectsForMarkersInNode(*node);
922 // repaint the affected node
923 if (node->layoutObject())
924 node->layoutObject()->setShouldDoFullPaintInvalidation();
925 }
926 }
927
861 } // namespace blink 928 } // namespace blink
862 929
863 #ifndef NDEBUG 930 #ifndef NDEBUG
864 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { 931 void showDocumentMarkers(const blink::DocumentMarkerController* controller) {
865 if (controller) 932 if (controller)
866 controller->showMarkers(); 933 controller->showMarkers();
867 } 934 }
868 #endif 935 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698