Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  *           (C) 2006 Alexey Proskuryakov (ap (at) 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 inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types)
     44 {
     45     return m_possiblyExistingMarkerTypes.intersects(types);
     46 }
     47 
     48 DocumentMarkerController::DocumentMarkerController()
     49     : m_possiblyExistingMarkerTypes(0)
     50 {
     51 }
     52 
     53 DocumentMarkerController::~DocumentMarkerController()
     54 {
     55 }
     56 
     57 void DocumentMarkerController::detach()
     58 {
     59     m_markers.clear();
     60     m_possiblyExistingMarkerTypes = 0;
     61 }
     62 
     63 void 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 
     72 void 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 
     81 void 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 
     91 void DocumentMarkerController::addMarkerToNode(Node* node, unsigned startOffset, unsigned length, DocumentMarker::MarkerType type)
     92 {
     93     addMarker(node, DocumentMarker(type, startOffset, startOffset + length));
     94 }
     95 
     96 void 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 
    102 void 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 
    122 void 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 
    139 void DocumentMarkerController::addMarker(Node* node, const DocumentMarker& newMarker)
    140 {
    141     ASSERT(newMarker.endOffset() >= newMarker.startOffset());
    142     if (newMarker.endOffset() == newMarker.startOffset())
    143         return;
    144 
    145     m_possiblyExistingMarkerTypes.add(newMarker.type());
    146 
    147     OwnPtr<MarkerList>& list = m_markers.add(node, nullptr).iterator->value;
    148 
    149     if (!list) {
    150         list = adoptPtr(new MarkerList);
    151         list->append(RenderedDocumentMarker(newMarker));
    152     } 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.
    199 void 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 
    241 void 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);
    298         if (m_markers.isEmpty())
    299             m_possiblyExistingMarkerTypes = 0;
    300     }
    301 
    302     // repaint the affected node
    303     if (docDirty && node->renderer())
    304         node->renderer()->repaint();
    305 }
    306 
    307 DocumentMarker* 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
    317         MarkerList* list = nodeIterator->value.get();
    318         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 
    334 Vector<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
    350 Vector<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 
    363 Vector<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 
    373 Vector<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 
    403 Vector<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
    415         MarkerList* list = nodeIterator->value.get();
    416         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 
    434 void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerTypes markerTypes)
    435 {
    436     if (!possiblyHasMarkers(markerTypes))
    437         return;
    438     ASSERT(!m_markers.isEmpty());
    439 
    440     MarkerMap::iterator iterator = m_markers.find(node);
    441     if (iterator != m_markers.end())
    442         removeMarkersFromList(iterator, markerTypes);
    443 }
    444 
    445 void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerTypes)
    446 {
    447     if (!possiblyHasMarkers(markerTypes))
    448         return;
    449     ASSERT(!m_markers.isEmpty());
    450 
    451     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 
    460     m_possiblyExistingMarkerTypes.remove(markerTypes);
    461 }
    462 
    463 void DocumentMarkerController::removeMarkersFromList(MarkerMap::iterator iterator, DocumentMarker::MarkerTypes markerTypes)
    464 {
    465     bool needsRepainting = false;
    466     bool listCanBeRemoved;
    467 
    468     if (markerTypes == DocumentMarker::AllMarkers()) {
    469         needsRepainting = true;
    470         listCanBeRemoved = true;
    471     } else {
    472         MarkerList* list = iterator->value.get();
    473 
    474         for (size_t i = 0; i != list->size(); ) {
    475             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);
    485             needsRepainting = true;
    486             // i now is the index of the next marker
    487         }
    488 
    489         listCanBeRemoved = list->isEmpty();
    490     }
    491 
    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     }
    502 }
    503 
    504 void 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
    516         MarkerList* list = i->value.get();
    517         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 
    537 void 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
    544         MarkerList* list = i->value.get();
    545         for (size_t listIndex = 0; listIndex < list->size(); ++listIndex)
    546             list->at(listIndex).invalidate(r);
    547     }
    548 }
    549 
    550 void 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 
    578 void 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 
    596 void 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 
    623 bool 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 
    652 #ifndef NDEBUG
    653 void 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);
    660         MarkerList* list = nodeIterator->value.get();
    661         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 
    673 #ifndef NDEBUG
    674 void showDocumentMarkers(const WebCore::DocumentMarkerController* controller)
    675 {
    676     if (controller)
    677         controller->showMarkers();
    678 }
    679 #endif
    680