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