| 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 return DocumentMarker::SpellingMarkerIndex; | 75 return DocumentMarker::SpellingMarkerIndex; |
| 76 } | 76 } |
| 77 | 77 |
| 78 } // namespace | 78 } // namespace |
| 79 | 79 |
| 80 inline bool DocumentMarkerController::possiblyHasMarkers( | 80 inline bool DocumentMarkerController::possiblyHasMarkers( |
| 81 DocumentMarker::MarkerTypes types) { | 81 DocumentMarker::MarkerTypes types) { |
| 82 return m_possiblyExistingMarkerTypes.intersects(types); | 82 return m_possiblyExistingMarkerTypes.intersects(types); |
| 83 } | 83 } |
| 84 | 84 |
| 85 DocumentMarkerController::DocumentMarkerController(const Document& document) | 85 DocumentMarkerController::DocumentMarkerController(Document& document) |
| 86 : m_possiblyExistingMarkerTypes(0), m_document(&document) {} | 86 : m_possiblyExistingMarkerTypes(0), m_document(&document) { |
| 87 setContext(&document); |
| 88 } |
| 87 | 89 |
| 88 void DocumentMarkerController::clear() { | 90 void DocumentMarkerController::clear() { |
| 89 m_markers.clear(); | 91 m_markers.clear(); |
| 90 m_possiblyExistingMarkerTypes = 0; | 92 m_possiblyExistingMarkerTypes = 0; |
| 91 } | 93 } |
| 92 | 94 |
| 93 void DocumentMarkerController::addMarker(const Position& start, | 95 void DocumentMarkerController::addMarker(const Position& start, |
| 94 const Position& end, | 96 const Position& end, |
| 95 DocumentMarker::MarkerType type, | 97 DocumentMarker::MarkerType type, |
| 96 const String& description) { | 98 const String& description) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 TextIterator markedText(range.startPosition(), range.endPosition()); | 170 TextIterator markedText(range.startPosition(), range.endPosition()); |
| 169 DocumentMarkerController::removeMarkers( | 171 DocumentMarkerController::removeMarkers( |
| 170 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); | 172 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); |
| 171 } | 173 } |
| 172 | 174 |
| 173 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, | 175 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, |
| 174 const DocumentMarker* rhv) { | 176 const DocumentMarker* rhv) { |
| 175 return lhv->startOffset() < rhv->startOffset(); | 177 return lhv->startOffset() < rhv->startOffset(); |
| 176 } | 178 } |
| 177 | 179 |
| 178 static bool startsAfter(const Member<RenderedDocumentMarker>& marker, | |
| 179 size_t startOffset) { | |
| 180 return marker->startOffset() < startOffset; | |
| 181 } | |
| 182 | |
| 183 static bool endsBefore(size_t startOffset, | 180 static bool endsBefore(size_t startOffset, |
| 184 const Member<RenderedDocumentMarker>& rhv) { | 181 const Member<RenderedDocumentMarker>& rhv) { |
| 185 return startOffset < rhv->endOffset(); | 182 return startOffset < rhv->endOffset(); |
| 186 } | 183 } |
| 187 | 184 |
| 188 static bool compareByStart(const Member<DocumentMarker>& lhv, | 185 static bool compareByStart(const Member<DocumentMarker>& lhv, |
| 189 const Member<DocumentMarker>& rhv) { | 186 const Member<DocumentMarker>& rhv) { |
| 190 return lhv->startOffset() < rhv->startOffset(); | 187 return lhv->startOffset() < rhv->startOffset(); |
| 191 } | 188 } |
| 192 | 189 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 298 | 295 |
| 299 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) | 296 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) |
| 300 return; | 297 return; |
| 301 DCHECK(!m_markers.isEmpty()); | 298 DCHECK(!m_markers.isEmpty()); |
| 302 | 299 |
| 303 MarkerLists* markers = m_markers.at(srcNode); | 300 MarkerLists* markers = m_markers.at(srcNode); |
| 304 if (!markers) | 301 if (!markers) |
| 305 return; | 302 return; |
| 306 | 303 |
| 307 bool docDirty = false; | 304 bool docDirty = false; |
| 308 for (size_t markerListIndex = 0; | 305 for (Member<MarkerList> list : *markers) { |
| 309 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; | |
| 310 ++markerListIndex) { | |
| 311 Member<MarkerList>& list = (*markers)[markerListIndex]; | |
| 312 if (!list) | 306 if (!list) |
| 313 continue; | 307 continue; |
| 314 | 308 |
| 315 unsigned endOffset = startOffset + length - 1; | 309 unsigned endOffset = startOffset + length - 1; |
| 316 MarkerList::iterator startPos = std::lower_bound( | 310 MarkerList::iterator startPos = std::lower_bound( |
| 317 list->begin(), list->end(), startOffset, doesNotInclude); | 311 list->begin(), list->end(), startOffset, doesNotInclude); |
| 318 for (MarkerList::iterator i = startPos; i != list->end(); ++i) { | 312 for (MarkerList::iterator i = startPos; i != list->end(); ++i) { |
| 319 DocumentMarker* marker = i->get(); | 313 DocumentMarker* marker = i->get(); |
| 320 | 314 |
| 321 // stop if we are now past the specified range | 315 // stop if we are now past the specified range |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 | 572 |
| 579 if (markerList->front()->type() == DocumentMarker::TextMatch) | 573 if (markerList->front()->type() == DocumentMarker::TextMatch) |
| 580 invalidatePaintForTickmarks(node); | 574 invalidatePaintForTickmarks(node); |
| 581 } | 575 } |
| 582 } | 576 } |
| 583 } | 577 } |
| 584 | 578 |
| 585 DEFINE_TRACE(DocumentMarkerController) { | 579 DEFINE_TRACE(DocumentMarkerController) { |
| 586 visitor->trace(m_markers); | 580 visitor->trace(m_markers); |
| 587 visitor->trace(m_document); | 581 visitor->trace(m_document); |
| 582 SynchronousMutationObserver::trace(visitor); |
| 588 } | 583 } |
| 589 | 584 |
| 590 void DocumentMarkerController::removeMarkers( | 585 void DocumentMarkerController::removeMarkers( |
| 591 Node* node, | 586 Node* node, |
| 592 DocumentMarker::MarkerTypes markerTypes) { | 587 DocumentMarker::MarkerTypes markerTypes) { |
| 593 if (!possiblyHasMarkers(markerTypes)) | 588 if (!possiblyHasMarkers(markerTypes)) |
| 594 return; | 589 return; |
| 595 DCHECK(!m_markers.isEmpty()); | 590 DCHECK(!m_markers.isEmpty()); |
| 596 | 591 |
| 597 MarkerMap::iterator iterator = m_markers.find(node); | 592 MarkerMap::iterator iterator = m_markers.find(node); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 | 712 |
| 718 // cause the node to be redrawn | 713 // cause the node to be redrawn |
| 719 if (LayoutObject* layoutObject = node->layoutObject()) { | 714 if (LayoutObject* layoutObject = node->layoutObject()) { |
| 720 layoutObject->setShouldDoFullPaintInvalidation(); | 715 layoutObject->setShouldDoFullPaintInvalidation(); |
| 721 break; | 716 break; |
| 722 } | 717 } |
| 723 } | 718 } |
| 724 } | 719 } |
| 725 } | 720 } |
| 726 | 721 |
| 727 void DocumentMarkerController::shiftMarkers(Node* node, | |
| 728 unsigned startOffset, | |
| 729 int delta) { | |
| 730 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) | |
| 731 return; | |
| 732 DCHECK(!m_markers.isEmpty()); | |
| 733 | |
| 734 MarkerLists* markers = m_markers.at(node); | |
| 735 if (!markers) | |
| 736 return; | |
| 737 | |
| 738 bool didShiftMarker = false; | |
| 739 for (size_t markerListIndex = 0; | |
| 740 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; | |
| 741 ++markerListIndex) { | |
| 742 Member<MarkerList>& list = (*markers)[markerListIndex]; | |
| 743 if (!list) | |
| 744 continue; | |
| 745 MarkerList::iterator startPos = | |
| 746 std::lower_bound(list->begin(), list->end(), startOffset, startsAfter); | |
| 747 for (MarkerList::iterator marker = startPos; marker != list->end(); | |
| 748 ++marker) { | |
| 749 #if DCHECK_IS_ON() | |
| 750 int startOffset = (*marker)->startOffset(); | |
| 751 DCHECK_GE(startOffset + delta, 0); | |
| 752 #endif | |
| 753 (*marker)->shiftOffsets(delta); | |
| 754 didShiftMarker = true; | |
| 755 } | |
| 756 } | |
| 757 | |
| 758 if (didShiftMarker) { | |
| 759 invalidateRectsForMarkersInNode(*node); | |
| 760 // repaint the affected node | |
| 761 if (node->layoutObject()) | |
| 762 node->layoutObject()->setShouldDoFullPaintInvalidation(); | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, | 722 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, |
| 767 bool active) { | 723 bool active) { |
| 768 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) | 724 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) |
| 769 return false; | 725 return false; |
| 770 | 726 |
| 771 DCHECK(!m_markers.isEmpty()); | 727 DCHECK(!m_markers.isEmpty()); |
| 772 | 728 |
| 773 Node* const startContainer = range.startPosition().computeContainerNode(); | 729 Node* const startContainer = range.startPosition().computeContainerNode(); |
| 774 DCHECK(startContainer); | 730 DCHECK(startContainer); |
| 775 Node* const endContainer = range.endPosition().computeContainerNode(); | 731 Node* const endContainer = range.endPosition().computeContainerNode(); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 builder.append(")"); | 804 builder.append(")"); |
| 849 } | 805 } |
| 850 } | 806 } |
| 851 builder.append("\n"); | 807 builder.append("\n"); |
| 852 } | 808 } |
| 853 LOG(INFO) << m_markers.size() << " nodes have markers:\n" | 809 LOG(INFO) << m_markers.size() << " nodes have markers:\n" |
| 854 << builder.toString().utf8().data(); | 810 << builder.toString().utf8().data(); |
| 855 } | 811 } |
| 856 #endif | 812 #endif |
| 857 | 813 |
| 814 // SynchronousMutationObserver |
| 815 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, |
| 816 unsigned offset, |
| 817 unsigned oldLength, |
| 818 unsigned newLength) { |
| 819 // If we're doing a pure remove operation, remove the markers in the range |
| 820 // being removed (markers containing, but larger than, the range, will be |
| 821 // split) |
| 822 if (newLength == 0) |
| 823 removeMarkers(node, offset, oldLength); |
| 824 |
| 825 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) |
| 826 return; |
| 827 DCHECK(!m_markers.isEmpty()); |
| 828 |
| 829 MarkerLists* markers = m_markers.at(node); |
| 830 if (!markers) |
| 831 return; |
| 832 |
| 833 bool didShiftMarker = false; |
| 834 for (MarkerList* list : *markers) { |
| 835 if (!list) |
| 836 continue; |
| 837 |
| 838 for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) { |
| 839 RenderedDocumentMarker& marker = **it; |
| 840 // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace |
| 841 // but with some changes |
| 842 if (marker.startOffset() > offset) { |
| 843 // Deviation from the concept-cd-replace algorithm: < instead of <= in |
| 844 // the next line |
| 845 if (marker.startOffset() < offset + oldLength) { |
| 846 // Marker start was in the replaced text. Move to end of new text |
| 847 // (Deviation from the concept-cd-replace algorithm: that algorithm |
| 848 // would move to the beginning of the new text here) |
| 849 marker.setStartOffset(offset + newLength); |
| 850 } else { |
| 851 // Marker start was after the replaced text. Shift by length |
| 852 // difference |
| 853 unsigned oldStartOffset = marker.startOffset(); |
| 854 marker.setStartOffset(oldStartOffset + newLength - oldLength); |
| 855 } |
| 856 didShiftMarker = true; |
| 857 } |
| 858 |
| 859 if (marker.endOffset() > offset) { |
| 860 // Deviation from the concept-cd-replace algorithm: < instead of <= in |
| 861 // the next line |
| 862 if (marker.endOffset() < offset + oldLength) { |
| 863 // Marker end was in the replaced text. Move to beginning of new text |
| 864 marker.setEndOffset(offset); |
| 865 } else { |
| 866 // Marker end was after the replaced text. Shift by length difference |
| 867 unsigned oldEndOffset = marker.endOffset(); |
| 868 marker.setEndOffset(oldEndOffset + newLength - oldLength); |
| 869 } |
| 870 didShiftMarker = true; |
| 871 } |
| 872 |
| 873 if (marker.startOffset() < marker.endOffset()) |
| 874 continue; |
| 875 list->remove(it - list->begin()); |
| 876 --it; |
| 877 } |
| 878 } |
| 879 |
| 880 if (!didShiftMarker) |
| 881 return; |
| 882 if (!node->layoutObject()) |
| 883 return; |
| 884 invalidateRectsForMarkersInNode(*node); |
| 885 // repaint the affected node |
| 886 node->layoutObject()->setShouldDoFullPaintInvalidation(); |
| 887 } |
| 888 |
| 858 } // namespace blink | 889 } // namespace blink |
| 859 | 890 |
| 860 #ifndef NDEBUG | 891 #ifndef NDEBUG |
| 861 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { | 892 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { |
| 862 if (controller) | 893 if (controller) |
| 863 controller->showMarkers(); | 894 controller->showMarkers(); |
| 864 } | 895 } |
| 865 #endif | 896 #endif |
| OLD | NEW |