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