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

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

Issue 2692093003: Rewrite DocumentMarkerController to use SynchronousMutationObserver (Closed)
Patch Set: Don't try to use -1 as default value for unsigned int 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];
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 &&
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, 752 void DocumentMarkerController::shiftMarkers(Node* node,
yosin_UTC9 2017/02/15 02:23:25 Let's make this function as didUpdateCharacterData
731 unsigned startOffset, 753 int startOffset,
732 int delta) { 754 int prevLength,
755 int newLength) {
756 DCHECK_GE(startOffset, 0);
757 DCHECK_GE(prevLength, 0);
758 DCHECK_GE(newLength, 0);
759
760 // If we're doing a pure remove operation, remove the markers in the range
761 // being removed (markers containing, but larger than, the range, will be
762 // split)
763 if (newLength == 0) {
764 removeMarkers(node, startOffset, prevLength);
765 }
766
733 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 767 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
734 return; 768 return;
735 DCHECK(!m_markers.isEmpty()); 769 DCHECK(!m_markers.isEmpty());
736 770
737 MarkerLists* markers = m_markers.get(node); 771 MarkerLists* markers = m_markers.get(node);
738 if (!markers) 772 if (!markers)
739 return; 773 return;
740 774
741 bool didShiftMarker = false; 775 bool didShiftMarker = false;
742 for (size_t markerListIndex = 0; 776 for (size_t markerListIndex = 0;
743 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 777 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
744 ++markerListIndex) { 778 ++markerListIndex) {
745 Member<MarkerList>& list = (*markers)[markerListIndex]; 779 Member<MarkerList>& list = (*markers)[markerListIndex];
746 if (!list) 780 if (!list)
747 continue; 781 continue;
748 MarkerList::iterator startPos = 782
749 std::lower_bound(list->begin(), list->end(), startOffset, startsAfter); 783 for (MarkerList::iterator marker = list->begin(); marker != list->end();
750 for (MarkerList::iterator marker = startPos; marker != list->end();
751 ++marker) { 784 ++marker) {
752 #if DCHECK_IS_ON() 785 // if marker is contained by but not equal to the replaced range, remove
753 int startOffset = (*marker)->startOffset(); 786 // the marker
754 DCHECK_GE(startOffset + delta, 0); 787 if (((unsigned)startOffset <= (*marker)->startOffset() &&
755 #endif 788 (*marker)->endOffset() < (unsigned)(startOffset + prevLength)) ||
756 (*marker)->shiftOffsets(delta); 789 ((unsigned)startOffset < (*marker)->startOffset() &&
790 (*marker)->endOffset() <= (unsigned)(startOffset + prevLength))) {
791 list->remove(marker - list->begin());
792 marker--;
793 continue;
794 }
795
796 // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace
797 // but with some changes
798 if ((*marker)->startOffset() > (unsigned)startOffset) {
799 // Deviation from the concept-cd-replace algorithm: < instead of <= in
800 // the next line
801 if ((*marker)->startOffset() < (unsigned)(startOffset + prevLength)) {
802 // Marker start was in the replaced text. Move to beginning of new
803 // text
804 (*marker)->setStartOffset(startOffset);
805 } else {
806 // Marker start was after the replaced text. Shift by length
807 // difference
808 unsigned oldStartOffset = (*marker)->startOffset();
809 (*marker)->setStartOffset(oldStartOffset + newLength - prevLength);
810 }
811 }
812
813 if ((*marker)->endOffset() > (unsigned)startOffset) {
814 // Deviation from the concept-cd-replace algorithm: < instead of <= in
815 // the next line
816 if ((*marker)->endOffset() < (unsigned)(startOffset + prevLength)) {
817 // Marker end was in the replaced text. Move to beginning of new text
818 (*marker)->setEndOffset(startOffset);
819 } else {
820 // Marker end was after the replaced text. Shift by length difference
821 unsigned oldEndOffset = (*marker)->endOffset();
822 (*marker)->setEndOffset(oldEndOffset + newLength - prevLength);
823 }
824 }
825
757 didShiftMarker = true; 826 didShiftMarker = true;
758 } 827 }
759 } 828 }
760 829
761 if (didShiftMarker) { 830 if (didShiftMarker) {
831 removeZeroLengthMarkers();
762 invalidateRectsForMarkersInNode(*node); 832 invalidateRectsForMarkersInNode(*node);
763 // repaint the affected node 833 // repaint the affected node
764 if (node->layoutObject()) 834 if (node->layoutObject())
765 node->layoutObject()->setShouldDoFullPaintInvalidation(); 835 node->layoutObject()->setShouldDoFullPaintInvalidation();
766 } 836 }
767 } 837 }
768 838
769 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, 839 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
770 bool active) { 840 bool active) {
771 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 841 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 builder.append(")"); 921 builder.append(")");
852 } 922 }
853 } 923 }
854 builder.append("\n"); 924 builder.append("\n");
855 } 925 }
856 LOG(INFO) << m_markers.size() << " nodes have markers:\n" 926 LOG(INFO) << m_markers.size() << " nodes have markers:\n"
857 << builder.toString().utf8().data(); 927 << builder.toString().utf8().data();
858 } 928 }
859 #endif 929 #endif
860 930
931 // SynchronousMutationObserver
932 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
933 unsigned offset,
934 unsigned oldLength,
935 unsigned newLength) {
936 shiftMarkers(node, offset, oldLength, newLength);
937 }
938
861 } // namespace blink 939 } // namespace blink
862 940
863 #ifndef NDEBUG 941 #ifndef NDEBUG
864 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { 942 void showDocumentMarkers(const blink::DocumentMarkerController* controller) {
865 if (controller) 943 if (controller)
866 controller->showMarkers(); 944 controller->showMarkers();
867 } 945 }
868 #endif 946 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698