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