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

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

Issue 2692093003: Rewrite DocumentMarkerController to use SynchronousMutationObserver (Closed)
Patch Set: Remove PaintInvalidationReason (to split off into separate CL) 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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 newMarker.type() != DocumentMarker::Composition) { 255 newMarker.type() != DocumentMarker::Composition) {
259 mergeOverlapping(list.get(), newRenderedMarker); 256 mergeOverlapping(list.get(), newRenderedMarker);
260 } else { 257 } else {
261 MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(), 258 MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(),
262 &newMarker, startsFurther); 259 &newMarker, startsFurther);
263 list->insert(pos - list->begin(), newRenderedMarker); 260 list->insert(pos - list->begin(), newRenderedMarker);
264 } 261 }
265 } 262 }
266 263
267 // repaint the affected node 264 // repaint the affected node
268 if (node->layoutObject()) 265 if (node->layoutObject()) {
Xiaocheng 2017/02/23 18:58:35 nit: no need to add braces
269 node->layoutObject()->setShouldDoFullPaintInvalidation(); 266 node->layoutObject()->setShouldDoFullPaintInvalidation();
267 }
270 } 268 }
271 269
272 void DocumentMarkerController::mergeOverlapping( 270 void DocumentMarkerController::mergeOverlapping(
273 MarkerList* list, 271 MarkerList* list,
274 RenderedDocumentMarker* toInsert) { 272 RenderedDocumentMarker* toInsert) {
275 MarkerList::iterator firstOverlapping = 273 MarkerList::iterator firstOverlapping =
276 std::lower_bound(list->begin(), list->end(), toInsert, doesNotOverlap); 274 std::lower_bound(list->begin(), list->end(), toInsert, doesNotOverlap);
277 size_t index = firstOverlapping - list->begin(); 275 size_t index = firstOverlapping - list->begin();
278 list->insert(index, toInsert); 276 list->insert(index, toInsert);
279 MarkerList::iterator inserted = list->begin() + index; 277 MarkerList::iterator inserted = list->begin() + index;
(...skipping 21 matching lines...) Expand all
301 299
302 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 300 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
303 return; 301 return;
304 DCHECK(!m_markers.isEmpty()); 302 DCHECK(!m_markers.isEmpty());
305 303
306 MarkerLists* markers = m_markers.at(srcNode); 304 MarkerLists* markers = m_markers.at(srcNode);
307 if (!markers) 305 if (!markers)
308 return; 306 return;
309 307
310 bool docDirty = false; 308 bool docDirty = false;
311 for (size_t markerListIndex = 0; 309 for (Member<MarkerList> list : *markers) {
312 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
313 ++markerListIndex) {
314 Member<MarkerList>& list = (*markers)[markerListIndex];
315 if (!list) 310 if (!list)
316 continue; 311 continue;
317 312
318 unsigned endOffset = startOffset + length - 1; 313 unsigned endOffset = startOffset + length - 1;
319 MarkerList::iterator startPos = std::lower_bound( 314 MarkerList::iterator startPos = std::lower_bound(
320 list->begin(), list->end(), startOffset, doesNotInclude); 315 list->begin(), list->end(), startOffset, doesNotInclude);
321 for (MarkerList::iterator i = startPos; i != list->end(); ++i) { 316 for (MarkerList::iterator i = startPos; i != list->end(); ++i) {
322 DocumentMarker* marker = i->get(); 317 DocumentMarker* marker = i->get();
323 318
324 // stop if we are now past the specified range 319 // stop if we are now past the specified range
325 if (marker->startOffset() > endOffset) 320 if (marker->startOffset() > endOffset)
326 break; 321 break;
327 322
328 // pin the marker to the specified range and apply the shift delta 323 // pin the marker to the specified range and apply the shift delta
329 docDirty = true; 324 docDirty = true;
330 if (marker->startOffset() < startOffset) 325 if (marker->startOffset() < startOffset)
331 marker->setStartOffset(startOffset); 326 marker->setStartOffset(startOffset);
332 if (marker->endOffset() > endOffset) 327 if (marker->endOffset() > endOffset)
333 marker->setEndOffset(endOffset); 328 marker->setEndOffset(endOffset);
334 marker->shiftOffsets(delta); 329 marker->shiftOffsets(delta);
335 330
336 addMarker(dstNode, *marker); 331 addMarker(dstNode, *marker);
337 } 332 }
338 } 333 }
339 334
340 // repaint the affected node 335 // repaint the affected node
341 if (docDirty && dstNode->layoutObject()) 336 if (docDirty && dstNode->layoutObject()) {
Xiaocheng 2017/02/23 18:58:35 nit: no need to add braces
342 dstNode->layoutObject()->setShouldDoFullPaintInvalidation(); 337 dstNode->layoutObject()->setShouldDoFullPaintInvalidation();
338 }
343 } 339 }
344 340
345 void DocumentMarkerController::removeMarkers( 341 void DocumentMarkerController::removeMarkers(
346 Node* node, 342 Node* node,
347 unsigned startOffset, 343 unsigned startOffset,
348 int length, 344 int length,
349 DocumentMarker::MarkerTypes markerTypes, 345 DocumentMarker::MarkerTypes markerTypes,
350 RemovePartiallyOverlappingMarkerOrNot 346 RemovePartiallyOverlappingMarkerOrNot
351 shouldRemovePartiallyOverlappingMarker) { 347 shouldRemovePartiallyOverlappingMarker) {
352 if (length <= 0) 348 if (length <= 0)
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 } 417 }
422 } 418 }
423 419
424 if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) { 420 if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) {
425 m_markers.erase(node); 421 m_markers.erase(node);
426 if (m_markers.isEmpty()) 422 if (m_markers.isEmpty())
427 m_possiblyExistingMarkerTypes = 0; 423 m_possiblyExistingMarkerTypes = 0;
428 } 424 }
429 425
430 // repaint the affected node 426 // repaint the affected node
431 if (docDirty && node->layoutObject()) 427 if (docDirty && node->layoutObject()) {
Xiaocheng 2017/02/23 18:58:35 nit: no need to add braces
432 node->layoutObject()->setShouldDoFullPaintInvalidation(); 428 node->layoutObject()->setShouldDoFullPaintInvalidation();
429 }
433 } 430 }
434 431
435 DocumentMarkerVector DocumentMarkerController::markersFor( 432 DocumentMarkerVector DocumentMarkerController::markersFor(
436 Node* node, 433 Node* node,
437 DocumentMarker::MarkerTypes markerTypes) { 434 DocumentMarker::MarkerTypes markerTypes) {
438 DocumentMarkerVector result; 435 DocumentMarkerVector result;
439 436
440 MarkerLists* markers = m_markers.at(node); 437 MarkerLists* markers = m_markers.at(node);
441 if (!markers) 438 if (!markers)
442 return result; 439 return result;
(...skipping 138 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 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 needsRepainting = true; 676 needsRepainting = true;
679 } 677 }
680 } 678 }
681 679
682 nodeCanBeRemoved = 680 nodeCanBeRemoved =
683 emptyListsCount == DocumentMarker::MarkerTypeIndexesCount; 681 emptyListsCount == DocumentMarker::MarkerTypeIndexesCount;
684 } 682 }
685 683
686 if (needsRepainting) { 684 if (needsRepainting) {
687 const Node& node = *iterator->key; 685 const Node& node = *iterator->key;
688 if (LayoutObject* layoutObject = node.layoutObject()) 686 if (LayoutObject* layoutObject = node.layoutObject()) {
Xiaocheng 2017/02/23 18:58:35 nit: no need to add braces
689 layoutObject->setShouldDoFullPaintInvalidation(); 687 layoutObject->setShouldDoFullPaintInvalidation();
688 }
690 invalidatePaintForTickmarks(node); 689 invalidatePaintForTickmarks(node);
691 } 690 }
692 691
693 if (nodeCanBeRemoved) { 692 if (nodeCanBeRemoved) {
694 m_markers.remove(iterator); 693 m_markers.remove(iterator);
695 if (m_markers.isEmpty()) 694 if (m_markers.isEmpty())
696 m_possiblyExistingMarkerTypes = 0; 695 m_possiblyExistingMarkerTypes = 0;
697 } 696 }
698 } 697 }
699 698
(...skipping 20 matching lines...) Expand all
720 719
721 // cause the node to be redrawn 720 // cause the node to be redrawn
722 if (LayoutObject* layoutObject = node->layoutObject()) { 721 if (LayoutObject* layoutObject = node->layoutObject()) {
723 layoutObject->setShouldDoFullPaintInvalidation(); 722 layoutObject->setShouldDoFullPaintInvalidation();
724 break; 723 break;
725 } 724 }
726 } 725 }
727 } 726 }
728 } 727 }
729 728
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.at(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, 729 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
770 bool active) { 730 bool active) {
771 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 731 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
772 return false; 732 return false;
773 733
774 DCHECK(!m_markers.isEmpty()); 734 DCHECK(!m_markers.isEmpty());
775 735
776 Node* const startContainer = range.startPosition().computeContainerNode(); 736 Node* const startContainer = range.startPosition().computeContainerNode();
777 DCHECK(startContainer); 737 DCHECK(startContainer);
778 Node* const endContainer = range.endPosition().computeContainerNode(); 738 Node* const endContainer = range.endPosition().computeContainerNode();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
812 // Markers are returned in order, so stop if we are now past the specified 772 // Markers are returned in order, so stop if we are now past the specified
813 // range. 773 // range.
814 if ((*marker)->startOffset() >= endOffset) 774 if ((*marker)->startOffset() >= endOffset)
815 break; 775 break;
816 776
817 (*marker)->setActiveMatch(active); 777 (*marker)->setActiveMatch(active);
818 docDirty = true; 778 docDirty = true;
819 } 779 }
820 780
821 // repaint the affected node 781 // repaint the affected node
822 if (docDirty && node->layoutObject()) 782 if (docDirty && node->layoutObject()) {
Xiaocheng 2017/02/23 18:58:35 nit: no need to add braces.
823 node->layoutObject()->setShouldDoFullPaintInvalidation(); 783 node->layoutObject()->setShouldDoFullPaintInvalidation();
784 }
824 return docDirty; 785 return docDirty;
825 } 786 }
826 787
827 #ifndef NDEBUG 788 #ifndef NDEBUG
828 void DocumentMarkerController::showMarkers() const { 789 void DocumentMarkerController::showMarkers() const {
829 StringBuilder builder; 790 StringBuilder builder;
830 MarkerMap::const_iterator end = m_markers.end(); 791 MarkerMap::const_iterator end = m_markers.end();
831 for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); 792 for (MarkerMap::const_iterator nodeIterator = m_markers.begin();
832 nodeIterator != end; ++nodeIterator) { 793 nodeIterator != end; ++nodeIterator) {
833 const Node* node = nodeIterator->key; 794 const Node* node = nodeIterator->key;
(...skipping 17 matching lines...) Expand all
851 builder.append(")"); 812 builder.append(")");
852 } 813 }
853 } 814 }
854 builder.append("\n"); 815 builder.append("\n");
855 } 816 }
856 LOG(INFO) << m_markers.size() << " nodes have markers:\n" 817 LOG(INFO) << m_markers.size() << " nodes have markers:\n"
857 << builder.toString().utf8().data(); 818 << builder.toString().utf8().data();
858 } 819 }
859 #endif 820 #endif
860 821
822 // SynchronousMutationObserver
823 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
824 unsigned offset,
825 unsigned oldLength,
826 unsigned newLength) {
827 // If we're doing a pure remove operation, remove the markers in the range
828 // being removed (markers containing, but larger than, the range, will be
829 // split)
830 if (newLength == 0)
831 removeMarkers(node, offset, oldLength);
832
833 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
834 return;
835 DCHECK(!m_markers.isEmpty());
836
837 MarkerLists* markers = m_markers.at(node);
838 if (!markers)
839 return;
840
841 bool didShiftMarker = false;
842 for (MarkerList* list : *markers) {
843 if (!list)
844 continue;
845
846 for (MarkerList::iterator marker = list->begin(); marker != list->end();
847 ++marker) {
848 // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace
849 // but with some changes
850 if ((*marker)->startOffset() > offset) {
851 // Deviation from the concept-cd-replace algorithm: < instead of <= in
852 // the next line
853 if ((*marker)->startOffset() < offset + oldLength) {
854 // Marker start was in the replaced text. Move to end of new text
855 // (Deviation from the concept-cd-replace algorithm: that algorithm
856 // would move to the beginning of the new text here)
857 (*marker)->setStartOffset(offset + newLength);
858 } else {
859 // Marker start was after the replaced text. Shift by length
860 // difference
861 unsigned oldStartOffset = (*marker)->startOffset();
862 (*marker)->setStartOffset(oldStartOffset + newLength - oldLength);
863 }
864 }
865
866 if ((*marker)->endOffset() > offset) {
867 // Deviation from the concept-cd-replace algorithm: < instead of <= in
868 // the next line
869 if ((*marker)->endOffset() < offset + oldLength) {
870 // Marker end was in the replaced text. Move to beginning of new text
871 (*marker)->setEndOffset(offset);
872 } else {
873 // Marker end was after the replaced text. Shift by length difference
874 unsigned oldEndOffset = (*marker)->endOffset();
875 (*marker)->setEndOffset(oldEndOffset + newLength - oldLength);
876 }
877 }
878
879 if ((*marker)->startOffset() >= (*marker)->endOffset()) {
880 list->remove(marker - list->begin());
881 --marker;
882 continue;
883 }
884
885 didShiftMarker = true;
Xiaocheng 2017/02/23 18:58:35 didShiftMarker = true should be set after L863 and
886 }
887 }
888
889 if (didShiftMarker) {
890 invalidateRectsForMarkersInNode(*node);
891 // repaint the affected node
892 if (node->layoutObject()) {
893 node->layoutObject()->setShouldDoFullPaintInvalidation();
894 }
895 }
896 }
897
861 } // namespace blink 898 } // namespace blink
862 899
863 #ifndef NDEBUG 900 #ifndef NDEBUG
864 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { 901 void showDocumentMarkers(const blink::DocumentMarkerController* controller) {
865 if (controller) 902 if (controller)
866 controller->showMarkers(); 903 controller->showMarkers();
867 } 904 }
868 #endif 905 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698