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 ▮
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