OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
647 unsigned size = nodesWithMarkers.size(); | 639 unsigned size = nodesWithMarkers.size(); |
648 for (unsigned i = 0; i < size; ++i) { | 640 for (unsigned i = 0; i < size; ++i) { |
649 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]); | 641 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]); |
650 if (iterator != m_markers.end()) | 642 if (iterator != m_markers.end()) |
651 removeMarkersFromList(iterator, markerTypes); | 643 removeMarkersFromList(iterator, markerTypes); |
652 } | 644 } |
653 | 645 |
654 m_possiblyExistingMarkerTypes.remove(markerTypes); | 646 m_possiblyExistingMarkerTypes.remove(markerTypes); |
655 } | 647 } |
656 | 648 |
649 bool DocumentMarkerController::relocateMarkerIfNeeded( | |
650 RenderedDocumentMarker* marker, | |
651 unsigned offset, | |
652 unsigned oldLength, | |
653 unsigned newLength) { | |
654 bool didShiftMarker = false; | |
655 | |
656 // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace | |
657 // but with some changes | |
658 if (marker->startOffset() > offset) { | |
rlanday
2017/03/23 22:52:00
I think there's one more tweak we want to make: as
| |
659 // Deviation from the concept-cd-replace algorithm: < instead of <= in | |
660 // the next line | |
661 if (marker->startOffset() < offset + oldLength) { | |
rlanday
2017/03/23 22:52:00
Since we're moving the marker start to the end of
| |
662 // Marker start was in the replaced text. Move to end of new text | |
663 // (Deviation from the concept-cd-replace algorithm: that algorithm | |
664 // would move to the beginning of the new text here) | |
665 marker->setStartOffset(offset + newLength); | |
666 } else { | |
667 // Marker start was after the replaced text. Shift by length | |
668 // difference | |
669 unsigned oldStartOffset = marker->startOffset(); | |
670 marker->setStartOffset(oldStartOffset + newLength - oldLength); | |
671 } | |
672 didShiftMarker = true; | |
673 } | |
674 | |
675 if (marker->endOffset() > offset) { | |
676 // Deviation from the concept-cd-replace algorithm: < instead of <= in | |
677 // the next line | |
678 if (marker->endOffset() < offset + oldLength) { | |
679 // Marker end was in the replaced text. Move to beginning of new text | |
680 marker->setEndOffset(offset); | |
681 } else { | |
682 // Marker end was after the replaced text. Shift by length difference | |
683 unsigned oldEndOffset = marker->endOffset(); | |
684 marker->setEndOffset(oldEndOffset + newLength - oldLength); | |
685 } | |
686 didShiftMarker = true; | |
687 } | |
688 | |
689 return didShiftMarker; | |
690 } | |
691 | |
657 void DocumentMarkerController::removeMarkersFromList( | 692 void DocumentMarkerController::removeMarkersFromList( |
658 MarkerMap::iterator iterator, | 693 MarkerMap::iterator iterator, |
659 DocumentMarker::MarkerTypes markerTypes) { | 694 DocumentMarker::MarkerTypes markerTypes) { |
660 bool needsRepainting = false; | 695 bool needsRepainting = false; |
661 bool nodeCanBeRemoved; | 696 bool nodeCanBeRemoved; |
662 | 697 |
663 size_t emptyListsCount = 0; | 698 size_t emptyListsCount = 0; |
664 if (markerTypes == DocumentMarker::AllMarkers()) { | 699 if (markerTypes == DocumentMarker::AllMarkers()) { |
665 needsRepainting = true; | 700 needsRepainting = true; |
666 nodeCanBeRemoved = true; | 701 nodeCanBeRemoved = true; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
729 // cause the node to be redrawn | 764 // cause the node to be redrawn |
730 if (LayoutObject* layoutObject = node->layoutObject()) { | 765 if (LayoutObject* layoutObject = node->layoutObject()) { |
731 layoutObject->setShouldDoFullPaintInvalidation( | 766 layoutObject->setShouldDoFullPaintInvalidation( |
732 PaintInvalidationDocumentMarkerChange); | 767 PaintInvalidationDocumentMarkerChange); |
733 break; | 768 break; |
734 } | 769 } |
735 } | 770 } |
736 } | 771 } |
737 } | 772 } |
738 | 773 |
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, | 774 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, |
781 bool active) { | 775 bool active) { |
782 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) | 776 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) |
783 return false; | 777 return false; |
784 | 778 |
785 DCHECK(!m_markers.isEmpty()); | 779 DCHECK(!m_markers.isEmpty()); |
786 | 780 |
787 Node* const startContainer = range.startPosition().computeContainerNode(); | 781 Node* const startContainer = range.startPosition().computeContainerNode(); |
788 DCHECK(startContainer); | 782 DCHECK(startContainer); |
789 Node* const endContainer = range.endPosition().computeContainerNode(); | 783 Node* const endContainer = range.endPosition().computeContainerNode(); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
869 LOG(INFO) << m_markers.size() << " nodes have markers:\n" | 863 LOG(INFO) << m_markers.size() << " nodes have markers:\n" |
870 << builder.toString().utf8().data(); | 864 << builder.toString().utf8().data(); |
871 } | 865 } |
872 #endif | 866 #endif |
873 | 867 |
874 // SynchronousMutationObserver | 868 // SynchronousMutationObserver |
875 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, | 869 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, |
876 unsigned offset, | 870 unsigned offset, |
877 unsigned oldLength, | 871 unsigned oldLength, |
878 unsigned newLength) { | 872 unsigned newLength) { |
879 // Shift markers as if we first remove the old text, then insert the new text | 873 // If we're doing a pure remove operation, remove the markers in the range |
880 removeMarkers(node, offset, oldLength); | 874 // being removed (markers containing, but larger than, the range, will be |
881 shiftMarkers(node, offset + oldLength, 0 - oldLength); | 875 // split) |
882 shiftMarkers(node, offset, newLength); | 876 if (newLength == 0) |
877 removeMarkers(node, offset, oldLength); | |
878 | |
879 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) | |
880 return; | |
881 DCHECK(!m_markers.isEmpty()); | |
882 | |
883 MarkerLists* markers = m_markers.at(node); | |
884 if (!markers) | |
885 return; | |
886 | |
887 bool didShiftMarker = false; | |
888 for (MarkerList* list : *markers) { | |
889 if (!list) | |
890 continue; | |
891 | |
892 for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) { | |
893 RenderedDocumentMarker& marker = **it; | |
894 if (relocateMarkerIfNeeded(&marker, offset, oldLength, newLength)) { | |
895 didShiftMarker = true; | |
896 | |
897 if (marker.startOffset() < marker.endOffset()) | |
898 continue; | |
899 list->remove(it - list->begin()); | |
900 --it; | |
901 } | |
902 } | |
903 } | |
904 | |
905 if (!didShiftMarker) | |
906 return; | |
907 if (!node->layoutObject()) | |
908 return; | |
909 invalidateRectsForMarkersInNode(*node); | |
910 // repaint the affected node | |
911 node->layoutObject()->setShouldDoFullPaintInvalidation(); | |
883 } | 912 } |
884 | 913 |
885 } // namespace blink | 914 } // namespace blink |
886 | 915 |
887 #ifndef NDEBUG | 916 #ifndef NDEBUG |
888 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { | 917 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { |
889 if (controller) | 918 if (controller) |
890 controller->showMarkers(); | 919 controller->showMarkers(); |
891 } | 920 } |
892 #endif | 921 #endif |
OLD | NEW |