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( | |
Xiaocheng
2017/03/29 18:35:19
Can we implement this function directly in Documen
| |
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 | |
659 // Deviation from the concept-cd-replace algorithm: second condition in the | |
660 // next line (don't include text inserted immediately before a marker in the | |
661 // marked range, but do include the new text if it's replacing text in the | |
662 // marked range) | |
663 if (marker->startOffset() > offset || | |
664 (marker->startOffset() == offset && oldLength == 0)) { | |
665 if (marker->startOffset() <= offset + oldLength) { | |
666 // Marker start was in the replaced text. Move to end of new text | |
667 // (Deviation from the concept-cd-replace algorithm: that algorithm | |
668 // would move to the beginning of the new text here) | |
669 marker->setStartOffset(offset + newLength); | |
670 } else { | |
671 // Marker start was after the replaced text. Shift by length | |
672 // difference | |
673 unsigned oldStartOffset = marker->startOffset(); | |
674 marker->setStartOffset(oldStartOffset + newLength - oldLength); | |
675 } | |
676 didShiftMarker = true; | |
677 } | |
678 | |
679 if (marker->endOffset() > offset) { | |
680 // Deviation from the concept-cd-replace algorithm: < instead of <= in | |
681 // the next line | |
682 if (marker->endOffset() < offset + oldLength) { | |
683 // Marker end was in the replaced text. Move to beginning of new text | |
684 marker->setEndOffset(offset); | |
685 } else { | |
686 // Marker end was after the replaced text. Shift by length difference | |
687 unsigned oldEndOffset = marker->endOffset(); | |
688 marker->setEndOffset(oldEndOffset + newLength - oldLength); | |
689 } | |
690 didShiftMarker = true; | |
691 } | |
692 | |
693 return didShiftMarker; | |
694 } | |
695 | |
657 void DocumentMarkerController::removeMarkersFromList( | 696 void DocumentMarkerController::removeMarkersFromList( |
658 MarkerMap::iterator iterator, | 697 MarkerMap::iterator iterator, |
659 DocumentMarker::MarkerTypes markerTypes) { | 698 DocumentMarker::MarkerTypes markerTypes) { |
660 bool needsRepainting = false; | 699 bool needsRepainting = false; |
661 bool nodeCanBeRemoved; | 700 bool nodeCanBeRemoved; |
662 | 701 |
663 size_t emptyListsCount = 0; | 702 size_t emptyListsCount = 0; |
664 if (markerTypes == DocumentMarker::AllMarkers()) { | 703 if (markerTypes == DocumentMarker::AllMarkers()) { |
665 needsRepainting = true; | 704 needsRepainting = true; |
666 nodeCanBeRemoved = true; | 705 nodeCanBeRemoved = true; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
729 // cause the node to be redrawn | 768 // cause the node to be redrawn |
730 if (LayoutObject* layoutObject = node->layoutObject()) { | 769 if (LayoutObject* layoutObject = node->layoutObject()) { |
731 layoutObject->setShouldDoFullPaintInvalidation( | 770 layoutObject->setShouldDoFullPaintInvalidation( |
732 PaintInvalidationDocumentMarkerChange); | 771 PaintInvalidationDocumentMarkerChange); |
733 break; | 772 break; |
734 } | 773 } |
735 } | 774 } |
736 } | 775 } |
737 } | 776 } |
738 | 777 |
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, | 778 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, |
781 bool active) { | 779 bool active) { |
782 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) | 780 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) |
783 return false; | 781 return false; |
784 | 782 |
785 DCHECK(!m_markers.isEmpty()); | 783 DCHECK(!m_markers.isEmpty()); |
786 | 784 |
787 Node* const startContainer = range.startPosition().computeContainerNode(); | 785 Node* const startContainer = range.startPosition().computeContainerNode(); |
788 DCHECK(startContainer); | 786 DCHECK(startContainer); |
789 Node* const endContainer = range.endPosition().computeContainerNode(); | 787 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" | 867 LOG(INFO) << m_markers.size() << " nodes have markers:\n" |
870 << builder.toString().utf8().data(); | 868 << builder.toString().utf8().data(); |
871 } | 869 } |
872 #endif | 870 #endif |
873 | 871 |
874 // SynchronousMutationObserver | 872 // SynchronousMutationObserver |
875 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, | 873 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, |
876 unsigned offset, | 874 unsigned offset, |
877 unsigned oldLength, | 875 unsigned oldLength, |
878 unsigned newLength) { | 876 unsigned newLength) { |
879 // Shift markers as if we first remove the old text, then insert the new text | 877 // If we're doing a pure remove operation, remove the markers in the range |
880 removeMarkers(node, offset, oldLength); | 878 // being removed (markers containing, but larger than, the range, will be |
881 shiftMarkers(node, offset + oldLength, 0 - oldLength); | 879 // split) |
882 shiftMarkers(node, offset, newLength); | 880 if (newLength == 0) |
881 removeMarkers(node, offset, oldLength); | |
882 | |
883 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) | |
884 return; | |
885 DCHECK(!m_markers.isEmpty()); | |
886 | |
887 MarkerLists* markers = m_markers.at(node); | |
888 if (!markers) | |
889 return; | |
890 | |
891 bool didShiftMarker = false; | |
892 for (MarkerList* list : *markers) { | |
893 if (!list) | |
894 continue; | |
895 | |
896 for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) { | |
897 RenderedDocumentMarker& marker = **it; | |
898 if (relocateMarkerIfNeeded(&marker, offset, oldLength, newLength)) { | |
899 didShiftMarker = true; | |
900 | |
901 if (marker.startOffset() < marker.endOffset()) | |
902 continue; | |
903 list->erase(it - list->begin()); | |
904 --it; | |
905 } | |
906 } | |
907 } | |
908 | |
909 if (!didShiftMarker) | |
910 return; | |
911 if (!node->layoutObject()) | |
912 return; | |
913 invalidateRectsForMarkersInNode(*node); | |
914 // repaint the affected node | |
915 node->layoutObject()->setShouldDoFullPaintInvalidation(); | |
883 } | 916 } |
884 | 917 |
885 } // namespace blink | 918 } // namespace blink |
886 | 919 |
887 #ifndef NDEBUG | 920 #ifndef NDEBUG |
888 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { | 921 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { |
889 if (controller) | 922 if (controller) |
890 controller->showMarkers(); | 923 controller->showMarkers(); |
891 } | 924 } |
892 #endif | 925 #endif |
OLD | NEW |