| 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 15 matching lines...) Expand all Loading... |
| 26 * | 26 * |
| 27 */ | 27 */ |
| 28 | 28 |
| 29 #include "core/editing/markers/DocumentMarkerController.h" | 29 #include "core/editing/markers/DocumentMarkerController.h" |
| 30 | 30 |
| 31 #include <algorithm> | 31 #include <algorithm> |
| 32 #include "core/dom/Node.h" | 32 #include "core/dom/Node.h" |
| 33 #include "core/dom/NodeTraversal.h" | 33 #include "core/dom/NodeTraversal.h" |
| 34 #include "core/dom/Range.h" | 34 #include "core/dom/Range.h" |
| 35 #include "core/dom/Text.h" | 35 #include "core/dom/Text.h" |
| 36 #include "core/editing/FrameSelection.h" |
| 36 #include "core/editing/iterators/TextIterator.h" | 37 #include "core/editing/iterators/TextIterator.h" |
| 37 #include "core/editing/markers/CompositionMarker.h" | 38 #include "core/editing/markers/CompositionMarker.h" |
| 38 #include "core/editing/markers/CompositionMarkerList.h" | 39 #include "core/editing/markers/CompositionMarkerList.h" |
| 39 #include "core/editing/markers/DocumentMarkerList.h" | 40 #include "core/editing/markers/DocumentMarkerList.h" |
| 40 #include "core/editing/markers/EditingMarkerList.h" | 41 #include "core/editing/markers/EditingMarkerList.h" |
| 41 #include "core/editing/markers/SpellCheckMarker.h" | 42 #include "core/editing/markers/SpellCheckMarker.h" |
| 42 #include "core/editing/markers/SpellCheckMarkerList.h" | 43 #include "core/editing/markers/SpellCheckMarkerList.h" |
| 44 #include "core/editing/markers/SuggestionHighlightMarker.h" |
| 45 #include "core/editing/markers/SuggestionHighlightMarkerList.h" |
| 46 #include "core/editing/markers/SuggestionMarkerList.h" |
| 43 #include "core/editing/markers/TextMatchMarkerList.h" | 47 #include "core/editing/markers/TextMatchMarkerList.h" |
| 44 #include "core/frame/FrameView.h" | 48 #include "core/frame/FrameView.h" |
| 49 #include "core/frame/LocalFrame.h" |
| 45 #include "core/layout/LayoutObject.h" | 50 #include "core/layout/LayoutObject.h" |
| 46 | 51 |
| 47 #ifndef NDEBUG | 52 #ifndef NDEBUG |
| 48 #include <stdio.h> | 53 #include <stdio.h> |
| 49 #endif | 54 #endif |
| 50 | 55 |
| 51 namespace blink { | 56 namespace blink { |
| 52 | 57 |
| 53 DocumentMarkerController::DocumentMarkerController(Document& document) | 58 DocumentMarkerController::DocumentMarkerController(Document& document) |
| 54 : m_document(&document) { | 59 : m_document(&document) { |
| 55 setContext(&document); | 60 setContext(&document); |
| 56 } | 61 } |
| 57 | 62 |
| 58 void DocumentMarkerController::clear() { | 63 void DocumentMarkerController::clear() { |
| 59 for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) { | 64 for (DocumentMarker::MarkerType type : DocumentMarker::AllMarkers()) { |
| 60 MarkerMap& markerMap = markerMapForType(type); | 65 MarkerMap& markerMap = markerMapForType(type); |
| 61 markerMap.clear(); | 66 markerMap.clear(); |
| 62 } | 67 } |
| 68 |
| 69 // Don't reset m_nextSuggestionMarkerID so if anything is still holding |
| 70 // onto an old ID, it won't get confused by new markers |
| 63 } | 71 } |
| 64 | 72 |
| 65 void DocumentMarkerController::addGrammarOrSpellingMarker( | 73 void DocumentMarkerController::addGrammarOrSpellingMarker( |
| 66 const EphemeralRange& range, | 74 const EphemeralRange& range, |
| 67 DocumentMarker::MarkerType type, | 75 DocumentMarker::MarkerType type, |
| 68 const String& description) { | 76 const String& description) { |
| 69 DCHECK(!m_document->needsLayoutTreeUpdate()); | 77 DCHECK(!m_document->needsLayoutTreeUpdate()); |
| 70 DCHECK(type == DocumentMarker::Grammar || type == DocumentMarker::Spelling) | 78 DCHECK(type == DocumentMarker::Grammar || type == DocumentMarker::Spelling) |
| 71 << type; | 79 << type; |
| 72 // Use a TextIterator to visit the potentially multiple nodes the range | 80 // Use a TextIterator to visit the potentially multiple nodes the range |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 | 124 |
| 117 for (TextIterator markedText(range.startPosition(), range.endPosition()); | 125 for (TextIterator markedText(range.startPosition(), range.endPosition()); |
| 118 !markedText.atEnd(); markedText.advance()) { | 126 !markedText.atEnd(); markedText.advance()) { |
| 119 addMarker(markedText.currentContainer(), | 127 addMarker(markedText.currentContainer(), |
| 120 new CompositionMarker(markedText.startOffsetInCurrentContainer(), | 128 new CompositionMarker(markedText.startOffsetInCurrentContainer(), |
| 121 markedText.endOffsetInCurrentContainer(), | 129 markedText.endOffsetInCurrentContainer(), |
| 122 underlineColor, thick, backgroundColor)); | 130 underlineColor, thick, backgroundColor)); |
| 123 } | 131 } |
| 124 } | 132 } |
| 125 | 133 |
| 134 void DocumentMarkerController::addSuggestionMarker(const EphemeralRange& range, |
| 135 Color underlineColor, |
| 136 bool thick, |
| 137 Color backgroundColor, |
| 138 const Vector<String>& suggest
ions) { |
| 139 DCHECK(!m_document->needsLayoutTreeUpdate()); |
| 140 |
| 141 for (TextIterator markedText(range.startPosition(), range.endPosition()); |
| 142 !markedText.atEnd(); markedText.advance()) { |
| 143 addMarker(markedText.currentContainer(), |
| 144 new SuggestionMarker( |
| 145 markedText.startOffsetInCurrentContainer(), |
| 146 markedText.endOffsetInCurrentContainer(), underlineColor, |
| 147 thick, backgroundColor, suggestions, m_nextSuggestionMarkerID+
+)); |
| 148 } |
| 149 } |
| 150 |
| 151 void DocumentMarkerController::addSuggestionHighlightMarker( |
| 152 const EphemeralRange& range, |
| 153 Color underlineColor, |
| 154 bool thick, |
| 155 Color backgroundColor) { |
| 156 DCHECK(!m_document->needsLayoutTreeUpdate()); |
| 157 |
| 158 for (TextIterator markedText(range.startPosition(), range.endPosition()); |
| 159 !markedText.atEnd(); markedText.advance()) { |
| 160 addMarker(markedText.currentContainer(), |
| 161 new SuggestionHighlightMarker( |
| 162 markedText.startOffsetInCurrentContainer(), |
| 163 markedText.endOffsetInCurrentContainer(), |
| 164 underlineColor, |
| 165 thick, backgroundColor)); |
| 166 } |
| 167 } |
| 168 |
| 126 void DocumentMarkerController::prepareForDestruction() { | 169 void DocumentMarkerController::prepareForDestruction() { |
| 127 clear(); | 170 clear(); |
| 128 } | 171 } |
| 129 | 172 |
| 130 void DocumentMarkerController::removeMarkers( | 173 void DocumentMarkerController::removeMarkers( |
| 131 const EphemeralRange& range, | 174 const EphemeralRange& range, |
| 132 DocumentMarker::MarkerTypes markerTypes, | 175 DocumentMarker::MarkerTypes markerTypes, |
| 133 RemovePartiallyOverlappingMarkerOrNot | 176 RemovePartiallyOverlappingMarkerOrNot |
| 134 shouldRemovePartiallyOverlappingMarker) { | 177 shouldRemovePartiallyOverlappingMarker) { |
| 135 DCHECK(!m_document->needsLayoutTreeUpdate()); | 178 DCHECK(!m_document->needsLayoutTreeUpdate()); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 PaintInvalidationDocumentMarkerChange); | 248 PaintInvalidationDocumentMarkerChange); |
| 206 } | 249 } |
| 207 } | 250 } |
| 208 | 251 |
| 209 void DocumentMarkerController::removeMarkers( | 252 void DocumentMarkerController::removeMarkers( |
| 210 Node* node, | 253 Node* node, |
| 211 unsigned startOffset, | 254 unsigned startOffset, |
| 212 int length, | 255 int length, |
| 213 DocumentMarker::MarkerTypes markerTypes, | 256 DocumentMarker::MarkerTypes markerTypes, |
| 214 RemovePartiallyOverlappingMarkerOrNot | 257 RemovePartiallyOverlappingMarkerOrNot |
| 215 shouldRemovePartiallyOverlappingMarker) { | 258 shouldRemovePartiallyOverlappingMarker) { |
| 216 if (length <= 0) | 259 if (length <= 0) |
| 217 return; | 260 return; |
| 218 | 261 |
| 219 bool docDirty = false; | 262 bool docDirty = false; |
| 220 for (DocumentMarker::MarkerType type : markerTypes) { | 263 for (DocumentMarker::MarkerType type : markerTypes) { |
| 221 MarkerMap& markerMap = markerMapForType(type); | 264 MarkerMap& markerMap = markerMapForType(type); |
| 222 auto it = markerMap.find(node); | 265 auto it = markerMap.find(node); |
| 223 if (it != markerMap.end()) { | 266 if (it != markerMap.end()) { |
| 224 docDirty = | 267 docDirty = |
| 225 (it->value->removeMarkers(startOffset, length, | 268 (it->value->removeMarkers(startOffset, length, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 it->value->appendMarkersToInputList(&result); | 303 it->value->appendMarkersToInputList(&result); |
| 261 } | 304 } |
| 262 | 305 |
| 263 std::sort(result.begin(), result.end(), compareByStart); | 306 std::sort(result.begin(), result.end(), compareByStart); |
| 264 return result; | 307 return result; |
| 265 } | 308 } |
| 266 | 309 |
| 267 DocumentMarkerVector DocumentMarkerController::markersInRange( | 310 DocumentMarkerVector DocumentMarkerController::markersInRange( |
| 268 const EphemeralRange& range, | 311 const EphemeralRange& range, |
| 269 DocumentMarker::MarkerTypes markerTypes) { | 312 DocumentMarker::MarkerTypes markerTypes) { |
| 313 return markersInRangeInternal(range, markerTypes, false); |
| 314 } |
| 270 | 315 |
| 316 DocumentMarkerVector DocumentMarkerController::markersInRangeInclusive( |
| 317 const EphemeralRange& range, |
| 318 DocumentMarker::MarkerTypes markerTypes) { |
| 319 return markersInRangeInternal(range, markerTypes, true); |
| 320 } |
| 321 |
| 322 DocumentMarkerVector DocumentMarkerController::markersInRangeInternal( |
| 323 const EphemeralRange& range, |
| 324 DocumentMarker::MarkerTypes markerTypes, |
| 325 bool includeSpansTouchingEndpoints) { |
| 271 DocumentMarkerVector foundMarkers; | 326 DocumentMarkerVector foundMarkers; |
| 272 | 327 |
| 273 Node* startContainer = range.startPosition().computeContainerNode(); | 328 Node* startContainer = range.startPosition().computeContainerNode(); |
| 274 DCHECK(startContainer); | 329 if (!startContainer) |
| 330 return DocumentMarkerVector(); |
| 331 |
| 275 unsigned startOffset = static_cast<unsigned>( | 332 unsigned startOffset = static_cast<unsigned>( |
| 276 range.startPosition().computeOffsetInContainerNode()); | 333 range.startPosition().computeOffsetInContainerNode()); |
| 334 |
| 277 Node* endContainer = range.endPosition().computeContainerNode(); | 335 Node* endContainer = range.endPosition().computeContainerNode(); |
| 278 DCHECK(endContainer); | 336 if (!endContainer) |
| 337 return DocumentMarkerVector(); |
| 338 |
| 279 unsigned endOffset = | 339 unsigned endOffset = |
| 280 static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode()); | 340 static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode()); |
| 281 | 341 |
| 282 for (Node& node : range.nodes()) { | 342 for (Node& node : range.nodes()) { |
| 283 for (DocumentMarker* marker : markersFor(&node)) { | 343 for (DocumentMarker* marker : markersFor(&node)) { |
| 284 if (!markerTypes.contains(marker->type())) | 344 if (!markerTypes.contains(marker->type())) |
| 285 continue; | 345 continue; |
| 286 if (node == startContainer && marker->endOffset() <= startOffset) | 346 if (node == startContainer) { |
| 287 continue; | 347 if (marker->endOffset() < startOffset || |
| 288 if (node == endContainer && marker->startOffset() >= endOffset) | 348 (marker->endOffset() == startOffset && |
| 289 continue; | 349 !includeSpansTouchingEndpoints)) |
| 350 continue; |
| 351 } |
| 352 if (node == endContainer) { |
| 353 if (marker->startOffset() > endOffset || |
| 354 (marker->startOffset() == endOffset && |
| 355 !includeSpansTouchingEndpoints)) |
| 356 continue; |
| 357 } |
| 290 foundMarkers.push_back(marker); | 358 foundMarkers.push_back(marker); |
| 291 } | 359 } |
| 292 } | 360 } |
| 293 return foundMarkers; | 361 return foundMarkers; |
| 294 } | 362 } |
| 295 | 363 |
| 296 Vector<IntRect> DocumentMarkerController::renderedRectsForTextMatchMarkers() { | 364 Vector<IntRect> DocumentMarkerController::renderedRectsForTextMatchMarkers() { |
| 297 Vector<IntRect> result; | 365 Vector<IntRect> result; |
| 298 for (auto nodeIterator = m_textMatches.begin(); | 366 for (auto nodeIterator = m_textMatches.begin(); |
| 299 nodeIterator != m_textMatches.end(); ++nodeIterator) { | 367 nodeIterator != m_textMatches.end(); ++nodeIterator) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 for (auto& nodeMarkers : m_textMatches) | 399 for (auto& nodeMarkers : m_textMatches) |
| 332 invalidateRectsForTextMatchMarkersInNode(*nodeMarkers.key); | 400 invalidateRectsForTextMatchMarkersInNode(*nodeMarkers.key); |
| 333 } | 401 } |
| 334 | 402 |
| 335 DEFINE_TRACE(DocumentMarkerController) { | 403 DEFINE_TRACE(DocumentMarkerController) { |
| 336 visitor->trace(m_spelling); | 404 visitor->trace(m_spelling); |
| 337 visitor->trace(m_grammar); | 405 visitor->trace(m_grammar); |
| 338 visitor->trace(m_textMatches); | 406 visitor->trace(m_textMatches); |
| 339 visitor->trace(m_compositions); | 407 visitor->trace(m_compositions); |
| 340 visitor->trace(m_document); | 408 visitor->trace(m_document); |
| 409 visitor->trace(m_suggestions); |
| 410 visitor->trace(m_suggestionHighlights); |
| 341 SynchronousMutationObserver::trace(visitor); | 411 SynchronousMutationObserver::trace(visitor); |
| 342 } | 412 } |
| 343 | 413 |
| 344 void DocumentMarkerController::removeMarkers( | 414 void DocumentMarkerController::removeMarkers( |
| 345 Node* node, | 415 Node* node, |
| 346 DocumentMarker::MarkerTypes markerTypes) { | 416 DocumentMarker::MarkerTypes markerTypes) { |
| 347 for (DocumentMarker::MarkerType type : markerTypes) { | 417 for (DocumentMarker::MarkerType type : markerTypes) { |
| 348 MarkerMap& markerMap = markerMapForType(type); | 418 MarkerMap& markerMap = markerMapForType(type); |
| 349 markerMap.erase(node); | 419 markerMap.erase(node); |
| 350 } | 420 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 362 const Vector<String>& words) { | 432 const Vector<String>& words) { |
| 363 for (auto& nodeMarkers : m_spelling) { | 433 for (auto& nodeMarkers : m_spelling) { |
| 364 const Node& node = *nodeMarkers.key; | 434 const Node& node = *nodeMarkers.key; |
| 365 if (!node.isTextNode()) | 435 if (!node.isTextNode()) |
| 366 continue; | 436 continue; |
| 367 toSpellCheckMarkerList(nodeMarkers.value.get()) | 437 toSpellCheckMarkerList(nodeMarkers.value.get()) |
| 368 ->removeMarkersForWords(static_cast<const Text&>(node).data(), words); | 438 ->removeMarkersForWords(static_cast<const Text&>(node).data(), words); |
| 369 } | 439 } |
| 370 } | 440 } |
| 371 | 441 |
| 442 void DocumentMarkerController::removeMarkersForWordsAffectedByEditing( |
| 443 DocumentMarker::MarkerTypes markerTypes, |
| 444 bool doNotRemoveIfSelectionAtWordBoundary) { |
| 445 LOG(INFO) << "removeMarkersForWordsAffectedByEditing: " << doNotRemoveIfSelect
ionAtWordBoundary; |
| 446 LOG(INFO) << "clearing suggestion markers: " << markerTypes.contains(DocumentM
arker::Suggestion); |
| 447 DCHECK(m_document->frame()->selection().isAvailable()); |
| 448 TRACE_EVENT0( |
| 449 "blink", |
| 450 "DocumentMarkerController::removeMarkersForWordsAffectedByEditing"); |
| 451 |
| 452 Document* document = m_document->frame()->document(); |
| 453 DCHECK(document); |
| 454 |
| 455 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| 456 // needs to be audited. See http://crbug.com/590369 for more details. |
| 457 document->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 458 |
| 459 // We want to remove the markers from a word if an editing command will change |
| 460 // the word. This can happen in one of several scenarios: |
| 461 // 1. Insert in the middle of a word. |
| 462 // 2. Appending non whitespace at the beginning of word. |
| 463 // 3. Appending non whitespace at the end of word. |
| 464 // Note that, appending only whitespaces at the beginning or end of word won't |
| 465 // change the word, so we don't need to remove the markers on that word. Of |
| 466 // course, if current selection is a range, we potentially will edit two words |
| 467 // that fall on the boundaries of selection, and remove words between the |
| 468 // selection boundaries. |
| 469 VisiblePosition startOfSelection = m_document->frame() |
| 470 ->selection() |
| 471 .computeVisibleSelectionInDOMTree() |
| 472 .visibleStart(); |
| 473 VisiblePosition endOfSelection = m_document->frame() |
| 474 ->selection() |
| 475 .computeVisibleSelectionInDOMTree() |
| 476 .visibleEnd(); |
| 477 if (startOfSelection.isNull()) |
| 478 return; |
| 479 // First word is the word that ends after or on the start of selection. |
| 480 VisiblePosition startOfFirstWord = |
| 481 startOfWord(startOfSelection, LeftWordIfOnBoundary); |
| 482 VisiblePosition endOfFirstWord = |
| 483 endOfWord(startOfSelection, LeftWordIfOnBoundary); |
| 484 // Last word is the word that begins before or on the end of selection |
| 485 VisiblePosition startOfLastWord = |
| 486 startOfWord(endOfSelection, RightWordIfOnBoundary); |
| 487 VisiblePosition endOfLastWord = |
| 488 endOfWord(endOfSelection, RightWordIfOnBoundary); |
| 489 |
| 490 if (startOfFirstWord.isNull()) { |
| 491 startOfFirstWord = startOfWord(startOfSelection, RightWordIfOnBoundary); |
| 492 endOfFirstWord = endOfWord(startOfSelection, RightWordIfOnBoundary); |
| 493 } |
| 494 |
| 495 if (endOfLastWord.isNull()) { |
| 496 startOfLastWord = startOfWord(endOfSelection, LeftWordIfOnBoundary); |
| 497 endOfLastWord = endOfWord(endOfSelection, LeftWordIfOnBoundary); |
| 498 } |
| 499 |
| 500 // If doNotRemoveIfSelectionAtWordBoundary is true, and first word ends at the |
| 501 // start of selection, we choose next word as the first word. |
| 502 if (doNotRemoveIfSelectionAtWordBoundary && |
| 503 endOfFirstWord.deepEquivalent() == startOfSelection.deepEquivalent()) { |
| 504 startOfFirstWord = nextWordPosition(startOfFirstWord); |
| 505 endOfFirstWord = endOfWord(startOfFirstWord, RightWordIfOnBoundary); |
| 506 if (startOfFirstWord.deepEquivalent() == endOfSelection.deepEquivalent()) |
| 507 return; |
| 508 } |
| 509 |
| 510 // If doNotRemoveIfSelectionAtWordBoundary is true, and last word begins at |
| 511 // the end of selection, we choose previous word as the last word. |
| 512 if (doNotRemoveIfSelectionAtWordBoundary && |
| 513 startOfLastWord.deepEquivalent() == endOfSelection.deepEquivalent()) { |
| 514 startOfLastWord = previousWordPosition(startOfLastWord); |
| 515 endOfLastWord = endOfWord(startOfLastWord, RightWordIfOnBoundary); |
| 516 if (endOfLastWord.deepEquivalent() == startOfSelection.deepEquivalent()) |
| 517 return; |
| 518 } |
| 519 |
| 520 if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || |
| 521 startOfLastWord.isNull() || endOfLastWord.isNull()) |
| 522 return; |
| 523 |
| 524 const Position& removeMarkerStart = startOfFirstWord.deepEquivalent(); |
| 525 const Position& removeMarkerEnd = endOfLastWord.deepEquivalent(); |
| 526 if (removeMarkerStart > removeMarkerEnd) { |
| 527 // editing/inserting/insert-br-008.html and more reach here. |
| 528 // TODO(yosin): To avoid |DCHECK(removeMarkerStart <= removeMarkerEnd)| |
| 529 // in |EphemeralRange| constructor, we have this if-statement. Once we |
| 530 // fix |startOfWord()| and |endOfWord()|, we should remove this |
| 531 // if-statement. |
| 532 return; |
| 533 } |
| 534 |
| 535 // Now we remove markers on everything between startOfFirstWord and |
| 536 // endOfLastWord. However, if an autocorrection change a single word to |
| 537 // multiple words, we want to remove correction mark from all the resulted |
| 538 // words even we only edit one of them. For example, assuming autocorrection |
| 539 // changes "avantgarde" to "avant garde", we will have CorrectionIndicator |
| 540 // marker on both words and on the whitespace between them. If we then edit |
| 541 // garde, we would like to remove the marker from word "avant" and whitespace |
| 542 // as well. So we need to get the continous range of of marker that contains |
| 543 // the word in question, and remove marker on that whole range. |
| 544 const EphemeralRange wordRange(removeMarkerStart, removeMarkerEnd); |
| 545 document->markers().removeMarkers( |
| 546 wordRange, markerTypes, |
| 547 DocumentMarkerController::RemovePartiallyOverlappingMarker); |
| 548 } |
| 549 |
| 372 void DocumentMarkerController::repaintMarkers( | 550 void DocumentMarkerController::repaintMarkers( |
| 373 DocumentMarker::MarkerTypes markerTypes) { | 551 DocumentMarker::MarkerTypes markerTypes) { |
| 374 HeapHashSet<Member<Node>> nodesToRepaint; | 552 HeapHashSet<Member<Node>> nodesToRepaint; |
| 375 for (DocumentMarker::MarkerType type : markerTypes) { | 553 for (DocumentMarker::MarkerType type : markerTypes) { |
| 376 MarkerMap& markerMap = markerMapForType(type); | 554 MarkerMap& markerMap = markerMapForType(type); |
| 377 for (auto& nodeMarkers : markerMap) { | 555 for (auto& nodeMarkers : markerMap) { |
| 378 if (!nodeMarkers.value->empty()) | 556 if (!nodeMarkers.value->empty()) |
| 379 nodesToRepaint.insert(nodeMarkers.key.get()); | 557 nodesToRepaint.insert(nodeMarkers.key.get()); |
| 380 } | 558 } |
| 381 } | 559 } |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 DocumentMarker::MarkerType type) { | 680 DocumentMarker::MarkerType type) { |
| 503 switch (type) { | 681 switch (type) { |
| 504 case DocumentMarker::Spelling: | 682 case DocumentMarker::Spelling: |
| 505 return new SpellCheckMarkerList(DocumentMarker::Spelling); | 683 return new SpellCheckMarkerList(DocumentMarker::Spelling); |
| 506 case DocumentMarker::Grammar: | 684 case DocumentMarker::Grammar: |
| 507 return new SpellCheckMarkerList(DocumentMarker::Grammar); | 685 return new SpellCheckMarkerList(DocumentMarker::Grammar); |
| 508 case DocumentMarker::TextMatch: | 686 case DocumentMarker::TextMatch: |
| 509 return new TextMatchMarkerList(); | 687 return new TextMatchMarkerList(); |
| 510 case DocumentMarker::Composition: | 688 case DocumentMarker::Composition: |
| 511 return new CompositionMarkerList(); | 689 return new CompositionMarkerList(); |
| 690 case DocumentMarker::Suggestion: |
| 691 return new SuggestionMarkerList(); |
| 692 case DocumentMarker::SuggestionHighlight: |
| 693 return new SuggestionHighlightMarkerList(); |
| 512 default: | 694 default: |
| 513 // MSVC thinks this method doesn't handle all enum values even though it | 695 // MSVC thinks this method doesn't handle all enum values even though it |
| 514 // does. So we have to return something for the default case to avoid a | 696 // does. So we have to return something for the default case to avoid a |
| 515 // C4715 warning. | 697 // C4715 warning. |
| 516 UNREACHABLE(); | 698 UNREACHABLE(); |
| 517 return nullptr; | 699 return nullptr; |
| 518 } | 700 } |
| 519 } | 701 } |
| 520 | 702 |
| 521 HeapVector<Member<DocumentMarkerList>> | 703 HeapVector<Member<DocumentMarkerList>> |
| (...skipping 24 matching lines...) Expand all Loading... |
| 546 DocumentMarker::MarkerType type) const { | 728 DocumentMarker::MarkerType type) const { |
| 547 switch (type) { | 729 switch (type) { |
| 548 case DocumentMarker::Spelling: | 730 case DocumentMarker::Spelling: |
| 549 return m_spelling; | 731 return m_spelling; |
| 550 case DocumentMarker::Grammar: | 732 case DocumentMarker::Grammar: |
| 551 return m_grammar; | 733 return m_grammar; |
| 552 case DocumentMarker::TextMatch: | 734 case DocumentMarker::TextMatch: |
| 553 return m_textMatches; | 735 return m_textMatches; |
| 554 case DocumentMarker::Composition: | 736 case DocumentMarker::Composition: |
| 555 return m_compositions; | 737 return m_compositions; |
| 738 case DocumentMarker::Suggestion: |
| 739 return m_suggestions; |
| 740 case DocumentMarker::SuggestionHighlight: |
| 741 return m_suggestionHighlights; |
| 556 default: | 742 default: |
| 557 // MSVC thinks this method doesn't handle all enum values even though it | 743 // MSVC thinks this method doesn't handle all enum values even though it |
| 558 // does. So we have to return something for the default case to avoid a | 744 // does. So we have to return something for the default case to avoid a |
| 559 // C4715 warning. | 745 // C4715 warning. |
| 560 UNREACHABLE(); | 746 UNREACHABLE(); |
| 561 return m_spelling; | 747 return m_spelling; |
| 562 } | 748 } |
| 563 } | 749 } |
| 564 | 750 |
| 565 void DocumentMarkerController::removeMarkers( | 751 void DocumentMarkerController::removeMarkers( |
| 566 TextIterator& markedText, | 752 TextIterator& markedText, |
| 567 DocumentMarker::MarkerTypes markerTypes, | 753 DocumentMarker::MarkerTypes markerTypes, |
| 568 RemovePartiallyOverlappingMarkerOrNot | 754 RemovePartiallyOverlappingMarkerOrNot |
| 569 shouldRemovePartiallyOverlappingMarker) { | 755 shouldRemovePartiallyOverlappingMarker) { |
| 570 for (; !markedText.atEnd(); markedText.advance()) { | 756 for (; !markedText.atEnd(); markedText.advance()) { |
| 757 LOG(INFO) << "removing markers from " << markedText.currentContainer() << "
from offsets " << markedText.startOffsetInCurrentContainer() << " to " << marked
Text.endOffsetInCurrentContainer(); |
| 571 int startOffset = markedText.startOffsetInCurrentContainer(); | 758 int startOffset = markedText.startOffsetInCurrentContainer(); |
| 572 int endOffset = markedText.endOffsetInCurrentContainer(); | 759 int endOffset = markedText.endOffsetInCurrentContainer(); |
| 573 removeMarkers(markedText.currentContainer(), startOffset, | 760 removeMarkers(markedText.currentContainer(), startOffset, |
| 574 endOffset - startOffset, markerTypes, | 761 endOffset - startOffset, markerTypes, |
| 575 shouldRemovePartiallyOverlappingMarker); | 762 shouldRemovePartiallyOverlappingMarker); |
| 576 } | 763 } |
| 577 } | 764 } |
| 578 | 765 |
| 579 // SynchronousMutationObserver | 766 // SynchronousMutationObserver |
| 580 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, | 767 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 605 } | 792 } |
| 606 | 793 |
| 607 } // namespace blink | 794 } // namespace blink |
| 608 | 795 |
| 609 #ifndef NDEBUG | 796 #ifndef NDEBUG |
| 610 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { | 797 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { |
| 611 if (controller) | 798 if (controller) |
| 612 controller->showMarkers(); | 799 controller->showMarkers(); |
| 613 } | 800 } |
| 614 #endif | 801 #endif |
| OLD | NEW |