blob: c47e8b802b5b1fe889e6f36fcc8eef24e669296e [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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
41namespace WebCore {
42
43inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types)
44{
45 return m_possiblyExistingMarkerTypes.intersects(types);
46}
47
48DocumentMarkerController::DocumentMarkerController()
49 : m_possiblyExistingMarkerTypes(0)
50{
51}
52
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010053DocumentMarkerController::~DocumentMarkerController()
54{
55}
56
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010057void DocumentMarkerController::detach()
58{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010059 m_markers.clear();
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010060 m_possiblyExistingMarkerTypes = 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010061}
62
63void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type, const String& description, uint32_t hash)
64{
65 // Use a TextIterator to visit the potentially multiple nodes the range covers.
66 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
67 RefPtr<Range> textPiece = markedText.range();
68 addMarker(textPiece->startContainer(), DocumentMarker(type, textPiece->startOffset(), textPiece->endOffset(), description, hash));
69 }
70}
71
72void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type, const String& description)
73{
74 // Use a TextIterator to visit the potentially multiple nodes the range covers.
75 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
76 RefPtr<Range> textPiece = markedText.range();
77 addMarker(textPiece->startContainer(), DocumentMarker(type, textPiece->startOffset(), textPiece->endOffset(), description));
78 }
79}
80
81void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type)
82{
83 // Use a TextIterator to visit the potentially multiple nodes the range covers.
84 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
85 RefPtr<Range> textPiece = markedText.range();
86 addMarker(textPiece->startContainer(), DocumentMarker(type, textPiece->startOffset(), textPiece->endOffset()));
87 }
88
89}
90
91void DocumentMarkerController::addMarkerToNode(Node* node, unsigned startOffset, unsigned length, DocumentMarker::MarkerType type)
92{
93 addMarker(node, DocumentMarker(type, startOffset, startOffset + length));
94}
95
96void DocumentMarkerController::addMarkerToNode(Node* node, unsigned startOffset, unsigned length, DocumentMarker::MarkerType type, PassRefPtr<DocumentMarkerDetails> details)
97{
98 addMarker(node, DocumentMarker(type, startOffset, startOffset + length, details));
99}
100
101
102void DocumentMarkerController::addTextMatchMarker(const Range* range, bool activeMatch)
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 unsigned startOffset = textPiece->startOffset();
108 unsigned endOffset = textPiece->endOffset();
109 addMarker(textPiece->startContainer(), DocumentMarker(startOffset, endOffset, activeMatch));
110 if (endOffset > startOffset) {
111 // Rendered rects for markers in WebKit are not populated until each time
112 // the markers are painted. However, we need it to happen sooner, because
113 // the whole purpose of tickmarks on the scrollbar is to show where
114 // matches off-screen are (that haven't been painted yet).
115 Node* node = textPiece->startContainer();
116 Vector<DocumentMarker*> markers = markersFor(node);
117 static_cast<RenderedDocumentMarker*>(markers[markers.size() - 1])->setRenderedRect(range->boundingBox());
118 }
119 }
120}
121
122void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
123{
124 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
125 if (!possiblyHasMarkers(markerTypes))
126 return;
127 ASSERT(!m_markers.isEmpty());
128
129 RefPtr<Range> textPiece = markedText.range();
130 int startOffset = textPiece->startOffset();
131 int endOffset = textPiece->endOffset();
132 removeMarkers(textPiece->startContainer(), startOffset, endOffset - startOffset, markerTypes, shouldRemovePartiallyOverlappingMarker);
133 }
134}
135
136// Markers are stored in order sorted by their start offset.
137// Markers of the same type do not overlap each other.
138
Ben Murdoch02772c62013-07-26 10:21:05 +0100139void DocumentMarkerController::addMarker(Node* node, const DocumentMarker& newMarker)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100140{
141 ASSERT(newMarker.endOffset() >= newMarker.startOffset());
142 if (newMarker.endOffset() == newMarker.startOffset())
143 return;
144
145 m_possiblyExistingMarkerTypes.add(newMarker.type());
146
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100147 OwnPtr<MarkerList>& list = m_markers.add(node, nullptr).iterator->value;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100148
149 if (!list) {
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100150 list = adoptPtr(new MarkerList);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100151 list->append(RenderedDocumentMarker(newMarker));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100152 } else {
153 RenderedDocumentMarker toInsert(newMarker);
154 size_t numMarkers = list->size();
155 size_t i;
156 // Iterate over all markers whose start offset is less than or equal to the new marker's.
157 // If one of them is of the same type as the new marker and touches it or intersects with it
158 // (there is at most one), remove it and adjust the new marker's start offset to encompass it.
159 for (i = 0; i < numMarkers; ++i) {
160 DocumentMarker marker = list->at(i);
161 if (marker.startOffset() > toInsert.startOffset())
162 break;
163 if (marker.type() == toInsert.type() && marker.endOffset() >= toInsert.startOffset()) {
164 toInsert.setStartOffset(marker.startOffset());
165 list->remove(i);
166 numMarkers--;
167 break;
168 }
169 }
170 size_t j = i;
171 // Iterate over all markers whose end offset is less than or equal to the new marker's,
172 // removing markers of the same type as the new marker which touch it or intersect with it,
173 // adjusting the new marker's end offset to cover them if necessary.
174 while (j < numMarkers) {
175 DocumentMarker marker = list->at(j);
176 if (marker.startOffset() > toInsert.endOffset())
177 break;
178 if (marker.type() == toInsert.type()) {
179 list->remove(j);
180 if (toInsert.endOffset() <= marker.endOffset()) {
181 toInsert.setEndOffset(marker.endOffset());
182 break;
183 }
184 numMarkers--;
185 } else
186 j++;
187 }
188 // At this point i points to the node before which we want to insert.
189 list->insert(i, RenderedDocumentMarker(toInsert));
190 }
191
192 // repaint the affected node
193 if (node->renderer())
194 node->renderer()->repaint();
195}
196
197// copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
198// useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode.
199void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta)
200{
201 if (length <= 0)
202 return;
203
204 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
205 return;
206 ASSERT(!m_markers.isEmpty());
207
208 MarkerList* list = m_markers.get(srcNode);
209 if (!list)
210 return;
211
212 bool docDirty = false;
213 unsigned endOffset = startOffset + length - 1;
214 for (size_t i = 0; i != list->size(); ++i) {
215 DocumentMarker marker = list->at(i);
216
217 // stop if we are now past the specified range
218 if (marker.startOffset() > endOffset)
219 break;
220
221 // skip marker that is before the specified range or is the wrong type
222 if (marker.endOffset() < startOffset)
223 continue;
224
225 // pin the marker to the specified range and apply the shift delta
226 docDirty = true;
227 if (marker.startOffset() < startOffset)
228 marker.setStartOffset(startOffset);
229 if (marker.endOffset() > endOffset)
230 marker.setEndOffset(endOffset);
231 marker.shiftOffsets(delta);
232
233 addMarker(dstNode, marker);
234 }
235
236 // repaint the affected node
237 if (docDirty && dstNode->renderer())
238 dstNode->renderer()->repaint();
239}
240
241void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
242{
243 if (length <= 0)
244 return;
245
246 if (!possiblyHasMarkers(markerTypes))
247 return;
248 ASSERT(!(m_markers.isEmpty()));
249
250 MarkerList* list = m_markers.get(node);
251 if (!list)
252 return;
253
254 bool docDirty = false;
255 unsigned endOffset = startOffset + length;
256 for (size_t i = 0; i < list->size();) {
257 DocumentMarker marker = list->at(i);
258
259 // markers are returned in order, so stop if we are now past the specified range
260 if (marker.startOffset() >= endOffset)
261 break;
262
263 // skip marker that is wrong type or before target
264 if (marker.endOffset() <= startOffset || !markerTypes.contains(marker.type())) {
265 i++;
266 continue;
267 }
268
269 // at this point we know that marker and target intersect in some way
270 docDirty = true;
271
272 // pitch the old marker
273 list->remove(i);
274
275 if (shouldRemovePartiallyOverlappingMarker)
276 // Stop here. Don't add resulting slices back.
277 continue;
278
279 // add either of the resulting slices that are left after removing target
280 if (startOffset > marker.startOffset()) {
281 DocumentMarker newLeft = marker;
282 newLeft.setEndOffset(startOffset);
283 list->insert(i, RenderedDocumentMarker(newLeft));
284 // i now points to the newly-inserted node, but we want to skip that one
285 i++;
286 }
287 if (marker.endOffset() > endOffset) {
288 DocumentMarker newRight = marker;
289 newRight.setStartOffset(endOffset);
290 list->insert(i, RenderedDocumentMarker(newRight));
291 // i now points to the newly-inserted node, but we want to skip that one
292 i++;
293 }
294 }
295
296 if (list->isEmpty()) {
297 m_markers.remove(node);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100298 if (m_markers.isEmpty())
299 m_possiblyExistingMarkerTypes = 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100300 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100301
302 // repaint the affected node
303 if (docDirty && node->renderer())
304 node->renderer()->repaint();
305}
306
307DocumentMarker* DocumentMarkerController::markerContainingPoint(const LayoutPoint& point, DocumentMarker::MarkerType markerType)
308{
309 if (!possiblyHasMarkers(markerType))
310 return 0;
311 ASSERT(!(m_markers.isEmpty()));
312
313 // outer loop: process each node that contains any markers
314 MarkerMap::iterator end = m_markers.end();
315 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
316 // inner loop; process each marker in this node
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100317 MarkerList* list = nodeIterator->value.get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100318 unsigned markerCount = list->size();
319 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
320 RenderedDocumentMarker& marker = list->at(markerIndex);
321
322 // skip marker that is wrong type
323 if (marker.type() != markerType)
324 continue;
325
326 if (marker.contains(point))
327 return &marker;
328 }
329 }
330
331 return 0;
332}
333
334Vector<DocumentMarker*> DocumentMarkerController::markersFor(Node* node, DocumentMarker::MarkerTypes markerTypes)
335{
336 Vector<DocumentMarker*> result;
337 MarkerList* list = m_markers.get(node);
338 if (!list)
339 return result;
340
341 for (size_t i = 0; i < list->size(); ++i) {
342 if (markerTypes.contains(list->at(i).type()))
343 result.append(&(list->at(i)));
344 }
345
346 return result;
347}
348
349// FIXME: Should be removed after all relevant patches are landed
350Vector<DocumentMarker> DocumentMarkerController::markersForNode(Node* node)
351{
352 Vector<DocumentMarker> result;
353 MarkerList* list = m_markers.get(node);
354 if (!list)
355 return result;
356
357 for (size_t i = 0; i < list->size(); ++i)
358 result.append(list->at(i));
359
360 return result;
361}
362
363Vector<DocumentMarker*> DocumentMarkerController::markers()
364{
365 Vector<DocumentMarker*> result;
366 for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) {
367 for (size_t j = 0; j < i->value->size(); ++j)
368 result.append(&(i->value->at(j)));
369 }
370 return result;
371}
372
373Vector<DocumentMarker*> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerTypes markerTypes)
374{
375 if (!possiblyHasMarkers(markerTypes))
376 return Vector<DocumentMarker*>();
377
378 Vector<DocumentMarker*> foundMarkers;
379
380 Node* startContainer = range->startContainer();
381 ASSERT(startContainer);
382 Node* endContainer = range->endContainer();
383 ASSERT(endContainer);
384
385 Node* pastLastNode = range->pastLastNode();
386 for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(node)) {
387 Vector<DocumentMarker*> markers = markersFor(node);
388 Vector<DocumentMarker*>::const_iterator end = markers.end();
389 for (Vector<DocumentMarker*>::const_iterator it = markers.begin(); it != end; ++it) {
390 DocumentMarker* marker = *it;
391 if (!markerTypes.contains(marker->type()))
392 continue;
393 if (node == startContainer && marker->endOffset() <= static_cast<unsigned>(range->startOffset()))
394 continue;
395 if (node == endContainer && marker->startOffset() >= static_cast<unsigned>(range->endOffset()))
396 continue;
397 foundMarkers.append(marker);
398 }
399 }
400 return foundMarkers;
401}
402
403Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
404{
405 Vector<IntRect> result;
406
407 if (!possiblyHasMarkers(markerType))
408 return result;
409 ASSERT(!(m_markers.isEmpty()));
410
411 // outer loop: process each node
412 MarkerMap::iterator end = m_markers.end();
413 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
414 // inner loop; process each marker in this node
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100415 MarkerList* list = nodeIterator->value.get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100416 unsigned markerCount = list->size();
417 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
418 const RenderedDocumentMarker& marker = list->at(markerIndex);
419
420 // skip marker that is wrong type
421 if (marker.type() != markerType)
422 continue;
423
424 if (!marker.isRendered())
425 continue;
426
427 result.append(marker.renderedRect());
428 }
429 }
430
431 return result;
432}
433
434void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerTypes markerTypes)
435{
436 if (!possiblyHasMarkers(markerTypes))
437 return;
438 ASSERT(!m_markers.isEmpty());
Ben Murdoch02772c62013-07-26 10:21:05 +0100439
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100440 MarkerMap::iterator iterator = m_markers.find(node);
441 if (iterator != m_markers.end())
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100442 removeMarkersFromList(iterator, markerTypes);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100443}
444
445void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerTypes)
446{
447 if (!possiblyHasMarkers(markerTypes))
448 return;
449 ASSERT(!m_markers.isEmpty());
450
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100451 Vector<RefPtr<Node> > nodesWithMarkers;
452 copyKeysToVector(m_markers, nodesWithMarkers);
453 unsigned size = nodesWithMarkers.size();
454 for (unsigned i = 0; i < size; ++i) {
455 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]);
456 if (iterator != m_markers.end())
457 removeMarkersFromList(iterator, markerTypes);
458 }
459
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100460 m_possiblyExistingMarkerTypes.remove(markerTypes);
461}
462
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100463void DocumentMarkerController::removeMarkersFromList(MarkerMap::iterator iterator, DocumentMarker::MarkerTypes markerTypes)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100464{
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100465 bool needsRepainting = false;
466 bool listCanBeRemoved;
467
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100468 if (markerTypes == DocumentMarker::AllMarkers()) {
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100469 needsRepainting = true;
470 listCanBeRemoved = true;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100471 } else {
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100472 MarkerList* list = iterator->value.get();
473
474 for (size_t i = 0; i != list->size(); ) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100475 DocumentMarker marker = list->at(i);
476
477 // skip nodes that are not of the specified type
478 if (!markerTypes.contains(marker.type())) {
479 ++i;
480 continue;
481 }
482
483 // pitch the old marker
484 list->remove(i);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100485 needsRepainting = true;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100486 // i now is the index of the next marker
487 }
488
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100489 listCanBeRemoved = list->isEmpty();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100490 }
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100491
492 if (needsRepainting) {
493 if (RenderObject* renderer = iterator->key->renderer())
494 renderer->repaint();
495 }
496
497 if (listCanBeRemoved) {
498 m_markers.remove(iterator);
499 if (m_markers.isEmpty())
500 m_possiblyExistingMarkerTypes = 0;
501 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100502}
503
504void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes markerTypes)
505{
506 if (!possiblyHasMarkers(markerTypes))
507 return;
508 ASSERT(!m_markers.isEmpty());
509
510 // outer loop: process each markered node in the document
511 MarkerMap::iterator end = m_markers.end();
512 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
513 Node* node = i->key.get();
514
515 // inner loop: process each marker in the current node
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100516 MarkerList* list = i->value.get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100517 bool nodeNeedsRepaint = false;
518 for (size_t i = 0; i != list->size(); ++i) {
519 DocumentMarker marker = list->at(i);
520
521 // skip nodes that are not of the specified type
522 if (markerTypes.contains(marker.type())) {
523 nodeNeedsRepaint = true;
524 break;
525 }
526 }
527
528 if (!nodeNeedsRepaint)
529 continue;
530
531 // cause the node to be redrawn
532 if (RenderObject* renderer = node->renderer())
533 renderer->repaint();
534 }
535}
536
537void DocumentMarkerController::invalidateRenderedRectsForMarkersInRect(const LayoutRect& r)
538{
539 // outer loop: process each markered node in the document
540 MarkerMap::iterator end = m_markers.end();
541 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
542
543 // inner loop: process each rect in the current node
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100544 MarkerList* list = i->value.get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100545 for (size_t listIndex = 0; listIndex < list->size(); ++listIndex)
546 list->at(listIndex).invalidate(r);
547 }
548}
549
550void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta)
551{
552 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
553 return;
554 ASSERT(!m_markers.isEmpty());
555
556 MarkerList* list = m_markers.get(node);
557 if (!list)
558 return;
559
560 bool docDirty = false;
561 for (size_t i = 0; i != list->size(); ++i) {
562 RenderedDocumentMarker& marker = list->at(i);
563 if (marker.startOffset() >= startOffset) {
564 ASSERT((int)marker.startOffset() + delta >= 0);
565 marker.shiftOffsets(delta);
566 docDirty = true;
567
568 // Marker moved, so previously-computed rendered rectangle is now invalid
569 marker.invalidate();
570 }
571 }
572
573 // repaint the affected node
574 if (docDirty && node->renderer())
575 node->renderer()->repaint();
576}
577
578void DocumentMarkerController::setMarkersActive(Range* range, bool active)
579{
580 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
581 return;
582 ASSERT(!m_markers.isEmpty());
583
584 Node* startContainer = range->startContainer();
585 Node* endContainer = range->endContainer();
586
587 Node* pastLastNode = range->pastLastNode();
588
589 for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(node)) {
590 int startOffset = node == startContainer ? range->startOffset() : 0;
591 int endOffset = node == endContainer ? range->endOffset() : INT_MAX;
592 setMarkersActive(node, startOffset, endOffset, active);
593 }
594}
595
596void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active)
597{
598 MarkerList* list = m_markers.get(node);
599 if (!list)
600 return;
601
602 bool docDirty = false;
603 for (size_t i = 0; i != list->size(); ++i) {
604 DocumentMarker& marker = list->at(i);
605
606 // Markers are returned in order, so stop if we are now past the specified range.
607 if (marker.startOffset() >= endOffset)
608 break;
609
610 // Skip marker that is wrong type or before target.
611 if (marker.endOffset() < startOffset || marker.type() != DocumentMarker::TextMatch)
612 continue;
613
614 marker.setActiveMatch(active);
615 docDirty = true;
616 }
617
618 // repaint the affected node
619 if (docDirty && node->renderer())
620 node->renderer()->repaint();
621}
622
623bool DocumentMarkerController::hasMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes)
624{
625 if (!possiblyHasMarkers(markerTypes))
626 return false;
627 ASSERT(!m_markers.isEmpty());
628
629 Node* startContainer = range->startContainer();
630 ASSERT(startContainer);
631 Node* endContainer = range->endContainer();
632 ASSERT(endContainer);
633
634 Node* pastLastNode = range->pastLastNode();
635 for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(node)) {
636 Vector<DocumentMarker*> markers = markersFor(node);
637 Vector<DocumentMarker*>::const_iterator end = markers.end();
638 for (Vector<DocumentMarker*>::const_iterator it = markers.begin(); it != end; ++it) {
639 DocumentMarker* marker = *it;
640 if (!markerTypes.contains(marker->type()))
641 continue;
642 if (node == startContainer && marker->endOffset() <= static_cast<unsigned>(range->startOffset()))
643 continue;
644 if (node == endContainer && marker->startOffset() >= static_cast<unsigned>(range->endOffset()))
645 continue;
646 return true;
647 }
648 }
649 return false;
650}
651
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100652#ifndef NDEBUG
653void DocumentMarkerController::showMarkers() const
654{
655 fprintf(stderr, "%d nodes have markers:\n", m_markers.size());
656 MarkerMap::const_iterator end = m_markers.end();
657 for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
658 Node* node = nodeIterator->key.get();
659 fprintf(stderr, "%p", node);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100660 MarkerList* list = nodeIterator->value.get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100661 for (unsigned markerIndex = 0; markerIndex < list->size(); ++markerIndex) {
662 const DocumentMarker& marker = list->at(markerIndex);
663 fprintf(stderr, " %d:[%d:%d](%d)", marker.type(), marker.startOffset(), marker.endOffset(), marker.activeMatch());
664 }
665
666 fprintf(stderr, "\n");
667 }
668}
669#endif
670
671} // namespace WebCore
672
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100673#ifndef NDEBUG
674void showDocumentMarkers(const WebCore::DocumentMarkerController* controller)
675{
676 if (controller)
677 controller->showMarkers();
678}
679#endif