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 "DocumentMarkerController.h" 29 30 #include "Node.h" 31 #include "Range.h" 32 #include "TextIterator.h" 33 34 namespace WebCore { 35 36 static IntRect placeholderRectForMarker() 37 { 38 return IntRect(-1, -1, -1, -1); 39 } 40 41 inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types) 42 { 43 return m_possiblyExistingMarkerTypes.intersects(types); 44 } 45 46 DocumentMarkerController::DocumentMarkerController() 47 : m_possiblyExistingMarkerTypes(0) 48 { 49 } 50 51 void DocumentMarkerController::detach() 52 { 53 m_possiblyExistingMarkerTypes = 0; 54 if (m_markers.isEmpty()) 55 return; 56 deleteAllValues(m_markers); 57 m_markers.clear(); 58 } 59 60 void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type, String description) 61 { 62 // Use a TextIterator to visit the potentially multiple nodes the range covers. 63 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { 64 RefPtr<Range> textPiece = markedText.range(); 65 int exception = 0; 66 DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description, false}; 67 addMarker(textPiece->startContainer(exception), marker); 68 } 69 } 70 71 void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker) 72 { 73 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { 74 if (!possiblyHasMarkers(markerTypes)) 75 return; 76 ASSERT(!m_markers.isEmpty()); 77 78 RefPtr<Range> textPiece = markedText.range(); 79 int startOffset = textPiece->startOffset(); 80 int endOffset = textPiece->endOffset(); 81 removeMarkers(textPiece->startContainer(), startOffset, endOffset - startOffset, markerTypes, shouldRemovePartiallyOverlappingMarker); 82 } 83 } 84 85 // Markers are stored in order sorted by their start offset. 86 // Markers of the same type do not overlap each other. 87 88 void DocumentMarkerController::addMarker(Node* node, DocumentMarker newMarker) 89 { 90 ASSERT(newMarker.endOffset >= newMarker.startOffset); 91 if (newMarker.endOffset == newMarker.startOffset) 92 return; 93 94 m_possiblyExistingMarkerTypes.add(newMarker.type); 95 96 MarkerMapVectorPair* vectorPair = m_markers.get(node); 97 98 if (!vectorPair) { 99 vectorPair = new MarkerMapVectorPair; 100 vectorPair->first.append(newMarker); 101 vectorPair->second.append(placeholderRectForMarker()); 102 m_markers.set(node, vectorPair); 103 } else { 104 Vector<DocumentMarker>& markers = vectorPair->first; 105 Vector<IntRect>& rects = vectorPair->second; 106 size_t numMarkers = markers.size(); 107 ASSERT(numMarkers == rects.size()); 108 size_t i; 109 // Iterate over all markers whose start offset is less than or equal to the new marker's. 110 // If one of them is of the same type as the new marker and touches it or intersects with it 111 // (there is at most one), remove it and adjust the new marker's start offset to encompass it. 112 for (i = 0; i < numMarkers; ++i) { 113 DocumentMarker marker = markers[i]; 114 if (marker.startOffset > newMarker.startOffset) 115 break; 116 if (marker.type == newMarker.type && marker.endOffset >= newMarker.startOffset) { 117 newMarker.startOffset = marker.startOffset; 118 markers.remove(i); 119 rects.remove(i); 120 numMarkers--; 121 break; 122 } 123 } 124 size_t j = i; 125 // Iterate over all markers whose end offset is less than or equal to the new marker's, 126 // removing markers of the same type as the new marker which touch it or intersect with it, 127 // adjusting the new marker's end offset to cover them if necessary. 128 while (j < numMarkers) { 129 DocumentMarker marker = markers[j]; 130 if (marker.startOffset > newMarker.endOffset) 131 break; 132 if (marker.type == newMarker.type) { 133 markers.remove(j); 134 rects.remove(j); 135 if (newMarker.endOffset <= marker.endOffset) { 136 newMarker.endOffset = marker.endOffset; 137 break; 138 } 139 numMarkers--; 140 } else 141 j++; 142 } 143 // At this point i points to the node before which we want to insert. 144 markers.insert(i, newMarker); 145 rects.insert(i, placeholderRectForMarker()); 146 } 147 148 // repaint the affected node 149 if (node->renderer()) 150 node->renderer()->repaint(); 151 } 152 153 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is 154 // useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode. 155 void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta) 156 { 157 if (length <= 0) 158 return; 159 160 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 161 return; 162 ASSERT(!m_markers.isEmpty()); 163 164 MarkerMapVectorPair* vectorPair = m_markers.get(srcNode); 165 if (!vectorPair) 166 return; 167 168 ASSERT(vectorPair->first.size() == vectorPair->second.size()); 169 170 bool docDirty = false; 171 unsigned endOffset = startOffset + length - 1; 172 Vector<DocumentMarker>& markers = vectorPair->first; 173 for (size_t i = 0; i != markers.size(); ++i) { 174 DocumentMarker marker = markers[i]; 175 176 // stop if we are now past the specified range 177 if (marker.startOffset > endOffset) 178 break; 179 180 // skip marker that is before the specified range or is the wrong type 181 if (marker.endOffset < startOffset) 182 continue; 183 184 // pin the marker to the specified range and apply the shift delta 185 docDirty = true; 186 if (marker.startOffset < startOffset) 187 marker.startOffset = startOffset; 188 if (marker.endOffset > endOffset) 189 marker.endOffset = endOffset; 190 marker.startOffset += delta; 191 marker.endOffset += delta; 192 193 addMarker(dstNode, marker); 194 } 195 196 // repaint the affected node 197 if (docDirty && dstNode->renderer()) 198 dstNode->renderer()->repaint(); 199 } 200 201 void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker) 202 { 203 if (length <= 0) 204 return; 205 206 if (!possiblyHasMarkers(markerTypes)) 207 return; 208 ASSERT(!(m_markers.isEmpty())); 209 210 MarkerMapVectorPair* vectorPair = m_markers.get(node); 211 if (!vectorPair) 212 return; 213 214 Vector<DocumentMarker>& markers = vectorPair->first; 215 Vector<IntRect>& rects = vectorPair->second; 216 ASSERT(markers.size() == rects.size()); 217 bool docDirty = false; 218 unsigned endOffset = startOffset + length; 219 for (size_t i = 0; i < markers.size();) { 220 DocumentMarker marker = markers[i]; 221 222 // markers are returned in order, so stop if we are now past the specified range 223 if (marker.startOffset >= endOffset) 224 break; 225 226 // skip marker that is wrong type or before target 227 if (marker.endOffset <= startOffset || !markerTypes.contains(marker.type)) { 228 i++; 229 continue; 230 } 231 232 // at this point we know that marker and target intersect in some way 233 docDirty = true; 234 235 // pitch the old marker and any associated rect 236 markers.remove(i); 237 rects.remove(i); 238 239 if (shouldRemovePartiallyOverlappingMarker) 240 // Stop here. Don't add resulting slices back. 241 continue; 242 243 // add either of the resulting slices that are left after removing target 244 if (startOffset > marker.startOffset) { 245 DocumentMarker newLeft = marker; 246 newLeft.endOffset = startOffset; 247 markers.insert(i, newLeft); 248 rects.insert(i, placeholderRectForMarker()); 249 // i now points to the newly-inserted node, but we want to skip that one 250 i++; 251 } 252 if (marker.endOffset > endOffset) { 253 DocumentMarker newRight = marker; 254 newRight.startOffset = endOffset; 255 markers.insert(i, newRight); 256 rects.insert(i, placeholderRectForMarker()); 257 // i now points to the newly-inserted node, but we want to skip that one 258 i++; 259 } 260 } 261 262 if (markers.isEmpty()) { 263 ASSERT(rects.isEmpty()); 264 m_markers.remove(node); 265 delete vectorPair; 266 } 267 268 if (m_markers.isEmpty()) 269 m_possiblyExistingMarkerTypes = 0; 270 271 // repaint the affected node 272 if (docDirty && node->renderer()) 273 node->renderer()->repaint(); 274 } 275 276 DocumentMarker* DocumentMarkerController::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType) 277 { 278 if (!possiblyHasMarkers(markerType)) 279 return 0; 280 ASSERT(!(m_markers.isEmpty())); 281 282 // outer loop: process each node that contains any markers 283 MarkerMap::iterator end = m_markers.end(); 284 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { 285 // inner loop; process each marker in this node 286 MarkerMapVectorPair* vectorPair = nodeIterator->second; 287 Vector<DocumentMarker>& markers = vectorPair->first; 288 Vector<IntRect>& rects = vectorPair->second; 289 ASSERT(markers.size() == rects.size()); 290 unsigned markerCount = markers.size(); 291 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { 292 DocumentMarker& marker = markers[markerIndex]; 293 294 // skip marker that is wrong type 295 if (marker.type != markerType) 296 continue; 297 298 IntRect& r = rects[markerIndex]; 299 300 // skip placeholder rects 301 if (r == placeholderRectForMarker()) 302 continue; 303 304 if (r.contains(point)) 305 return ▮ 306 } 307 } 308 309 return 0; 310 } 311 312 Vector<DocumentMarker> DocumentMarkerController::markersForNode(Node* node) 313 { 314 MarkerMapVectorPair* vectorPair = m_markers.get(node); 315 if (vectorPair) 316 return vectorPair->first; 317 return Vector<DocumentMarker>(); 318 } 319 320 Vector<DocumentMarker> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerType markerType) 321 { 322 if (!possiblyHasMarkers(markerType)) 323 return Vector<DocumentMarker>(); 324 325 Vector<DocumentMarker> foundMarkers; 326 327 Node* startContainer = range->startContainer(); 328 ASSERT(startContainer); 329 Node* endContainer = range->endContainer(); 330 ASSERT(endContainer); 331 332 Node* pastLastNode = range->pastLastNode(); 333 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { 334 Vector<DocumentMarker> markers = markersForNode(node); 335 Vector<DocumentMarker>::const_iterator end = markers.end(); 336 for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) { 337 if (markerType != it->type) 338 continue; 339 if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset())) 340 continue; 341 if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset())) 342 continue; 343 foundMarkers.append(*it); 344 } 345 } 346 return foundMarkers; 347 } 348 349 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType) 350 { 351 Vector<IntRect> result; 352 353 if (!possiblyHasMarkers(markerType)) 354 return result; 355 ASSERT(!(m_markers.isEmpty())); 356 357 // outer loop: process each node 358 MarkerMap::iterator end = m_markers.end(); 359 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { 360 // inner loop; process each marker in this node 361 MarkerMapVectorPair* vectorPair = nodeIterator->second; 362 Vector<DocumentMarker>& markers = vectorPair->first; 363 Vector<IntRect>& rects = vectorPair->second; 364 ASSERT(markers.size() == rects.size()); 365 unsigned markerCount = markers.size(); 366 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { 367 DocumentMarker marker = markers[markerIndex]; 368 369 // skip marker that is wrong type 370 if (marker.type != markerType) 371 continue; 372 373 IntRect r = rects[markerIndex]; 374 // skip placeholder rects 375 if (r == placeholderRectForMarker()) 376 continue; 377 378 result.append(r); 379 } 380 } 381 382 return result; 383 } 384 385 void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerTypes markerTypes) 386 { 387 if (!possiblyHasMarkers(markerTypes)) 388 return; 389 ASSERT(!m_markers.isEmpty()); 390 391 MarkerMap::iterator iterator = m_markers.find(node); 392 if (iterator != m_markers.end()) 393 removeMarkersFromMarkerMapVectorPair(node, iterator->second, markerTypes); 394 } 395 396 void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerTypes) 397 { 398 if (!possiblyHasMarkers(markerTypes)) 399 return; 400 ASSERT(!m_markers.isEmpty()); 401 402 // outer loop: process each markered node in the document 403 MarkerMap markerMapCopy = m_markers; 404 MarkerMap::iterator end = markerMapCopy.end(); 405 for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) { 406 Node* node = i->first.get(); 407 MarkerMapVectorPair* vectorPair = i->second; 408 removeMarkersFromMarkerMapVectorPair(node, vectorPair, markerTypes); 409 } 410 411 m_possiblyExistingMarkerTypes.remove(markerTypes); 412 } 413 414 // This function may release node and vectorPair. 415 void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, MarkerMapVectorPair* vectorPair, DocumentMarker::MarkerTypes markerTypes) 416 { 417 if (markerTypes == DocumentMarker::AllMarkers()) { 418 delete vectorPair; 419 m_markers.remove(node); 420 if (RenderObject* renderer = node->renderer()) 421 renderer->repaint(); 422 } else { 423 bool needsRepaint = false; 424 Vector<DocumentMarker>& markers = vectorPair->first; 425 Vector<IntRect>& rects = vectorPair->second; 426 ASSERT(markers.size() == rects.size()); 427 for (size_t i = 0; i != markers.size();) { 428 DocumentMarker marker = markers[i]; 429 430 // skip nodes that are not of the specified type 431 if (!markerTypes.contains(marker.type)) { 432 ++i; 433 continue; 434 } 435 436 // pitch the old marker 437 markers.remove(i); 438 rects.remove(i); 439 needsRepaint = true; 440 // i now is the index of the next marker 441 } 442 443 // Redraw the node if it changed. Do this before the node is removed from m_markers, since 444 // m_markers might contain the last reference to the node. 445 if (needsRepaint) { 446 RenderObject* renderer = node->renderer(); 447 if (renderer) 448 renderer->repaint(); 449 } 450 451 // delete the node's list if it is now empty 452 if (markers.isEmpty()) { 453 ASSERT(rects.isEmpty()); 454 m_markers.remove(node); 455 delete vectorPair; 456 } 457 } 458 if (m_markers.isEmpty()) 459 m_possiblyExistingMarkerTypes = 0; 460 } 461 462 void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes markerTypes) 463 { 464 if (!possiblyHasMarkers(markerTypes)) 465 return; 466 ASSERT(!m_markers.isEmpty()); 467 468 // outer loop: process each markered node in the document 469 MarkerMap::iterator end = m_markers.end(); 470 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { 471 Node* node = i->first.get(); 472 473 // inner loop: process each marker in the current node 474 MarkerMapVectorPair* vectorPair = i->second; 475 Vector<DocumentMarker>& markers = vectorPair->first; 476 bool nodeNeedsRepaint = false; 477 for (size_t i = 0; i != markers.size(); ++i) { 478 DocumentMarker marker = markers[i]; 479 480 // skip nodes that are not of the specified type 481 if (markerTypes.contains(marker.type)) { 482 nodeNeedsRepaint = true; 483 break; 484 } 485 } 486 487 if (!nodeNeedsRepaint) 488 continue; 489 490 // cause the node to be redrawn 491 if (RenderObject* renderer = node->renderer()) 492 renderer->repaint(); 493 } 494 } 495 496 void DocumentMarkerController::setRenderedRectForMarker(Node* node, const DocumentMarker& marker, const IntRect& r) 497 { 498 MarkerMapVectorPair* vectorPair = m_markers.get(node); 499 if (!vectorPair) { 500 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about 501 return; 502 } 503 504 Vector<DocumentMarker>& markers = vectorPair->first; 505 ASSERT(markers.size() == vectorPair->second.size()); 506 unsigned markerCount = markers.size(); 507 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { 508 DocumentMarker m = markers[markerIndex]; 509 if (m == marker) { 510 vectorPair->second[markerIndex] = r; 511 return; 512 } 513 } 514 515 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about 516 } 517 518 void DocumentMarkerController::invalidateRenderedRectsForMarkersInRect(const IntRect& r) 519 { 520 // outer loop: process each markered node in the document 521 MarkerMap::iterator end = m_markers.end(); 522 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { 523 524 // inner loop: process each rect in the current node 525 MarkerMapVectorPair* vectorPair = i->second; 526 Vector<IntRect>& rects = vectorPair->second; 527 528 unsigned rectCount = rects.size(); 529 for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex) 530 if (rects[rectIndex].intersects(r)) 531 rects[rectIndex] = placeholderRectForMarker(); 532 } 533 } 534 535 void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta) 536 { 537 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 538 return; 539 ASSERT(!m_markers.isEmpty()); 540 541 MarkerMapVectorPair* vectorPair = m_markers.get(node); 542 if (!vectorPair) 543 return; 544 545 Vector<DocumentMarker>& markers = vectorPair->first; 546 Vector<IntRect>& rects = vectorPair->second; 547 ASSERT(markers.size() == rects.size()); 548 549 bool docDirty = false; 550 for (size_t i = 0; i != markers.size(); ++i) { 551 DocumentMarker& marker = markers[i]; 552 if (marker.startOffset >= startOffset) { 553 ASSERT((int)marker.startOffset + delta >= 0); 554 marker.startOffset += delta; 555 marker.endOffset += delta; 556 docDirty = true; 557 558 // Marker moved, so previously-computed rendered rectangle is now invalid 559 rects[i] = placeholderRectForMarker(); 560 } 561 } 562 563 // repaint the affected node 564 if (docDirty && node->renderer()) 565 node->renderer()->repaint(); 566 } 567 568 void DocumentMarkerController::setMarkersActive(Range* range, bool active) 569 { 570 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 571 return; 572 ASSERT(!m_markers.isEmpty()); 573 574 ExceptionCode ec = 0; 575 Node* startContainer = range->startContainer(ec); 576 Node* endContainer = range->endContainer(ec); 577 578 Node* pastLastNode = range->pastLastNode(); 579 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { 580 int startOffset = node == startContainer ? range->startOffset(ec) : 0; 581 int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX; 582 setMarkersActive(node, startOffset, endOffset, active); 583 } 584 } 585 586 void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active) 587 { 588 MarkerMapVectorPair* vectorPair = m_markers.get(node); 589 if (!vectorPair) 590 return; 591 592 Vector<DocumentMarker>& markers = vectorPair->first; 593 ASSERT(markers.size() == vectorPair->second.size()); 594 595 bool docDirty = false; 596 for (size_t i = 0; i != markers.size(); ++i) { 597 DocumentMarker& marker = markers[i]; 598 599 // Markers are returned in order, so stop if we are now past the specified range. 600 if (marker.startOffset >= endOffset) 601 break; 602 603 // Skip marker that is wrong type or before target. 604 if (marker.endOffset < startOffset || marker.type != DocumentMarker::TextMatch) 605 continue; 606 607 marker.activeMatch = active; 608 docDirty = true; 609 } 610 611 // repaint the affected node 612 if (docDirty && node->renderer()) 613 node->renderer()->repaint(); 614 } 615 616 bool DocumentMarkerController::hasMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes) 617 { 618 if (!possiblyHasMarkers(markerTypes)) 619 return false; 620 ASSERT(!m_markers.isEmpty()); 621 622 Node* startContainer = range->startContainer(); 623 ASSERT(startContainer); 624 Node* endContainer = range->endContainer(); 625 ASSERT(endContainer); 626 627 Node* pastLastNode = range->pastLastNode(); 628 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { 629 Vector<DocumentMarker> markers = markersForNode(node); 630 Vector<DocumentMarker>::const_iterator end = markers.end(); 631 for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) { 632 if (!markerTypes.contains(it->type)) 633 continue; 634 if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset())) 635 continue; 636 if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset())) 637 continue; 638 return true; 639 } 640 } 641 return false; 642 } 643 644 void DocumentMarkerController::clearDescriptionOnMarkersIntersectingRange(Range* range, DocumentMarker::MarkerTypes markerTypes) 645 { 646 if (!possiblyHasMarkers(markerTypes)) 647 return; 648 ASSERT(!m_markers.isEmpty()); 649 650 Node* startContainer = range->startContainer(); 651 Node* endContainer = range->endContainer(); 652 653 Node* pastLastNode = range->pastLastNode(); 654 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { 655 unsigned startOffset = node == startContainer ? range->startOffset() : 0; 656 unsigned endOffset = node == endContainer ? static_cast<unsigned>(range->endOffset()) : std::numeric_limits<unsigned>::max(); 657 MarkerMapVectorPair* vectorPair = m_markers.get(node); 658 if (!vectorPair) 659 continue; 660 661 Vector<DocumentMarker>& markers = vectorPair->first; 662 for (size_t i = 0; i < markers.size(); ++i) { 663 DocumentMarker& marker = markers[i]; 664 665 // markers are returned in order, so stop if we are now past the specified range 666 if (marker.startOffset >= endOffset) 667 break; 668 669 // skip marker that is wrong type or before target 670 if (marker.endOffset <= startOffset || !markerTypes.contains(marker.type)) { 671 i++; 672 continue; 673 } 674 675 marker.description = String(); 676 } 677 } 678 } 679 680 #ifndef NDEBUG 681 void DocumentMarkerController::showMarkers() const 682 { 683 fprintf(stderr, "%d nodes have markers:\n", m_markers.size()); 684 MarkerMap::const_iterator end = m_markers.end(); 685 for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { 686 Node* node = nodeIterator->first.get(); 687 fprintf(stderr, "%p", node); 688 MarkerMapVectorPair* vectorPair = nodeIterator->second; 689 Vector<DocumentMarker>& markers = vectorPair->first; 690 unsigned markerCount = markers.size(); 691 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) 692 fprintf(stderr, " %d:[%d:%d](%d)", markers[markerIndex].type, markers[markerIndex].startOffset, markers[markerIndex].endOffset, markers[markerIndex].activeMatch); 693 fprintf(stderr, "\n"); 694 } 695 } 696 #endif 697 698 } // namespace WebCore 699 700 701 #ifndef NDEBUG 702 void showDocumentMarkers(const WebCore::DocumentMarkerController* controller) 703 { 704 if (controller) 705 controller->showMarkers(); 706 } 707 #endif 708