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