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