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