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