Chromium Code Reviews| 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 |