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