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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |