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 "DocumentMarkerController.h"
29
30 #include "Node.h"
31 #include "Range.h"
32 #include "TextIterator.h"
33
34 namespace WebCore {
35
placeholderRectForMarker()36 static IntRect placeholderRectForMarker()
37 {
38 return IntRect(-1, -1, -1, -1);
39 }
40
possiblyHasMarkers(DocumentMarker::MarkerTypes types)41 inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types)
42 {
43 return m_possiblyExistingMarkerTypes.intersects(types);
44 }
45
DocumentMarkerController()46 DocumentMarkerController::DocumentMarkerController()
47 : m_possiblyExistingMarkerTypes(0)
48 {
49 }
50
detach()51 void DocumentMarkerController::detach()
52 {
53 m_possiblyExistingMarkerTypes = 0;
54 if (m_markers.isEmpty())
55 return;
56 deleteAllValues(m_markers);
57 m_markers.clear();
58 }
59
addMarker(Range * range,DocumentMarker::MarkerType type,String description)60 void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type, String description)
61 {
62 // Use a TextIterator to visit the potentially multiple nodes the range covers.
63 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
64 RefPtr<Range> textPiece = markedText.range();
65 int exception = 0;
66 DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description, false};
67 addMarker(textPiece->startContainer(exception), marker);
68 }
69 }
70
removeMarkers(Range * range,DocumentMarker::MarkerTypes markerTypes,RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)71 void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
72 {
73 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
74 if (!possiblyHasMarkers(markerTypes))
75 return;
76 ASSERT(!m_markers.isEmpty());
77
78 RefPtr<Range> textPiece = markedText.range();
79 int startOffset = textPiece->startOffset();
80 int endOffset = textPiece->endOffset();
81 removeMarkers(textPiece->startContainer(), startOffset, endOffset - startOffset, markerTypes, shouldRemovePartiallyOverlappingMarker);
82 }
83 }
84
85 // Markers are stored in order sorted by their start offset.
86 // Markers of the same type do not overlap each other.
87
addMarker(Node * node,DocumentMarker newMarker)88 void DocumentMarkerController::addMarker(Node* node, DocumentMarker newMarker)
89 {
90 ASSERT(newMarker.endOffset >= newMarker.startOffset);
91 if (newMarker.endOffset == newMarker.startOffset)
92 return;
93
94 m_possiblyExistingMarkerTypes.add(newMarker.type);
95
96 MarkerMapVectorPair* vectorPair = m_markers.get(node);
97
98 if (!vectorPair) {
99 vectorPair = new MarkerMapVectorPair;
100 vectorPair->first.append(newMarker);
101 vectorPair->second.append(placeholderRectForMarker());
102 m_markers.set(node, vectorPair);
103 } else {
104 Vector<DocumentMarker>& markers = vectorPair->first;
105 Vector<IntRect>& rects = vectorPair->second;
106 size_t numMarkers = markers.size();
107 ASSERT(numMarkers == rects.size());
108 size_t i;
109 // Iterate over all markers whose start offset is less than or equal to the new marker's.
110 // If one of them is of the same type as the new marker and touches it or intersects with it
111 // (there is at most one), remove it and adjust the new marker's start offset to encompass it.
112 for (i = 0; i < numMarkers; ++i) {
113 DocumentMarker marker = markers[i];
114 if (marker.startOffset > newMarker.startOffset)
115 break;
116 if (marker.type == newMarker.type && marker.endOffset >= newMarker.startOffset) {
117 newMarker.startOffset = marker.startOffset;
118 markers.remove(i);
119 rects.remove(i);
120 numMarkers--;
121 break;
122 }
123 }
124 size_t j = i;
125 // Iterate over all markers whose end offset is less than or equal to the new marker's,
126 // removing markers of the same type as the new marker which touch it or intersect with it,
127 // adjusting the new marker's end offset to cover them if necessary.
128 while (j < numMarkers) {
129 DocumentMarker marker = markers[j];
130 if (marker.startOffset > newMarker.endOffset)
131 break;
132 if (marker.type == newMarker.type) {
133 markers.remove(j);
134 rects.remove(j);
135 if (newMarker.endOffset <= marker.endOffset) {
136 newMarker.endOffset = marker.endOffset;
137 break;
138 }
139 numMarkers--;
140 } else
141 j++;
142 }
143 // At this point i points to the node before which we want to insert.
144 markers.insert(i, newMarker);
145 rects.insert(i, placeholderRectForMarker());
146 }
147
148 // repaint the affected node
149 if (node->renderer())
150 node->renderer()->repaint();
151 }
152
153 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
154 // 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)155 void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta)
156 {
157 if (length <= 0)
158 return;
159
160 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
161 return;
162 ASSERT(!m_markers.isEmpty());
163
164 MarkerMapVectorPair* vectorPair = m_markers.get(srcNode);
165 if (!vectorPair)
166 return;
167
168 ASSERT(vectorPair->first.size() == vectorPair->second.size());
169
170 bool docDirty = false;
171 unsigned endOffset = startOffset + length - 1;
172 Vector<DocumentMarker>& markers = vectorPair->first;
173 for (size_t i = 0; i != markers.size(); ++i) {
174 DocumentMarker marker = markers[i];
175
176 // stop if we are now past the specified range
177 if (marker.startOffset > endOffset)
178 break;
179
180 // skip marker that is before the specified range or is the wrong type
181 if (marker.endOffset < startOffset)
182 continue;
183
184 // pin the marker to the specified range and apply the shift delta
185 docDirty = true;
186 if (marker.startOffset < startOffset)
187 marker.startOffset = startOffset;
188 if (marker.endOffset > endOffset)
189 marker.endOffset = endOffset;
190 marker.startOffset += delta;
191 marker.endOffset += delta;
192
193 addMarker(dstNode, marker);
194 }
195
196 // repaint the affected node
197 if (docDirty && dstNode->renderer())
198 dstNode->renderer()->repaint();
199 }
200
removeMarkers(Node * node,unsigned startOffset,int length,DocumentMarker::MarkerTypes markerTypes,RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)201 void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
202 {
203 if (length <= 0)
204 return;
205
206 if (!possiblyHasMarkers(markerTypes))
207 return;
208 ASSERT(!(m_markers.isEmpty()));
209
210 MarkerMapVectorPair* vectorPair = m_markers.get(node);
211 if (!vectorPair)
212 return;
213
214 Vector<DocumentMarker>& markers = vectorPair->first;
215 Vector<IntRect>& rects = vectorPair->second;
216 ASSERT(markers.size() == rects.size());
217 bool docDirty = false;
218 unsigned endOffset = startOffset + length;
219 for (size_t i = 0; i < markers.size();) {
220 DocumentMarker marker = markers[i];
221
222 // markers are returned in order, so stop if we are now past the specified range
223 if (marker.startOffset >= endOffset)
224 break;
225
226 // skip marker that is wrong type or before target
227 if (marker.endOffset <= startOffset || !markerTypes.contains(marker.type)) {
228 i++;
229 continue;
230 }
231
232 // at this point we know that marker and target intersect in some way
233 docDirty = true;
234
235 // pitch the old marker and any associated rect
236 markers.remove(i);
237 rects.remove(i);
238
239 if (shouldRemovePartiallyOverlappingMarker)
240 // Stop here. Don't add resulting slices back.
241 continue;
242
243 // add either of the resulting slices that are left after removing target
244 if (startOffset > marker.startOffset) {
245 DocumentMarker newLeft = marker;
246 newLeft.endOffset = startOffset;
247 markers.insert(i, newLeft);
248 rects.insert(i, placeholderRectForMarker());
249 // i now points to the newly-inserted node, but we want to skip that one
250 i++;
251 }
252 if (marker.endOffset > endOffset) {
253 DocumentMarker newRight = marker;
254 newRight.startOffset = endOffset;
255 markers.insert(i, newRight);
256 rects.insert(i, placeholderRectForMarker());
257 // i now points to the newly-inserted node, but we want to skip that one
258 i++;
259 }
260 }
261
262 if (markers.isEmpty()) {
263 ASSERT(rects.isEmpty());
264 m_markers.remove(node);
265 delete vectorPair;
266 }
267
268 if (m_markers.isEmpty())
269 m_possiblyExistingMarkerTypes = 0;
270
271 // repaint the affected node
272 if (docDirty && node->renderer())
273 node->renderer()->repaint();
274 }
275
markerContainingPoint(const IntPoint & point,DocumentMarker::MarkerType markerType)276 DocumentMarker* DocumentMarkerController::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType)
277 {
278 if (!possiblyHasMarkers(markerType))
279 return 0;
280 ASSERT(!(m_markers.isEmpty()));
281
282 // outer loop: process each node that contains any markers
283 MarkerMap::iterator end = m_markers.end();
284 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
285 // inner loop; process each marker in this node
286 MarkerMapVectorPair* vectorPair = nodeIterator->second;
287 Vector<DocumentMarker>& markers = vectorPair->first;
288 Vector<IntRect>& rects = vectorPair->second;
289 ASSERT(markers.size() == rects.size());
290 unsigned markerCount = markers.size();
291 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
292 DocumentMarker& marker = markers[markerIndex];
293
294 // skip marker that is wrong type
295 if (marker.type != markerType)
296 continue;
297
298 IntRect& r = rects[markerIndex];
299
300 // skip placeholder rects
301 if (r == placeholderRectForMarker())
302 continue;
303
304 if (r.contains(point))
305 return ▮
306 }
307 }
308
309 return 0;
310 }
311
markersForNode(Node * node)312 Vector<DocumentMarker> DocumentMarkerController::markersForNode(Node* node)
313 {
314 MarkerMapVectorPair* vectorPair = m_markers.get(node);
315 if (vectorPair)
316 return vectorPair->first;
317 return Vector<DocumentMarker>();
318 }
319
markersInRange(Range * range,DocumentMarker::MarkerType markerType)320 Vector<DocumentMarker> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerType markerType)
321 {
322 if (!possiblyHasMarkers(markerType))
323 return Vector<DocumentMarker>();
324
325 Vector<DocumentMarker> foundMarkers;
326
327 Node* startContainer = range->startContainer();
328 ASSERT(startContainer);
329 Node* endContainer = range->endContainer();
330 ASSERT(endContainer);
331
332 Node* pastLastNode = range->pastLastNode();
333 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
334 Vector<DocumentMarker> markers = markersForNode(node);
335 Vector<DocumentMarker>::const_iterator end = markers.end();
336 for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) {
337 if (markerType != it->type)
338 continue;
339 if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset()))
340 continue;
341 if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset()))
342 continue;
343 foundMarkers.append(*it);
344 }
345 }
346 return foundMarkers;
347 }
348
renderedRectsForMarkers(DocumentMarker::MarkerType markerType)349 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
350 {
351 Vector<IntRect> result;
352
353 if (!possiblyHasMarkers(markerType))
354 return result;
355 ASSERT(!(m_markers.isEmpty()));
356
357 // outer loop: process each node
358 MarkerMap::iterator end = m_markers.end();
359 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
360 // inner loop; process each marker in this node
361 MarkerMapVectorPair* vectorPair = nodeIterator->second;
362 Vector<DocumentMarker>& markers = vectorPair->first;
363 Vector<IntRect>& rects = vectorPair->second;
364 ASSERT(markers.size() == rects.size());
365 unsigned markerCount = markers.size();
366 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
367 DocumentMarker marker = markers[markerIndex];
368
369 // skip marker that is wrong type
370 if (marker.type != markerType)
371 continue;
372
373 IntRect r = rects[markerIndex];
374 // skip placeholder rects
375 if (r == placeholderRectForMarker())
376 continue;
377
378 result.append(r);
379 }
380 }
381
382 return result;
383 }
384
removeMarkers(Node * node,DocumentMarker::MarkerTypes markerTypes)385 void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerTypes markerTypes)
386 {
387 if (!possiblyHasMarkers(markerTypes))
388 return;
389 ASSERT(!m_markers.isEmpty());
390
391 MarkerMap::iterator iterator = m_markers.find(node);
392 if (iterator != m_markers.end())
393 removeMarkersFromMarkerMapVectorPair(node, iterator->second, markerTypes);
394 }
395
removeMarkers(DocumentMarker::MarkerTypes markerTypes)396 void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerTypes)
397 {
398 if (!possiblyHasMarkers(markerTypes))
399 return;
400 ASSERT(!m_markers.isEmpty());
401
402 // outer loop: process each markered node in the document
403 MarkerMap markerMapCopy = m_markers;
404 MarkerMap::iterator end = markerMapCopy.end();
405 for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) {
406 Node* node = i->first.get();
407 MarkerMapVectorPair* vectorPair = i->second;
408 removeMarkersFromMarkerMapVectorPair(node, vectorPair, markerTypes);
409 }
410
411 m_possiblyExistingMarkerTypes.remove(markerTypes);
412 }
413
414 // This function may release node and vectorPair.
removeMarkersFromMarkerMapVectorPair(Node * node,MarkerMapVectorPair * vectorPair,DocumentMarker::MarkerTypes markerTypes)415 void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, MarkerMapVectorPair* vectorPair, DocumentMarker::MarkerTypes markerTypes)
416 {
417 if (markerTypes == DocumentMarker::AllMarkers()) {
418 delete vectorPair;
419 m_markers.remove(node);
420 if (RenderObject* renderer = node->renderer())
421 renderer->repaint();
422 } else {
423 bool needsRepaint = false;
424 Vector<DocumentMarker>& markers = vectorPair->first;
425 Vector<IntRect>& rects = vectorPair->second;
426 ASSERT(markers.size() == rects.size());
427 for (size_t i = 0; i != markers.size();) {
428 DocumentMarker marker = markers[i];
429
430 // skip nodes that are not of the specified type
431 if (!markerTypes.contains(marker.type)) {
432 ++i;
433 continue;
434 }
435
436 // pitch the old marker
437 markers.remove(i);
438 rects.remove(i);
439 needsRepaint = true;
440 // i now is the index of the next marker
441 }
442
443 // Redraw the node if it changed. Do this before the node is removed from m_markers, since
444 // m_markers might contain the last reference to the node.
445 if (needsRepaint) {
446 RenderObject* renderer = node->renderer();
447 if (renderer)
448 renderer->repaint();
449 }
450
451 // delete the node's list if it is now empty
452 if (markers.isEmpty()) {
453 ASSERT(rects.isEmpty());
454 m_markers.remove(node);
455 delete vectorPair;
456 }
457 }
458 if (m_markers.isEmpty())
459 m_possiblyExistingMarkerTypes = 0;
460 }
461
repaintMarkers(DocumentMarker::MarkerTypes markerTypes)462 void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes markerTypes)
463 {
464 if (!possiblyHasMarkers(markerTypes))
465 return;
466 ASSERT(!m_markers.isEmpty());
467
468 // outer loop: process each markered node in the document
469 MarkerMap::iterator end = m_markers.end();
470 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
471 Node* node = i->first.get();
472
473 // inner loop: process each marker in the current node
474 MarkerMapVectorPair* vectorPair = i->second;
475 Vector<DocumentMarker>& markers = vectorPair->first;
476 bool nodeNeedsRepaint = false;
477 for (size_t i = 0; i != markers.size(); ++i) {
478 DocumentMarker marker = markers[i];
479
480 // skip nodes that are not of the specified type
481 if (markerTypes.contains(marker.type)) {
482 nodeNeedsRepaint = true;
483 break;
484 }
485 }
486
487 if (!nodeNeedsRepaint)
488 continue;
489
490 // cause the node to be redrawn
491 if (RenderObject* renderer = node->renderer())
492 renderer->repaint();
493 }
494 }
495
setRenderedRectForMarker(Node * node,const DocumentMarker & marker,const IntRect & r)496 void DocumentMarkerController::setRenderedRectForMarker(Node* node, const DocumentMarker& marker, const IntRect& r)
497 {
498 MarkerMapVectorPair* vectorPair = m_markers.get(node);
499 if (!vectorPair) {
500 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
501 return;
502 }
503
504 Vector<DocumentMarker>& markers = vectorPair->first;
505 ASSERT(markers.size() == vectorPair->second.size());
506 unsigned markerCount = markers.size();
507 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
508 DocumentMarker m = markers[markerIndex];
509 if (m == marker) {
510 vectorPair->second[markerIndex] = r;
511 return;
512 }
513 }
514
515 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
516 }
517
invalidateRenderedRectsForMarkersInRect(const IntRect & r)518 void DocumentMarkerController::invalidateRenderedRectsForMarkersInRect(const IntRect& r)
519 {
520 // outer loop: process each markered node in the document
521 MarkerMap::iterator end = m_markers.end();
522 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
523
524 // inner loop: process each rect in the current node
525 MarkerMapVectorPair* vectorPair = i->second;
526 Vector<IntRect>& rects = vectorPair->second;
527
528 unsigned rectCount = rects.size();
529 for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex)
530 if (rects[rectIndex].intersects(r))
531 rects[rectIndex] = placeholderRectForMarker();
532 }
533 }
534
shiftMarkers(Node * node,unsigned startOffset,int delta)535 void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta)
536 {
537 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
538 return;
539 ASSERT(!m_markers.isEmpty());
540
541 MarkerMapVectorPair* vectorPair = m_markers.get(node);
542 if (!vectorPair)
543 return;
544
545 Vector<DocumentMarker>& markers = vectorPair->first;
546 Vector<IntRect>& rects = vectorPair->second;
547 ASSERT(markers.size() == rects.size());
548
549 bool docDirty = false;
550 for (size_t i = 0; i != markers.size(); ++i) {
551 DocumentMarker& marker = markers[i];
552 if (marker.startOffset >= startOffset) {
553 ASSERT((int)marker.startOffset + delta >= 0);
554 marker.startOffset += delta;
555 marker.endOffset += delta;
556 docDirty = true;
557
558 // Marker moved, so previously-computed rendered rectangle is now invalid
559 rects[i] = placeholderRectForMarker();
560 }
561 }
562
563 // repaint the affected node
564 if (docDirty && node->renderer())
565 node->renderer()->repaint();
566 }
567
setMarkersActive(Range * range,bool active)568 void DocumentMarkerController::setMarkersActive(Range* range, bool active)
569 {
570 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
571 return;
572 ASSERT(!m_markers.isEmpty());
573
574 ExceptionCode ec = 0;
575 Node* startContainer = range->startContainer(ec);
576 Node* endContainer = range->endContainer(ec);
577
578 Node* pastLastNode = range->pastLastNode();
579 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
580 int startOffset = node == startContainer ? range->startOffset(ec) : 0;
581 int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
582 setMarkersActive(node, startOffset, endOffset, active);
583 }
584 }
585
setMarkersActive(Node * node,unsigned startOffset,unsigned endOffset,bool active)586 void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active)
587 {
588 MarkerMapVectorPair* vectorPair = m_markers.get(node);
589 if (!vectorPair)
590 return;
591
592 Vector<DocumentMarker>& markers = vectorPair->first;
593 ASSERT(markers.size() == vectorPair->second.size());
594
595 bool docDirty = false;
596 for (size_t i = 0; i != markers.size(); ++i) {
597 DocumentMarker& marker = markers[i];
598
599 // Markers are returned in order, so stop if we are now past the specified range.
600 if (marker.startOffset >= endOffset)
601 break;
602
603 // Skip marker that is wrong type or before target.
604 if (marker.endOffset < startOffset || marker.type != DocumentMarker::TextMatch)
605 continue;
606
607 marker.activeMatch = active;
608 docDirty = true;
609 }
610
611 // repaint the affected node
612 if (docDirty && node->renderer())
613 node->renderer()->repaint();
614 }
615
hasMarkers(Range * range,DocumentMarker::MarkerTypes markerTypes)616 bool DocumentMarkerController::hasMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes)
617 {
618 if (!possiblyHasMarkers(markerTypes))
619 return false;
620 ASSERT(!m_markers.isEmpty());
621
622 Node* startContainer = range->startContainer();
623 ASSERT(startContainer);
624 Node* endContainer = range->endContainer();
625 ASSERT(endContainer);
626
627 Node* pastLastNode = range->pastLastNode();
628 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
629 Vector<DocumentMarker> markers = markersForNode(node);
630 Vector<DocumentMarker>::const_iterator end = markers.end();
631 for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) {
632 if (!markerTypes.contains(it->type))
633 continue;
634 if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset()))
635 continue;
636 if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset()))
637 continue;
638 return true;
639 }
640 }
641 return false;
642 }
643
clearDescriptionOnMarkersIntersectingRange(Range * range,DocumentMarker::MarkerTypes markerTypes)644 void DocumentMarkerController::clearDescriptionOnMarkersIntersectingRange(Range* range, DocumentMarker::MarkerTypes markerTypes)
645 {
646 if (!possiblyHasMarkers(markerTypes))
647 return;
648 ASSERT(!m_markers.isEmpty());
649
650 Node* startContainer = range->startContainer();
651 Node* endContainer = range->endContainer();
652
653 Node* pastLastNode = range->pastLastNode();
654 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
655 unsigned startOffset = node == startContainer ? range->startOffset() : 0;
656 unsigned endOffset = node == endContainer ? static_cast<unsigned>(range->endOffset()) : std::numeric_limits<unsigned>::max();
657 MarkerMapVectorPair* vectorPair = m_markers.get(node);
658 if (!vectorPair)
659 continue;
660
661 Vector<DocumentMarker>& markers = vectorPair->first;
662 for (size_t i = 0; i < markers.size(); ++i) {
663 DocumentMarker& marker = markers[i];
664
665 // markers are returned in order, so stop if we are now past the specified range
666 if (marker.startOffset >= endOffset)
667 break;
668
669 // skip marker that is wrong type or before target
670 if (marker.endOffset <= startOffset || !markerTypes.contains(marker.type)) {
671 i++;
672 continue;
673 }
674
675 marker.description = String();
676 }
677 }
678 }
679
680 #ifndef NDEBUG
showMarkers() const681 void DocumentMarkerController::showMarkers() const
682 {
683 fprintf(stderr, "%d nodes have markers:\n", m_markers.size());
684 MarkerMap::const_iterator end = m_markers.end();
685 for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
686 Node* node = nodeIterator->first.get();
687 fprintf(stderr, "%p", node);
688 MarkerMapVectorPair* vectorPair = nodeIterator->second;
689 Vector<DocumentMarker>& markers = vectorPair->first;
690 unsigned markerCount = markers.size();
691 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex)
692 fprintf(stderr, " %d:[%d:%d](%d)", markers[markerIndex].type, markers[markerIndex].startOffset, markers[markerIndex].endOffset, markers[markerIndex].activeMatch);
693 fprintf(stderr, "\n");
694 }
695 }
696 #endif
697
698 } // namespace WebCore
699
700
701 #ifndef NDEBUG
showDocumentMarkers(const WebCore::DocumentMarkerController * controller)702 void showDocumentMarkers(const WebCore::DocumentMarkerController* controller)
703 {
704 if (controller)
705 controller->showMarkers();
706 }
707 #endif
708