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 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 |