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

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

Issue 2650113004: [WIP] Add support for Android SuggestionSpans when editing text (Closed)
Patch Set: Created 3 years, 11 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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 case DocumentMarker::Spelling: 64 case DocumentMarker::Spelling:
65 return DocumentMarker::SpellingMarkerIndex; 65 return DocumentMarker::SpellingMarkerIndex;
66 case DocumentMarker::Grammar: 66 case DocumentMarker::Grammar:
67 return DocumentMarker::GrammarMarkerIndex; 67 return DocumentMarker::GrammarMarkerIndex;
68 case DocumentMarker::TextMatch: 68 case DocumentMarker::TextMatch:
69 return DocumentMarker::TextMatchMarkerIndex; 69 return DocumentMarker::TextMatchMarkerIndex;
70 case DocumentMarker::InvisibleSpellcheck: 70 case DocumentMarker::InvisibleSpellcheck:
71 return DocumentMarker::InvisibleSpellcheckMarkerIndex; 71 return DocumentMarker::InvisibleSpellcheckMarkerIndex;
72 case DocumentMarker::Composition: 72 case DocumentMarker::Composition:
73 return DocumentMarker::CompositionMarkerIndex; 73 return DocumentMarker::CompositionMarkerIndex;
74 case DocumentMarker::Suggestion:
75 return DocumentMarker::SuggestionMarkerIndex;
76 case DocumentMarker::SuggestionBackgroundHighlight:
77 return DocumentMarker::SuggestionBackgroundHighlightMarkerIndex;
74 } 78 }
75 79
76 NOTREACHED(); 80 NOTREACHED();
77 return DocumentMarker::SpellingMarkerIndex; 81 return DocumentMarker::SpellingMarkerIndex;
78 } 82 }
79 83
80 } // namespace 84 } // namespace
81 85
82 inline bool DocumentMarkerController::possiblyHasMarkers( 86 inline bool DocumentMarkerController::possiblyHasMarkers(
83 DocumentMarker::MarkerTypes types) { 87 DocumentMarker::MarkerTypes types) {
84 return m_possiblyExistingMarkerTypes.intersects(types); 88 return m_possiblyExistingMarkerTypes.intersects(types);
85 } 89 }
86 90
87 DocumentMarkerController::DocumentMarkerController(const Document& document) 91 DocumentMarkerController::DocumentMarkerController(const Document& document)
88 : m_possiblyExistingMarkerTypes(0), m_document(&document) {} 92 : m_possiblyExistingMarkerTypes(0),
93 m_document(&document),
94 m_nextSuggestionMarkerID(0) {}
89 95
90 void DocumentMarkerController::clear() { 96 void DocumentMarkerController::clear() {
91 m_markers.clear(); 97 m_markers.clear();
92 m_possiblyExistingMarkerTypes = 0; 98 m_possiblyExistingMarkerTypes = 0;
99 m_nextSuggestionMarkerID = 0;
93 } 100 }
94 101
95 void DocumentMarkerController::addMarker(const Position& start, 102 void DocumentMarkerController::addMarker(const Position& start,
96 const Position& end, 103 const Position& end,
97 DocumentMarker::MarkerType type, 104 DocumentMarker::MarkerType type,
98 const String& description, 105 const String& description,
99 uint32_t hash) { 106 uint32_t hash) {
100 // Use a TextIterator to visit the potentially multiple nodes the range 107 // Use a TextIterator to visit the potentially multiple nodes the range
101 // covers. 108 // covers.
102 for (TextIterator markedText(start, end); !markedText.atEnd(); 109 for (TextIterator markedText(start, end); !markedText.atEnd();
(...skipping 14 matching lines...) Expand all
117 for (TextIterator markedText(range.startPosition(), range.endPosition()); 124 for (TextIterator markedText(range.startPosition(), range.endPosition());
118 !markedText.atEnd(); markedText.advance()) 125 !markedText.atEnd(); markedText.advance())
119 addMarker( 126 addMarker(
120 markedText.currentContainer(), 127 markedText.currentContainer(),
121 DocumentMarker(markedText.startOffsetInCurrentContainer(), 128 DocumentMarker(markedText.startOffsetInCurrentContainer(),
122 markedText.endOffsetInCurrentContainer(), activeMatch)); 129 markedText.endOffsetInCurrentContainer(), activeMatch));
123 // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a 130 // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a
124 // throttling algorithm. crbug.com/6819. 131 // throttling algorithm. crbug.com/6819.
125 } 132 }
126 133
127 void DocumentMarkerController::addCompositionMarker(const Position& start, 134 void DocumentMarkerController::addCompositionMarker(
128 const Position& end, 135 const Position& start,
129 Color underlineColor, 136 const Position& end,
130 bool thick, 137 Color underlineColor,
131 Color backgroundColor) { 138 bool thick,
139 Color backgroundColor,
140 const std::vector<std::string>& suggestions) {
141 DCHECK(!m_document->needsLayoutTreeUpdate());
142 for (TextIterator markedText(start, end); !markedText.atEnd();
143 markedText.advance()) {
144 addMarker(markedText.currentContainer(),
145 DocumentMarker(markedText.startOffsetInCurrentContainer(),
146 markedText.endOffsetInCurrentContainer(),
147 underlineColor, thick, backgroundColor,
148 suggestions, m_nextSuggestionMarkerID++));
149 }
150 }
151
152 void DocumentMarkerController::addSuggestionBackgroundHighlightMarker(
153 const Position& start,
154 const Position& end,
155 Color underlineColor,
156 bool thick,
157 Color backgroundColor) {
132 DCHECK(!m_document->needsLayoutTreeUpdate()); 158 DCHECK(!m_document->needsLayoutTreeUpdate());
133 159
134 for (TextIterator markedText(start, end); !markedText.atEnd(); 160 for (TextIterator markedText(start, end); !markedText.atEnd();
135 markedText.advance()) 161 markedText.advance()) {
136 addMarker(markedText.currentContainer(), 162 addMarker(markedText.currentContainer(),
137 DocumentMarker(markedText.startOffsetInCurrentContainer(), 163 DocumentMarker(DocumentMarker::SuggestionBackgroundHighlight,
164 markedText.startOffsetInCurrentContainer(),
138 markedText.endOffsetInCurrentContainer(), 165 markedText.endOffsetInCurrentContainer(),
139 underlineColor, thick, backgroundColor)); 166 underlineColor, thick, backgroundColor));
167 }
140 } 168 }
141 169
142 void DocumentMarkerController::prepareForDestruction() { 170 void DocumentMarkerController::prepareForDestruction() {
143 clear(); 171 clear();
144 } 172 }
145 173
146 void DocumentMarkerController::removeMarkers( 174 void DocumentMarkerController::removeMarkers(
147 TextIterator& markedText, 175 TextIterator& markedText,
148 DocumentMarker::MarkerTypes markerTypes, 176 DocumentMarker::MarkerTypes markerTypes,
149 RemovePartiallyOverlappingMarkerOrNot 177 RemovePartiallyOverlappingMarkerOrNot
150 shouldRemovePartiallyOverlappingMarker) { 178 shouldRemovePartiallyOverlappingMarker) {
151 for (; !markedText.atEnd(); markedText.advance()) { 179 for (; !markedText.atEnd(); markedText.advance()) {
152 if (!possiblyHasMarkers(markerTypes)) 180 if (!possiblyHasMarkers(markerTypes))
153 return; 181 return;
154 DCHECK(!m_markers.isEmpty()); 182 DCHECK(!m_markers.isEmpty());
155 183
156 int startOffset = markedText.startOffsetInCurrentContainer(); 184 int startOffset = markedText.startOffsetInCurrentContainer();
157 int endOffset = markedText.endOffsetInCurrentContainer(); 185 int endOffset = markedText.endOffsetInCurrentContainer();
158 removeMarkers(markedText.currentContainer(), startOffset, 186 removeMarkers(markedText.currentContainer(), startOffset,
159 endOffset - startOffset, markerTypes, 187 endOffset - startOffset, markerTypes,
160 shouldRemovePartiallyOverlappingMarker); 188 shouldRemovePartiallyOverlappingMarker);
161 } 189 }
190 showMarkers();
162 } 191 }
163 192
164 void DocumentMarkerController::removeMarkers( 193 void DocumentMarkerController::removeMarkers(
165 const EphemeralRange& range, 194 const EphemeralRange& range,
166 DocumentMarker::MarkerTypes markerTypes, 195 DocumentMarker::MarkerTypes markerTypes,
167 RemovePartiallyOverlappingMarkerOrNot 196 RemovePartiallyOverlappingMarkerOrNot
168 shouldRemovePartiallyOverlappingMarker) { 197 shouldRemovePartiallyOverlappingMarker) {
169 DCHECK(!m_document->needsLayoutTreeUpdate()); 198 DCHECK(!m_document->needsLayoutTreeUpdate());
170 199
171 TextIterator markedText(range.startPosition(), range.endPosition()); 200 TextIterator markedText(range.startPosition(), range.endPosition());
172 DocumentMarkerController::removeMarkers( 201 DocumentMarkerController::removeMarkers(
173 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); 202 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
203 showMarkers();
174 } 204 }
175 205
176 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, 206 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv,
177 const DocumentMarker* rhv) { 207 const DocumentMarker* rhv) {
178 return lhv->startOffset() < rhv->startOffset(); 208 return lhv->startOffset() < rhv->startOffset();
179 } 209 }
180 210
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, 211 static bool endsBefore(size_t startOffset,
187 const Member<RenderedDocumentMarker>& rhv) { 212 const Member<RenderedDocumentMarker>& rhv) {
188 return startOffset < rhv->endOffset(); 213 return startOffset < rhv->endOffset();
189 } 214 }
190 215
191 static bool compareByStart(const Member<DocumentMarker>& lhv, 216 static bool compareByStart(const Member<DocumentMarker>& lhv,
192 const Member<DocumentMarker>& rhv) { 217 const Member<DocumentMarker>& rhv) {
193 return lhv->startOffset() < rhv->startOffset(); 218 return lhv->startOffset() < rhv->startOffset();
194 } 219 }
195 220
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 markers->at(markerListIndex) = new MarkerList; 273 markers->at(markerListIndex) = new MarkerList;
249 } 274 }
250 275
251 Member<MarkerList>& list = markers->at(markerListIndex); 276 Member<MarkerList>& list = markers->at(markerListIndex);
252 RenderedDocumentMarker* newRenderedMarker = 277 RenderedDocumentMarker* newRenderedMarker =
253 RenderedDocumentMarker::create(newMarker); 278 RenderedDocumentMarker::create(newMarker);
254 if (list->isEmpty() || list->back()->endOffset() < newMarker.startOffset()) { 279 if (list->isEmpty() || list->back()->endOffset() < newMarker.startOffset()) {
255 list->push_back(newRenderedMarker); 280 list->push_back(newRenderedMarker);
256 } else { 281 } else {
257 if (newMarker.type() != DocumentMarker::TextMatch && 282 if (newMarker.type() != DocumentMarker::TextMatch &&
258 newMarker.type() != DocumentMarker::Composition) { 283 newMarker.type() != DocumentMarker::Composition &&
284 newMarker.type() != DocumentMarker::Suggestion) {
259 mergeOverlapping(list.get(), newRenderedMarker); 285 mergeOverlapping(list.get(), newRenderedMarker);
260 } else { 286 } else {
261 MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(), 287 MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(),
262 &newMarker, startsFurther); 288 &newMarker, startsFurther);
263 list->insert(pos - list->begin(), newRenderedMarker); 289 list->insert(pos - list->begin(), newRenderedMarker);
264 } 290 }
265 } 291 }
266 292
267 // repaint the affected node 293 // repaint the affected node
268 if (node->layoutObject()) 294 if (node->layoutObject())
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 unsigned startOffset, 373 unsigned startOffset,
348 int length, 374 int length,
349 DocumentMarker::MarkerTypes markerTypes, 375 DocumentMarker::MarkerTypes markerTypes,
350 RemovePartiallyOverlappingMarkerOrNot 376 RemovePartiallyOverlappingMarkerOrNot
351 shouldRemovePartiallyOverlappingMarker) { 377 shouldRemovePartiallyOverlappingMarker) {
352 if (length <= 0) 378 if (length <= 0)
353 return; 379 return;
354 380
355 if (!possiblyHasMarkers(markerTypes)) 381 if (!possiblyHasMarkers(markerTypes))
356 return; 382 return;
383
357 DCHECK(!(m_markers.isEmpty())); 384 DCHECK(!(m_markers.isEmpty()));
358 385
359 MarkerLists* markers = m_markers.get(node); 386 MarkerLists* markers = m_markers.get(node);
360 if (!markers) 387 if (!markers)
361 return; 388 return;
362 389
363 bool docDirty = false; 390 bool docDirty = false;
364 size_t emptyListsCount = 0; 391 size_t emptyListsCount = 0;
365 for (size_t markerListIndex = 0; 392 for (size_t markerListIndex = 0;
366 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 393 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 450
424 if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) { 451 if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) {
425 m_markers.remove(node); 452 m_markers.remove(node);
426 if (m_markers.isEmpty()) 453 if (m_markers.isEmpty())
427 m_possiblyExistingMarkerTypes = 0; 454 m_possiblyExistingMarkerTypes = 0;
428 } 455 }
429 456
430 // repaint the affected node 457 // repaint the affected node
431 if (docDirty && node->layoutObject()) 458 if (docDirty && node->layoutObject())
432 node->layoutObject()->setShouldDoFullPaintInvalidation(); 459 node->layoutObject()->setShouldDoFullPaintInvalidation();
460
461 showMarkers();
433 } 462 }
434 463
435 DocumentMarkerVector DocumentMarkerController::markersFor( 464 DocumentMarkerVector DocumentMarkerController::markersFor(
436 Node* node, 465 Node* node,
437 DocumentMarker::MarkerTypes markerTypes) { 466 DocumentMarker::MarkerTypes markerTypes) {
438 DocumentMarkerVector result; 467 DocumentMarkerVector result;
439 468
440 MarkerLists* markers = m_markers.get(node); 469 MarkerLists* markers = m_markers.get(node);
441 if (!markers) 470 if (!markers)
442 return result; 471 return result;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 504
476 DocumentMarkerVector DocumentMarkerController::markersInRange( 505 DocumentMarkerVector DocumentMarkerController::markersInRange(
477 const EphemeralRange& range, 506 const EphemeralRange& range,
478 DocumentMarker::MarkerTypes markerTypes) { 507 DocumentMarker::MarkerTypes markerTypes) {
479 if (!possiblyHasMarkers(markerTypes)) 508 if (!possiblyHasMarkers(markerTypes))
480 return DocumentMarkerVector(); 509 return DocumentMarkerVector();
481 510
482 DocumentMarkerVector foundMarkers; 511 DocumentMarkerVector foundMarkers;
483 512
484 Node* startContainer = range.startPosition().computeContainerNode(); 513 Node* startContainer = range.startPosition().computeContainerNode();
485 DCHECK(startContainer); 514 if (!startContainer)
515 return DocumentMarkerVector();
516
486 unsigned startOffset = static_cast<unsigned>( 517 unsigned startOffset = static_cast<unsigned>(
487 range.startPosition().computeOffsetInContainerNode()); 518 range.startPosition().computeOffsetInContainerNode());
519
488 Node* endContainer = range.endPosition().computeContainerNode(); 520 Node* endContainer = range.endPosition().computeContainerNode();
489 DCHECK(endContainer); 521 if (!endContainer)
522 return DocumentMarkerVector();
523
490 unsigned endOffset = 524 unsigned endOffset =
491 static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode()); 525 static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode());
492 526
527 // For zero-length ranges, include spans whose endpoints touch the range
aelias_OOO_until_Jul13 2017/01/25 03:34:27 That's not very principled. I'd prefer you introd
rlanday 2017/01/25 18:48:10 That's a good idea; I got the idea to do it the wa
528 // location
529 bool isZeroLengthRange =
530 (startContainer == endContainer) && (startOffset == endOffset);
531
493 for (Node& node : range.nodes()) { 532 for (Node& node : range.nodes()) {
494 for (DocumentMarker* marker : markersFor(&node)) { 533 for (DocumentMarker* marker : markersFor(&node)) {
495 if (!markerTypes.contains(marker->type())) 534 if (!markerTypes.contains(marker->type()))
496 continue; 535 continue;
497 if (node == startContainer && marker->endOffset() <= startOffset) 536 if (node == startContainer) {
498 continue; 537 if (marker->endOffset() < startOffset ||
499 if (node == endContainer && marker->startOffset() >= endOffset) 538 (marker->endOffset() == startOffset && !isZeroLengthRange))
500 continue; 539 continue;
540 }
541 if (node == endContainer) {
542 if (marker->startOffset() > endOffset ||
543 (marker->startOffset() == endOffset && !isZeroLengthRange))
544 continue;
545 }
501 foundMarkers.push_back(marker); 546 foundMarkers.push_back(marker);
502 } 547 }
503 } 548 }
504 return foundMarkers; 549 return foundMarkers;
505 } 550 }
506 551
507 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers( 552 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(
508 DocumentMarker::MarkerType markerType) { 553 DocumentMarker::MarkerType markerType) {
509 Vector<IntRect> result; 554 Vector<IntRect> result;
510 555
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 void DocumentMarkerController::removeMarkers( 638 void DocumentMarkerController::removeMarkers(
594 Node* node, 639 Node* node,
595 DocumentMarker::MarkerTypes markerTypes) { 640 DocumentMarker::MarkerTypes markerTypes) {
596 if (!possiblyHasMarkers(markerTypes)) 641 if (!possiblyHasMarkers(markerTypes))
597 return; 642 return;
598 DCHECK(!m_markers.isEmpty()); 643 DCHECK(!m_markers.isEmpty());
599 644
600 MarkerMap::iterator iterator = m_markers.find(node); 645 MarkerMap::iterator iterator = m_markers.find(node);
601 if (iterator != m_markers.end()) 646 if (iterator != m_markers.end())
602 removeMarkersFromList(iterator, markerTypes); 647 removeMarkersFromList(iterator, markerTypes);
648
649 showMarkers();
603 } 650 }
604 651
605 void DocumentMarkerController::removeMarkers( 652 void DocumentMarkerController::removeMarkers(
606 const MarkerRemoverPredicate& shouldRemoveMarker) { 653 const MarkerRemoverPredicate& shouldRemoveMarker) {
607 for (auto& nodeMarkers : m_markers) { 654 for (auto& nodeMarkers : m_markers) {
608 const Node& node = *nodeMarkers.key; 655 const Node& node = *nodeMarkers.key;
609 if (!node.isTextNode()) // MarkerRemoverPredicate requires a Text node. 656 if (!node.isTextNode()) // MarkerRemoverPredicate requires a Text node.
610 continue; 657 continue;
611 MarkerLists& markers = *nodeMarkers.value; 658 MarkerLists& markers = *nodeMarkers.value;
612 for (size_t markerListIndex = 0; 659 for (size_t markerListIndex = 0;
613 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 660 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
614 ++markerListIndex) { 661 ++markerListIndex) {
615 Member<MarkerList>& list = markers[markerListIndex]; 662 Member<MarkerList>& list = markers[markerListIndex];
616 if (!list) 663 if (!list)
617 continue; 664 continue;
618 bool removedMarkers = false; 665 bool removedMarkers = false;
619 for (size_t j = list->size(); j > 0; --j) { 666 for (size_t j = list->size(); j > 0; --j) {
620 if (shouldRemoveMarker(*list->at(j - 1), 667 if (shouldRemoveMarker(*list->at(j - 1),
621 static_cast<const Text&>(node))) { 668 static_cast<const Text&>(node))) {
622 list->remove(j - 1); 669 list->remove(j - 1);
623 removedMarkers = true; 670 removedMarkers = true;
624 } 671 }
625 } 672 }
626 if (removedMarkers && 673 if (removedMarkers &&
627 markerListIndex == DocumentMarker::TextMatchMarkerIndex) 674 markerListIndex == DocumentMarker::TextMatchMarkerIndex)
628 invalidatePaintForTickmarks(node); 675 invalidatePaintForTickmarks(node);
629 } 676 }
630 } 677 }
678
679 showMarkers();
631 } 680 }
632 681
633 void DocumentMarkerController::removeMarkers( 682 void DocumentMarkerController::removeMarkers(
634 DocumentMarker::MarkerTypes markerTypes) { 683 DocumentMarker::MarkerTypes markerTypes) {
635 if (!possiblyHasMarkers(markerTypes)) 684 if (!possiblyHasMarkers(markerTypes))
636 return; 685 return;
637 DCHECK(!m_markers.isEmpty()); 686 DCHECK(!m_markers.isEmpty());
638 687
639 HeapVector<Member<const Node>> nodesWithMarkers; 688 HeapVector<Member<const Node>> nodesWithMarkers;
640 copyKeysToVector(m_markers, nodesWithMarkers); 689 copyKeysToVector(m_markers, nodesWithMarkers);
641 unsigned size = nodesWithMarkers.size(); 690 unsigned size = nodesWithMarkers.size();
642 for (unsigned i = 0; i < size; ++i) { 691 for (unsigned i = 0; i < size; ++i) {
643 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]); 692 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]);
644 if (iterator != m_markers.end()) 693 if (iterator != m_markers.end())
645 removeMarkersFromList(iterator, markerTypes); 694 removeMarkersFromList(iterator, markerTypes);
646 } 695 }
647 696
648 m_possiblyExistingMarkerTypes.remove(markerTypes); 697 m_possiblyExistingMarkerTypes.remove(markerTypes);
698
699 showMarkers();
700 }
701
702 void DocumentMarkerController::removeSuggestionMarkersByID(
703 const Vector<int>& idsToRemove) {
704 for (auto& nodeMarkers : m_markers) {
705 MarkerLists& markers = *nodeMarkers.value;
706 Member<MarkerList>& suggestionMarkerList =
707 markers[DocumentMarker::SuggestionMarkerIndex];
708 if (!suggestionMarkerList)
709 continue;
710 bool removedMarkers = false;
711 for (size_t j = suggestionMarkerList->size(); j > 0; --j) {
712 if (idsToRemove.contains(
713 suggestionMarkerList->at(j - 1)->suggestionMarkerID())) {
714 suggestionMarkerList->remove(j - 1);
715 removedMarkers = true;
716 }
717 }
718 }
649 } 719 }
650 720
651 void DocumentMarkerController::removeMarkersFromList( 721 void DocumentMarkerController::removeMarkersFromList(
652 MarkerMap::iterator iterator, 722 MarkerMap::iterator iterator,
653 DocumentMarker::MarkerTypes markerTypes) { 723 DocumentMarker::MarkerTypes markerTypes) {
654 bool needsRepainting = false; 724 bool needsRepainting = false;
655 bool nodeCanBeRemoved; 725 bool nodeCanBeRemoved;
656 726
657 size_t emptyListsCount = 0; 727 size_t emptyListsCount = 0;
658 if (markerTypes == DocumentMarker::AllMarkers()) { 728 if (markerTypes == DocumentMarker::AllMarkers()) {
(...skipping 29 matching lines...) Expand all
688 if (LayoutObject* layoutObject = node.layoutObject()) 758 if (LayoutObject* layoutObject = node.layoutObject())
689 layoutObject->setShouldDoFullPaintInvalidation(); 759 layoutObject->setShouldDoFullPaintInvalidation();
690 invalidatePaintForTickmarks(node); 760 invalidatePaintForTickmarks(node);
691 } 761 }
692 762
693 if (nodeCanBeRemoved) { 763 if (nodeCanBeRemoved) {
694 m_markers.remove(iterator); 764 m_markers.remove(iterator);
695 if (m_markers.isEmpty()) 765 if (m_markers.isEmpty())
696 m_possiblyExistingMarkerTypes = 0; 766 m_possiblyExistingMarkerTypes = 0;
697 } 767 }
768
769 showMarkers();
698 } 770 }
699 771
700 void DocumentMarkerController::repaintMarkers( 772 void DocumentMarkerController::repaintMarkers(
701 DocumentMarker::MarkerTypes markerTypes) { 773 DocumentMarker::MarkerTypes markerTypes) {
702 if (!possiblyHasMarkers(markerTypes)) 774 if (!possiblyHasMarkers(markerTypes))
703 return; 775 return;
704 DCHECK(!m_markers.isEmpty()); 776 DCHECK(!m_markers.isEmpty());
705 777
706 // outer loop: process each markered node in the document 778 // outer loop: process each markered node in the document
707 MarkerMap::iterator end = m_markers.end(); 779 MarkerMap::iterator end = m_markers.end();
(...skipping 13 matching lines...) Expand all
721 // cause the node to be redrawn 793 // cause the node to be redrawn
722 if (LayoutObject* layoutObject = node->layoutObject()) { 794 if (LayoutObject* layoutObject = node->layoutObject()) {
723 layoutObject->setShouldDoFullPaintInvalidation(); 795 layoutObject->setShouldDoFullPaintInvalidation();
724 break; 796 break;
725 } 797 }
726 } 798 }
727 } 799 }
728 } 800 }
729 801
730 void DocumentMarkerController::shiftMarkers(Node* node, 802 void DocumentMarkerController::shiftMarkers(Node* node,
731 unsigned startOffset, 803 int startOffset,
732 int delta) { 804 int prevLength,
805 int newLength) {
806 DCHECK_GE(startOffset, 0);
807 DCHECK_GE(prevLength, 0);
808 DCHECK_GE(newLength, 0);
809
733 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 810 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
734 return; 811 return;
735 DCHECK(!m_markers.isEmpty()); 812 DCHECK(!m_markers.isEmpty());
736 813
737 MarkerLists* markers = m_markers.get(node); 814 MarkerLists* markers = m_markers.get(node);
738 if (!markers) 815 if (!markers)
739 return; 816 return;
740 817
741 bool didShiftMarker = false; 818 bool didShiftMarker = false;
742 for (size_t markerListIndex = 0; 819 for (size_t markerListIndex = 0;
743 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 820 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
744 ++markerListIndex) { 821 ++markerListIndex) {
745 Member<MarkerList>& list = (*markers)[markerListIndex]; 822 Member<MarkerList>& list = (*markers)[markerListIndex];
746 if (!list) 823 if (!list)
747 continue; 824 continue;
748 MarkerList::iterator startPos = 825
749 std::lower_bound(list->begin(), list->end(), startOffset, startsAfter); 826 // algorithm from https://dom.spec.whatwg.org/#concept-cd-replace
750 for (MarkerList::iterator marker = startPos; marker != list->end(); 827 for (MarkerList::iterator marker = list->begin(); marker != list->end();
751 ++marker) { 828 ++marker) {
752 #if DCHECK_IS_ON() 829 if ((*marker)->startOffset() > (unsigned)startOffset) {
753 int startOffset = (*marker)->startOffset(); 830 if ((*marker)->startOffset() <= (unsigned)(startOffset + prevLength)) {
754 DCHECK_GE(startOffset + delta, 0); 831 // Marker start was in the replaced text. Move to beginning of new
755 #endif 832 // text
756 (*marker)->shiftOffsets(delta); 833 (*marker)->setStartOffset(startOffset);
834 } else {
835 // Marker start was after the replaced text. Shift by length
836 // difference
837 unsigned oldStartOffset = (*marker)->startOffset();
838 (*marker)->setStartOffset(oldStartOffset + newLength - prevLength);
839 }
840 }
841
842 if ((*marker)->endOffset() > (unsigned)startOffset) {
843 if ((*marker)->endOffset() <= (unsigned)(startOffset + prevLength)) {
844 // Marker end was in the replaced text. Move to beginning of new text
845 (*marker)->setEndOffset(startOffset);
846 } else {
847 // Marker end was after the replaced text. Shift by length difference
848 unsigned oldEndOffset = (*marker)->endOffset();
849 (*marker)->setEndOffset(oldEndOffset + newLength - prevLength);
850 }
851 }
852
757 didShiftMarker = true; 853 didShiftMarker = true;
758 } 854 }
759 } 855 }
760 856
761 if (didShiftMarker) { 857 if (didShiftMarker) {
762 invalidateRectsForMarkersInNode(*node); 858 invalidateRectsForMarkersInNode(*node);
763 // repaint the affected node 859 // repaint the affected node
764 if (node->layoutObject()) 860 if (node->layoutObject())
765 node->layoutObject()->setShouldDoFullPaintInvalidation(); 861 node->layoutObject()->setShouldDoFullPaintInvalidation();
766 } 862 }
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 #endif 955 #endif
860 956
861 } // namespace blink 957 } // namespace blink
862 958
863 #ifndef NDEBUG 959 #ifndef NDEBUG
864 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { 960 void showDocumentMarkers(const blink::DocumentMarkerController* controller) {
865 if (controller) 961 if (controller)
866 controller->showMarkers(); 962 controller->showMarkers();
867 } 963 }
868 #endif 964 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698