1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * (C) 2006 Alexey Proskuryakov (ap (at) webkit.org) 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 8 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Library General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Library General Public License for more details. 19 * 20 * You should have received a copy of the GNU Library General Public License 21 * along with this library; see the file COPYING.LIB. If not, write to 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23 * Boston, MA 02110-1301, USA. 24 * 25 */ 26 27 #include "config.h" 28 #include "core/dom/DocumentMarkerController.h" 29 30 #include "core/dom/Node.h" 31 #include "core/dom/NodeTraversal.h" 32 #include "core/dom/Range.h" 33 #include "core/dom/RenderedDocumentMarker.h" 34 #include "core/editing/TextIterator.h" 35 #include "core/rendering/RenderObject.h" 36 37 #ifndef NDEBUG 38 #include <stdio.h> 39 #endif 40 41 namespace WebCore { 42 43 namespace { 44 45 DocumentMarker::MarkerTypeIndex MarkerTypeToMarkerIndex(DocumentMarker::MarkerType type) 46 { 47 switch (type) { 48 case DocumentMarker::Spelling: 49 return DocumentMarker::SpellingMarkerIndex; 50 case DocumentMarker::Grammar: 51 return DocumentMarker::GramarMarkerIndex; 52 case DocumentMarker::TextMatch: 53 return DocumentMarker::TextMatchMarkerIndex; 54 case DocumentMarker::InvisibleSpellcheck: 55 return DocumentMarker::InvisibleSpellcheckMarkerIndex; 56 } 57 58 ASSERT_NOT_REACHED(); 59 return DocumentMarker::SpellingMarkerIndex; 60 } 61 62 } // namespace 63 64 inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types) 65 { 66 return m_possiblyExistingMarkerTypes.intersects(types); 67 } 68 69 DocumentMarkerController::DocumentMarkerController() 70 : m_possiblyExistingMarkerTypes(0) 71 { 72 } 73 74 DocumentMarkerController::~DocumentMarkerController() 75 { 76 } 77 78 void DocumentMarkerController::clear() 79 { 80 m_markers.clear(); 81 m_possiblyExistingMarkerTypes = 0; 82 } 83 84 void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type, const String& description, uint32_t hash) 85 { 86 // Use a TextIterator to visit the potentially multiple nodes the range covers. 87 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { 88 RefPtr<Range> textPiece = markedText.range(); 89 addMarker(textPiece->startContainer(), DocumentMarker(type, textPiece->startOffset(), textPiece->endOffset(), description, hash)); 90 } 91 } 92 93 void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type, const String& description) 94 { 95 // Use a TextIterator to visit the potentially multiple nodes the range covers. 96 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { 97 RefPtr<Range> textPiece = markedText.range(); 98 addMarker(textPiece->startContainer(), DocumentMarker(type, textPiece->startOffset(), textPiece->endOffset(), description)); 99 } 100 } 101 102 void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type) 103 { 104 // Use a TextIterator to visit the potentially multiple nodes the range covers. 105 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { 106 RefPtr<Range> textPiece = markedText.range(); 107 addMarker(textPiece->startContainer(), DocumentMarker(type, textPiece->startOffset(), textPiece->endOffset())); 108 } 109 110 } 111 112 void DocumentMarkerController::addMarkerToNode(Node* node, unsigned startOffset, unsigned length, DocumentMarker::MarkerType type) 113 { 114 addMarker(node, DocumentMarker(type, startOffset, startOffset + length)); 115 } 116 117 void DocumentMarkerController::addMarkerToNode(Node* node, unsigned startOffset, unsigned length, DocumentMarker::MarkerType type, PassRefPtr<DocumentMarkerDetails> details) 118 { 119 addMarker(node, DocumentMarker(type, startOffset, startOffset + length, details)); 120 } 121 122 123 void DocumentMarkerController::addTextMatchMarker(const Range* range, bool activeMatch) 124 { 125 // Use a TextIterator to visit the potentially multiple nodes the range covers. 126 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { 127 RefPtr<Range> textPiece = markedText.range(); 128 unsigned startOffset = textPiece->startOffset(); 129 unsigned endOffset = textPiece->endOffset(); 130 addMarker(textPiece->startContainer(), DocumentMarker(startOffset, endOffset, activeMatch)); 131 if (endOffset > startOffset) { 132 // Rendered rects for markers in WebKit are not populated until each time 133 // the markers are painted. However, we need it to happen sooner, because 134 // the whole purpose of tickmarks on the scrollbar is to show where 135 // matches off-screen are (that haven't been painted yet). 136 Node* node = textPiece->startContainer(); 137 Vector<DocumentMarker*> markers = markersFor(node); 138 toRenderedDocumentMarker(markers[markers.size() - 1])->setRenderedRect(range->boundingBox()); 139 } 140 } 141 } 142 143 void DocumentMarkerController::prepareForDestruction() 144 { 145 clear(); 146 } 147 148 void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker) 149 { 150 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { 151 if (!possiblyHasMarkers(markerTypes)) 152 return; 153 ASSERT(!m_markers.isEmpty()); 154 155 RefPtr<Range> textPiece = markedText.range(); 156 int startOffset = textPiece->startOffset(); 157 int endOffset = textPiece->endOffset(); 158 removeMarkers(textPiece->startContainer(), startOffset, endOffset - startOffset, markerTypes, shouldRemovePartiallyOverlappingMarker); 159 } 160 } 161 162 static bool startsFurther(const DocumentMarker& lhv, const DocumentMarker& rhv) 163 { 164 return lhv.startOffset() < rhv.startOffset(); 165 } 166 167 static bool startsAfter(const DocumentMarker& marker, size_t startOffset) 168 { 169 return marker.startOffset() < startOffset; 170 } 171 172 static bool endsBefore(size_t startOffset, const DocumentMarker& rhv) 173 { 174 return startOffset < rhv.endOffset(); 175 } 176 177 static bool compareByStart(const DocumentMarker* lhv, const DocumentMarker* rhv) 178 { 179 return startsFurther(*lhv, *rhv); 180 } 181 182 static bool doesNotOverlap(const DocumentMarker& lhv, const DocumentMarker& rhv) 183 { 184 return lhv.endOffset() < rhv.startOffset(); 185 } 186 187 static bool doesNotInclude(const DocumentMarker& marker, size_t startOffset) 188 { 189 return marker.endOffset() < startOffset; 190 } 191 192 // Markers are stored in order sorted by their start offset. 193 // Markers of the same type do not overlap each other. 194 195 void DocumentMarkerController::addMarker(Node* node, const DocumentMarker& newMarker) 196 { 197 ASSERT(newMarker.endOffset() >= newMarker.startOffset()); 198 if (newMarker.endOffset() == newMarker.startOffset()) 199 return; 200 201 m_possiblyExistingMarkerTypes.add(newMarker.type()); 202 203 OwnPtr<MarkerLists>& markers = m_markers.add(node, nullptr).iterator->value; 204 if (!markers) { 205 markers = adoptPtr(new MarkerLists); 206 markers->grow(DocumentMarker::MarkerTypeIndexesCount); 207 } 208 209 DocumentMarker::MarkerTypeIndex markerListIndex = MarkerTypeToMarkerIndex(newMarker.type()); 210 if (!markers->at(markerListIndex)) { 211 markers->insert(markerListIndex, adoptPtr(new MarkerList)); 212 } 213 214 OwnPtr<MarkerList>& list = markers->at(markerListIndex); 215 if (list->isEmpty() || list->last().endOffset() < newMarker.startOffset()) { 216 list->append(RenderedDocumentMarker(newMarker)); 217 } else { 218 RenderedDocumentMarker toInsert(newMarker); 219 if (toInsert.type() != DocumentMarker::TextMatch) { 220 mergeOverlapping(list.get(), toInsert); 221 } else { 222 MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(), toInsert, startsFurther); 223 list->insert(pos - list->begin(), RenderedDocumentMarker(toInsert)); 224 } 225 } 226 227 // repaint the affected node 228 if (node->renderer()) 229 node->renderer()->repaint(); 230 } 231 232 void DocumentMarkerController::mergeOverlapping(MarkerList* list, DocumentMarker& toInsert) 233 { 234 MarkerList::iterator firstOverlapping = std::lower_bound(list->begin(), list->end(), toInsert, doesNotOverlap); 235 size_t index = firstOverlapping - list->begin(); 236 list->insert(index, RenderedDocumentMarker(toInsert)); 237 MarkerList::iterator inserted = list->begin() + index; 238 firstOverlapping = inserted + 1; 239 for (MarkerList::iterator i = firstOverlapping; i != list->end() && i->startOffset() <= inserted->endOffset(); ) { 240 inserted->setStartOffset(std::min(inserted->startOffset(), i->startOffset())); 241 inserted->setEndOffset(std::max(inserted->endOffset(), i->endOffset())); 242 list->remove(i - list->begin()); 243 } 244 } 245 246 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is 247 // useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode. 248 void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta) 249 { 250 if (length <= 0) 251 return; 252 253 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 254 return; 255 ASSERT(!m_markers.isEmpty()); 256 257 MarkerLists* markers = m_markers.get(srcNode); 258 if (!markers) 259 return; 260 261 bool docDirty = false; 262 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 263 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 264 if (!list) 265 continue; 266 267 unsigned endOffset = startOffset + length - 1; 268 MarkerList::iterator startPos = std::lower_bound(list->begin(), list->end(), startOffset, doesNotInclude); 269 for (MarkerList::iterator i = startPos; i != list->end(); ++i) { 270 DocumentMarker marker = *i; 271 272 // stop if we are now past the specified range 273 if (marker.startOffset() > endOffset) 274 break; 275 276 // pin the marker to the specified range and apply the shift delta 277 docDirty = true; 278 if (marker.startOffset() < startOffset) 279 marker.setStartOffset(startOffset); 280 if (marker.endOffset() > endOffset) 281 marker.setEndOffset(endOffset); 282 marker.shiftOffsets(delta); 283 284 addMarker(dstNode, marker); 285 } 286 } 287 288 // repaint the affected node 289 if (docDirty && dstNode->renderer()) 290 dstNode->renderer()->repaint(); 291 } 292 293 void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker) 294 { 295 if (length <= 0) 296 return; 297 298 if (!possiblyHasMarkers(markerTypes)) 299 return; 300 ASSERT(!(m_markers.isEmpty())); 301 302 MarkerLists* markers = m_markers.get(node); 303 if (!markers) 304 return; 305 306 bool docDirty = false; 307 size_t emptyListsCount = 0; 308 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 309 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 310 if (!list || list->isEmpty()) { 311 if (list.get() && list->isEmpty()) 312 list.clear(); 313 ++emptyListsCount; 314 continue; 315 } 316 if (!markerTypes.contains(list->begin()->type())) 317 continue; 318 unsigned endOffset = startOffset + length; 319 MarkerList::iterator startPos = std::upper_bound(list->begin(), list->end(), startOffset, endsBefore); 320 for (MarkerList::iterator i = startPos; i != list->end(); ) { 321 DocumentMarker marker = *i; 322 323 // markers are returned in order, so stop if we are now past the specified range 324 if (marker.startOffset() >= endOffset) 325 break; 326 327 // at this point we know that marker and target intersect in some way 328 docDirty = true; 329 330 // pitch the old marker 331 list->remove(i - list->begin()); 332 333 if (shouldRemovePartiallyOverlappingMarker) { 334 // Stop here. Don't add resulting slices back. 335 continue; 336 } 337 338 // add either of the resulting slices that are left after removing target 339 if (startOffset > marker.startOffset()) { 340 DocumentMarker newLeft = marker; 341 newLeft.setEndOffset(startOffset); 342 size_t insertIndex = i - list->begin(); 343 list->insert(insertIndex , RenderedDocumentMarker(newLeft)); 344 // Move to the marker after the inserted one. 345 i = list->begin() + insertIndex + 1; 346 } 347 if (marker.endOffset() > endOffset) { 348 DocumentMarker newRight = marker; 349 newRight.setStartOffset(endOffset); 350 size_t insertIndex = i - list->begin(); 351 list->insert(insertIndex, RenderedDocumentMarker(newRight)); 352 // Move to the marker after the inserted one. 353 i = list->begin() + insertIndex + 1; 354 } 355 } 356 357 if (list->isEmpty()) { 358 list.clear(); 359 ++emptyListsCount; 360 } 361 } 362 363 if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) { 364 m_markers.remove(node); 365 if (m_markers.isEmpty()) 366 m_possiblyExistingMarkerTypes = 0; 367 } 368 369 // repaint the affected node 370 if (docDirty && node->renderer()) 371 node->renderer()->repaint(); 372 } 373 374 DocumentMarker* DocumentMarkerController::markerContainingPoint(const LayoutPoint& point, DocumentMarker::MarkerType markerType) 375 { 376 if (!possiblyHasMarkers(markerType)) 377 return 0; 378 ASSERT(!(m_markers.isEmpty())); 379 380 // outer loop: process each node that contains any markers 381 MarkerMap::iterator end = m_markers.end(); 382 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { 383 // inner loop; process each marker in this node 384 MarkerLists* markers = nodeIterator->value.get(); 385 OwnPtr<MarkerList>& list = (*markers)[MarkerTypeToMarkerIndex(markerType)]; 386 unsigned markerCount = list.get() ? list->size() : 0; 387 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { 388 RenderedDocumentMarker& marker = list->at(markerIndex); 389 390 if (marker.contains(point)) 391 return ▮ 392 } 393 } 394 395 return 0; 396 } 397 398 Vector<DocumentMarker*> DocumentMarkerController::markersFor(Node* node, DocumentMarker::MarkerTypes markerTypes) 399 { 400 Vector<DocumentMarker*> result; 401 402 MarkerLists* markers = m_markers.get(node); 403 if (!markers) 404 return result; 405 406 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 407 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 408 if (!list || list->isEmpty() || !markerTypes.contains(list->begin()->type())) 409 continue; 410 411 for (size_t i = 0; i < list->size(); ++i) 412 result.append(&(list->at(i))); 413 } 414 415 std::sort(result.begin(), result.end(), compareByStart); 416 return result; 417 } 418 419 Vector<DocumentMarker*> DocumentMarkerController::markers() 420 { 421 Vector<DocumentMarker*> result; 422 for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) { 423 MarkerLists* markers = i->value.get(); 424 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 425 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 426 for (size_t j = 0; list.get() && j < list->size(); ++j) 427 result.append(&(list->at(j))); 428 } 429 } 430 std::sort(result.begin(), result.end(), compareByStart); 431 return result; 432 } 433 434 Vector<DocumentMarker*> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerTypes markerTypes) 435 { 436 if (!possiblyHasMarkers(markerTypes)) 437 return Vector<DocumentMarker*>(); 438 439 Vector<DocumentMarker*> foundMarkers; 440 441 Node* startContainer = range->startContainer(); 442 ASSERT(startContainer); 443 Node* endContainer = range->endContainer(); 444 ASSERT(endContainer); 445 446 Node* pastLastNode = range->pastLastNode(); 447 for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) { 448 Vector<DocumentMarker*> markers = markersFor(node); 449 Vector<DocumentMarker*>::const_iterator end = markers.end(); 450 for (Vector<DocumentMarker*>::const_iterator it = markers.begin(); it != end; ++it) { 451 DocumentMarker* marker = *it; 452 if (!markerTypes.contains(marker->type())) 453 continue; 454 if (node == startContainer && marker->endOffset() <= static_cast<unsigned>(range->startOffset())) 455 continue; 456 if (node == endContainer && marker->startOffset() >= static_cast<unsigned>(range->endOffset())) 457 continue; 458 foundMarkers.append(marker); 459 } 460 } 461 return foundMarkers; 462 } 463 464 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType) 465 { 466 Vector<IntRect> result; 467 468 if (!possiblyHasMarkers(markerType)) 469 return result; 470 ASSERT(!(m_markers.isEmpty())); 471 472 // outer loop: process each node 473 MarkerMap::iterator end = m_markers.end(); 474 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { 475 // inner loop; process each marker in this node 476 MarkerLists* markers = nodeIterator->value.get(); 477 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 478 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 479 if (!list || list->isEmpty() || list->begin()->type() != markerType) 480 continue; 481 for (unsigned markerIndex = 0; markerIndex < list->size(); ++markerIndex) { 482 const RenderedDocumentMarker& marker = list->at(markerIndex); 483 484 if (!marker.isRendered()) 485 continue; 486 487 result.append(marker.renderedRect()); 488 } 489 } 490 } 491 492 return result; 493 } 494 495 void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerTypes markerTypes) 496 { 497 if (!possiblyHasMarkers(markerTypes)) 498 return; 499 ASSERT(!m_markers.isEmpty()); 500 501 MarkerMap::iterator iterator = m_markers.find(node); 502 if (iterator != m_markers.end()) 503 removeMarkersFromList(iterator, markerTypes); 504 } 505 506 void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerTypes) 507 { 508 if (!possiblyHasMarkers(markerTypes)) 509 return; 510 ASSERT(!m_markers.isEmpty()); 511 512 Vector<const Node*> nodesWithMarkers; 513 copyKeysToVector(m_markers, nodesWithMarkers); 514 unsigned size = nodesWithMarkers.size(); 515 for (unsigned i = 0; i < size; ++i) { 516 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]); 517 if (iterator != m_markers.end()) 518 removeMarkersFromList(iterator, markerTypes); 519 } 520 521 m_possiblyExistingMarkerTypes.remove(markerTypes); 522 } 523 524 void DocumentMarkerController::removeMarkersFromList(MarkerMap::iterator iterator, DocumentMarker::MarkerTypes markerTypes) 525 { 526 bool needsRepainting = false; 527 bool nodeCanBeRemoved; 528 529 size_t emptyListsCount = 0; 530 if (markerTypes == DocumentMarker::AllMarkers()) { 531 needsRepainting = true; 532 nodeCanBeRemoved = true; 533 } else { 534 MarkerLists* markers = iterator->value.get(); 535 536 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 537 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 538 if (!list || list->isEmpty()) { 539 if (list.get() && list->isEmpty()) 540 list.clear(); 541 ++emptyListsCount; 542 continue; 543 } 544 if (markerTypes.contains(list->begin()->type())) { 545 list->clear(); 546 list.clear(); 547 ++emptyListsCount; 548 needsRepainting = true; 549 } 550 } 551 552 nodeCanBeRemoved = emptyListsCount == DocumentMarker::MarkerTypeIndexesCount; 553 } 554 555 if (needsRepainting) { 556 if (RenderObject* renderer = iterator->key->renderer()) 557 renderer->repaint(); 558 } 559 560 if (nodeCanBeRemoved) { 561 m_markers.remove(iterator); 562 if (m_markers.isEmpty()) 563 m_possiblyExistingMarkerTypes = 0; 564 } 565 } 566 567 void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes markerTypes) 568 { 569 if (!possiblyHasMarkers(markerTypes)) 570 return; 571 ASSERT(!m_markers.isEmpty()); 572 573 // outer loop: process each markered node in the document 574 MarkerMap::iterator end = m_markers.end(); 575 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { 576 const Node* node = i->key; 577 578 // inner loop: process each marker in the current node 579 MarkerLists* markers = i->value.get(); 580 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 581 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 582 if (!list || list->isEmpty() || !markerTypes.contains(list->begin()->type())) 583 continue; 584 585 // cause the node to be redrawn 586 if (RenderObject* renderer = node->renderer()) { 587 renderer->repaint(); 588 break; 589 } 590 } 591 } 592 } 593 594 void DocumentMarkerController::invalidateRenderedRectsForMarkersInRect(const LayoutRect& r) 595 { 596 // outer loop: process each markered node in the document 597 MarkerMap::iterator end = m_markers.end(); 598 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { 599 600 // inner loop: process each rect in the current node 601 MarkerLists* markers = i->value.get(); 602 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 603 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 604 for (size_t markerIndex = 0; list.get() && markerIndex < list->size(); ++markerIndex) 605 list->at(markerIndex).invalidate(r); 606 } 607 } 608 } 609 610 void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta) 611 { 612 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 613 return; 614 ASSERT(!m_markers.isEmpty()); 615 616 MarkerLists* markers = m_markers.get(node); 617 if (!markers) 618 return; 619 620 bool docDirty = false; 621 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 622 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 623 if (!list) 624 continue; 625 MarkerList::iterator startPos = std::lower_bound(list->begin(), list->end(), startOffset, startsAfter); 626 for (MarkerList::iterator marker = startPos; marker != list->end(); ++marker) { 627 ASSERT((int)marker->startOffset() + delta >= 0); 628 marker->shiftOffsets(delta); 629 docDirty = true; 630 631 // Marker moved, so previously-computed rendered rectangle is now invalid 632 marker->invalidate(); 633 } 634 } 635 636 // repaint the affected node 637 if (docDirty && node->renderer()) 638 node->renderer()->repaint(); 639 } 640 641 void DocumentMarkerController::setMarkersActive(Range* range, bool active) 642 { 643 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 644 return; 645 ASSERT(!m_markers.isEmpty()); 646 647 Node* startContainer = range->startContainer(); 648 Node* endContainer = range->endContainer(); 649 650 Node* pastLastNode = range->pastLastNode(); 651 652 for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) { 653 int startOffset = node == startContainer ? range->startOffset() : 0; 654 int endOffset = node == endContainer ? range->endOffset() : INT_MAX; 655 setMarkersActive(node, startOffset, endOffset, active); 656 } 657 } 658 659 void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active) 660 { 661 MarkerLists* markers = m_markers.get(node); 662 if (!markers) 663 return; 664 665 bool docDirty = false; 666 OwnPtr<MarkerList>& list = (*markers)[MarkerTypeToMarkerIndex(DocumentMarker::TextMatch)]; 667 if (!list) 668 return; 669 MarkerList::iterator startPos = std::upper_bound(list->begin(), list->end(), startOffset, endsBefore); 670 for (MarkerList::iterator marker = startPos; marker != list->end(); ++marker) { 671 672 // Markers are returned in order, so stop if we are now past the specified range. 673 if (marker->startOffset() >= endOffset) 674 break; 675 676 marker->setActiveMatch(active); 677 docDirty = true; 678 } 679 680 // repaint the affected node 681 if (docDirty && node->renderer()) 682 node->renderer()->repaint(); 683 } 684 685 bool DocumentMarkerController::hasMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes) 686 { 687 if (!possiblyHasMarkers(markerTypes)) 688 return false; 689 ASSERT(!m_markers.isEmpty()); 690 691 Node* startContainer = range->startContainer(); 692 ASSERT(startContainer); 693 Node* endContainer = range->endContainer(); 694 ASSERT(endContainer); 695 696 Node* pastLastNode = range->pastLastNode(); 697 for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) { 698 Vector<DocumentMarker*> markers = markersFor(node); 699 Vector<DocumentMarker*>::const_iterator end = markers.end(); 700 for (Vector<DocumentMarker*>::const_iterator it = markers.begin(); it != end; ++it) { 701 DocumentMarker* marker = *it; 702 if (!markerTypes.contains(marker->type())) 703 continue; 704 if (node == startContainer && marker->endOffset() <= static_cast<unsigned>(range->startOffset())) 705 continue; 706 if (node == endContainer && marker->startOffset() >= static_cast<unsigned>(range->endOffset())) 707 continue; 708 return true; 709 } 710 } 711 return false; 712 } 713 714 #ifndef NDEBUG 715 void DocumentMarkerController::showMarkers() const 716 { 717 fprintf(stderr, "%d nodes have markers:\n", m_markers.size()); 718 MarkerMap::const_iterator end = m_markers.end(); 719 for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { 720 const Node* node = nodeIterator->key; 721 fprintf(stderr, "%p", node); 722 MarkerLists* markers = m_markers.get(node); 723 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) { 724 OwnPtr<MarkerList>& list = (*markers)[markerListIndex]; 725 for (unsigned markerIndex = 0; list.get() && markerIndex < list->size(); ++markerIndex) { 726 const DocumentMarker& marker = list->at(markerIndex); 727 fprintf(stderr, " %d:[%d:%d](%d)", marker.type(), marker.startOffset(), marker.endOffset(), marker.activeMatch()); 728 } 729 } 730 731 fprintf(stderr, "\n"); 732 } 733 } 734 #endif 735 736 } // namespace WebCore 737 738 #ifndef NDEBUG 739 void showDocumentMarkers(const WebCore::DocumentMarkerController* controller) 740 { 741 if (controller) 742 controller->showMarkers(); 743 } 744 #endif 745