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 "Range.h"
32#include "TextIterator.h"
33
34namespace WebCore {
35
36static IntRect placeholderRectForMarker()
37{
38    return IntRect(-1, -1, -1, -1);
39}
40
41inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types)
42{
43    return m_possiblyExistingMarkerTypes.intersects(types);
44}
45
46DocumentMarkerController::DocumentMarkerController()
47    : m_possiblyExistingMarkerTypes(0)
48{
49}
50
51void DocumentMarkerController::detach()
52{
53    m_possiblyExistingMarkerTypes = 0;
54    if (m_markers.isEmpty())
55        return;
56    deleteAllValues(m_markers);
57    m_markers.clear();
58}
59
60void 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
71void 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
88void 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.
155void 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
201void 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
276DocumentMarker* 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 &marker;
306        }
307    }
308
309    return 0;
310}
311
312Vector<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
320Vector<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
349Vector<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
385void 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
396void 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.
415void 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
462void 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
496void 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
518void 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
535void 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
568void 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
586void 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
616bool 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
644void 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
681void 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
702void showDocumentMarkers(const WebCore::DocumentMarkerController* controller)
703{
704    if (controller)
705        controller->showMarkers();
706}
707#endif
708