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/dom/Text.h"
     35 #include "core/editing/TextIterator.h"
     36 #include "core/rendering/RenderObject.h"
     37 
     38 #ifndef NDEBUG
     39 #include <stdio.h>
     40 #endif
     41 
     42 namespace blink {
     43 
     44 MarkerRemoverPredicate::MarkerRemoverPredicate(const Vector<String>& words)
     45     : m_words(words)
     46 {
     47 }
     48 
     49 bool MarkerRemoverPredicate::operator()(const DocumentMarker& documentMarker, const Text& textNode) const
     50 {
     51     unsigned start  = documentMarker.startOffset();
     52     unsigned length = documentMarker.endOffset() - documentMarker.startOffset();
     53 
     54     String markerText = textNode.data().substring(start, length);
     55     return m_words.contains(markerText);
     56 }
     57 
     58 namespace {
     59 
     60 DocumentMarker::MarkerTypeIndex MarkerTypeToMarkerIndex(DocumentMarker::MarkerType type)
     61 {
     62     switch (type) {
     63     case DocumentMarker::Spelling:
     64         return DocumentMarker::SpellingMarkerIndex;
     65     case DocumentMarker::Grammar:
     66         return DocumentMarker::GramarMarkerIndex;
     67     case DocumentMarker::TextMatch:
     68         return DocumentMarker::TextMatchMarkerIndex;
     69     case DocumentMarker::InvisibleSpellcheck:
     70         return DocumentMarker::InvisibleSpellcheckMarkerIndex;
     71     }
     72 
     73     ASSERT_NOT_REACHED();
     74     return DocumentMarker::SpellingMarkerIndex;
     75 }
     76 
     77 } // namespace
     78 
     79 inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types)
     80 {
     81     return m_possiblyExistingMarkerTypes.intersects(types);
     82 }
     83 
     84 DocumentMarkerController::DocumentMarkerController()
     85     : m_possiblyExistingMarkerTypes(0)
     86 {
     87 }
     88 
     89 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(DocumentMarkerController);
     90 
     91 void DocumentMarkerController::clear()
     92 {
     93     m_markers.clear();
     94     m_possiblyExistingMarkerTypes = 0;
     95 }
     96 
     97 void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type, const String& description, uint32_t hash)
     98 {
     99     // Use a TextIterator to visit the potentially multiple nodes the range covers.
    100     for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
    101         addMarker(markedText.startContainer(), DocumentMarker(type, markedText.startOffset(), markedText.endOffset(), description, hash));
    102     }
    103 }
    104 
    105 void DocumentMarkerController::addMarker(const Position& start, const Position& end, DocumentMarker::MarkerType type, const String& description, uint32_t hash)
    106 {
    107     // Use a TextIterator to visit the potentially multiple nodes the range covers.
    108     for (TextIterator markedText(start, end); !markedText.atEnd(); markedText.advance()) {
    109         addMarker(markedText.startContainer(), DocumentMarker(type, markedText.startOffset(), markedText.endOffset(), description, hash));
    110     }
    111 }
    112 
    113 void DocumentMarkerController::addTextMatchMarker(const Range* range, bool activeMatch)
    114 {
    115     // Use a TextIterator to visit the potentially multiple nodes the range covers.
    116     for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
    117         unsigned startOffset = markedText.startOffset();
    118         unsigned endOffset = markedText.endOffset();
    119         addMarker(markedText.startContainer(), DocumentMarker(startOffset, endOffset, activeMatch));
    120         if (endOffset > startOffset) {
    121             // Rendered rects for markers in WebKit are not populated until each time
    122             // the markers are painted. However, we need it to happen sooner, because
    123             // the whole purpose of tickmarks on the scrollbar is to show where
    124             // matches off-screen are (that haven't been painted yet).
    125             Node* node = markedText.startContainer();
    126             DocumentMarkerVector markers = markersFor(node);
    127             toRenderedDocumentMarker(markers[markers.size() - 1])->setRenderedRect(range->boundingBox());
    128         }
    129     }
    130 }
    131 
    132 void DocumentMarkerController::prepareForDestruction()
    133 {
    134     clear();
    135 }
    136 
    137 void DocumentMarkerController::removeMarkers(TextIterator& markedText, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
    138 {
    139     for (; !markedText.atEnd(); markedText.advance()) {
    140         if (!possiblyHasMarkers(markerTypes))
    141             return;
    142         ASSERT(!m_markers.isEmpty());
    143 
    144         int startOffset = markedText.startOffset();
    145         int endOffset = markedText.endOffset();
    146         removeMarkers(markedText.startContainer(), startOffset, endOffset - startOffset, markerTypes, shouldRemovePartiallyOverlappingMarker);
    147     }
    148 }
    149 
    150 void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
    151 {
    152     TextIterator markedText(range);
    153     DocumentMarkerController::removeMarkers(markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
    154 }
    155 
    156 void DocumentMarkerController::removeMarkers(const Position& start, const Position& end, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
    157 {
    158     TextIterator markedText(start, end);
    159     DocumentMarkerController::removeMarkers(markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
    160 }
    161 
    162 static bool startsFurther(const OwnPtrWillBeMember<RenderedDocumentMarker>& lhv, const DocumentMarker* rhv)
    163 {
    164     return lhv->startOffset() < rhv->startOffset();
    165 }
    166 
    167 static bool startsAfter(const OwnPtrWillBeMember<RenderedDocumentMarker>& marker, size_t startOffset)
    168 {
    169     return marker->startOffset() < startOffset;
    170 }
    171 
    172 static bool endsBefore(size_t startOffset, const OwnPtrWillBeMember<RenderedDocumentMarker>& rhv)
    173 {
    174     return startOffset < rhv->endOffset();
    175 }
    176 
    177 static bool compareByStart(const RawPtrWillBeMember<DocumentMarker>& lhv, const RawPtrWillBeMember<DocumentMarker>& rhv)
    178 {
    179     return lhv->startOffset() < rhv->startOffset();
    180 }
    181 
    182 static bool doesNotOverlap(const OwnPtrWillBeMember<RenderedDocumentMarker>& lhv, const DocumentMarker* rhv)
    183 {
    184     return lhv->endOffset() < rhv->startOffset();
    185 }
    186 
    187 static bool doesNotInclude(const OwnPtrWillBeMember<RenderedDocumentMarker>& marker, size_t startOffset)
    188 {
    189     return marker->endOffset() < startOffset;
    190 }
    191 
    192 // Markers are stored in order sorted by their start offset.
    193 // Markers of the same type do not overlap each other.
    194 
    195 void DocumentMarkerController::addMarker(Node* node, const DocumentMarker& newMarker)
    196 {
    197     ASSERT(newMarker.endOffset() >= newMarker.startOffset());
    198     if (newMarker.endOffset() == newMarker.startOffset())
    199         return;
    200 
    201     m_possiblyExistingMarkerTypes.add(newMarker.type());
    202 
    203     OwnPtrWillBeMember<MarkerLists>& markers = m_markers.add(node, nullptr).storedValue->value;
    204     if (!markers) {
    205         markers = adoptPtrWillBeNoop(new MarkerLists);
    206         markers->grow(DocumentMarker::MarkerTypeIndexesCount);
    207     }
    208 
    209     DocumentMarker::MarkerTypeIndex markerListIndex = MarkerTypeToMarkerIndex(newMarker.type());
    210     if (!markers->at(markerListIndex)) {
    211         markers->insert(markerListIndex, adoptPtrWillBeNoop(new MarkerList));
    212     }
    213 
    214     OwnPtrWillBeMember<MarkerList>& list = markers->at(markerListIndex);
    215     if (list->isEmpty() || list->last()->endOffset() < newMarker.startOffset()) {
    216         list->append(RenderedDocumentMarker::create(newMarker));
    217     } else {
    218         DocumentMarker toInsert(newMarker);
    219         if (toInsert.type() != DocumentMarker::TextMatch) {
    220             mergeOverlapping(list.get(), toInsert);
    221         } else {
    222             MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(), &toInsert, startsFurther);
    223             list->insert(pos - list->begin(), RenderedDocumentMarker::create(toInsert));
    224         }
    225     }
    226 
    227     // repaint the affected node
    228     if (node->renderer())
    229         node->renderer()->setShouldDoFullPaintInvalidation(true);
    230 }
    231 
    232 void DocumentMarkerController::mergeOverlapping(MarkerList* list, DocumentMarker& toInsert)
    233 {
    234     MarkerList::iterator firstOverlapping = std::lower_bound(list->begin(), list->end(), &toInsert, doesNotOverlap);
    235     size_t index = firstOverlapping - list->begin();
    236     list->insert(index, RenderedDocumentMarker::create(toInsert));
    237     MarkerList::iterator inserted = list->begin() + index;
    238     firstOverlapping = inserted + 1;
    239     for (MarkerList::iterator i = firstOverlapping; i != list->end() && (*i)->startOffset() <= (*inserted)->endOffset(); ) {
    240         (*inserted)->setStartOffset(std::min((*inserted)->startOffset(), (*i)->startOffset()));
    241         (*inserted)->setEndOffset(std::max((*inserted)->endOffset(), (*i)->endOffset()));
    242         list->remove(i - list->begin());
    243     }
    244 }
    245 
    246 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies.  The shift is
    247 // useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode.
    248 void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta)
    249 {
    250     if (length <= 0)
    251         return;
    252 
    253     if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
    254         return;
    255     ASSERT(!m_markers.isEmpty());
    256 
    257     MarkerLists* markers = m_markers.get(srcNode);
    258     if (!markers)
    259         return;
    260 
    261     bool docDirty = false;
    262     for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    263         OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    264         if (!list)
    265             continue;
    266 
    267         unsigned endOffset = startOffset + length - 1;
    268         MarkerList::iterator startPos = std::lower_bound(list->begin(), list->end(), startOffset, doesNotInclude);
    269         for (MarkerList::iterator i = startPos; i != list->end(); ++i) {
    270             DocumentMarker* marker = i->get();
    271 
    272             // stop if we are now past the specified range
    273             if (marker->startOffset() > endOffset)
    274                 break;
    275 
    276             // pin the marker to the specified range and apply the shift delta
    277             docDirty = true;
    278             if (marker->startOffset() < startOffset)
    279                 marker->setStartOffset(startOffset);
    280             if (marker->endOffset() > endOffset)
    281                 marker->setEndOffset(endOffset);
    282             marker->shiftOffsets(delta);
    283 
    284             addMarker(dstNode, *marker);
    285         }
    286     }
    287 
    288     // repaint the affected node
    289     if (docDirty && dstNode->renderer())
    290         dstNode->renderer()->setShouldDoFullPaintInvalidation(true);
    291 }
    292 
    293 void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
    294 {
    295     if (length <= 0)
    296         return;
    297 
    298     if (!possiblyHasMarkers(markerTypes))
    299         return;
    300     ASSERT(!(m_markers.isEmpty()));
    301 
    302     MarkerLists* markers = m_markers.get(node);
    303     if (!markers)
    304         return;
    305 
    306     bool docDirty = false;
    307     size_t emptyListsCount = 0;
    308     for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    309         OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    310         if (!list || list->isEmpty()) {
    311             if (list.get() && list->isEmpty())
    312                 list.clear();
    313             ++emptyListsCount;
    314             continue;
    315         }
    316         if (!markerTypes.contains((*list->begin())->type()))
    317             continue;
    318         unsigned endOffset = startOffset + length;
    319         MarkerList::iterator startPos = std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
    320         for (MarkerList::iterator i = startPos; i != list->end(); ) {
    321             DocumentMarker marker(*i->get());
    322 
    323             // markers are returned in order, so stop if we are now past the specified range
    324             if (marker.startOffset() >= endOffset)
    325                 break;
    326 
    327             // at this point we know that marker and target intersect in some way
    328             docDirty = true;
    329 
    330             // pitch the old marker
    331             list->remove(i - list->begin());
    332 
    333             if (shouldRemovePartiallyOverlappingMarker) {
    334                 // Stop here. Don't add resulting slices back.
    335                 continue;
    336             }
    337 
    338             // add either of the resulting slices that are left after removing target
    339             if (startOffset > marker.startOffset()) {
    340                 DocumentMarker newLeft = marker;
    341                 newLeft.setEndOffset(startOffset);
    342                 size_t insertIndex = i - list->begin();
    343                 list->insert(insertIndex, RenderedDocumentMarker::create(newLeft));
    344                 // Move to the marker after the inserted one.
    345                 i = list->begin() + insertIndex + 1;
    346             }
    347             if (marker.endOffset() > endOffset) {
    348                 DocumentMarker newRight = marker;
    349                 newRight.setStartOffset(endOffset);
    350                 size_t insertIndex = i - list->begin();
    351                 list->insert(insertIndex, RenderedDocumentMarker::create(newRight));
    352                 // Move to the marker after the inserted one.
    353                 i = list->begin() + insertIndex + 1;
    354             }
    355         }
    356 
    357         if (list->isEmpty()) {
    358             list.clear();
    359             ++emptyListsCount;
    360         }
    361     }
    362 
    363     if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) {
    364         m_markers.remove(node);
    365         if (m_markers.isEmpty())
    366             m_possiblyExistingMarkerTypes = 0;
    367     }
    368 
    369     // repaint the affected node
    370     if (docDirty && node->renderer())
    371         node->renderer()->setShouldDoFullPaintInvalidation(true);
    372 }
    373 
    374 DocumentMarker* DocumentMarkerController::markerContainingPoint(const LayoutPoint& point, DocumentMarker::MarkerType markerType)
    375 {
    376     if (!possiblyHasMarkers(markerType))
    377         return 0;
    378     ASSERT(!(m_markers.isEmpty()));
    379 
    380     // outer loop: process each node that contains any markers
    381     MarkerMap::iterator end = m_markers.end();
    382     for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
    383         // inner loop; process each marker in this node
    384         MarkerLists* markers = nodeIterator->value.get();
    385         OwnPtrWillBeMember<MarkerList>& list = (*markers)[MarkerTypeToMarkerIndex(markerType)];
    386         unsigned markerCount = list.get() ? list->size() : 0;
    387         for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
    388             RenderedDocumentMarker* marker = list->at(markerIndex).get();
    389             if (marker->contains(point))
    390                 return marker;
    391         }
    392     }
    393 
    394     return 0;
    395 }
    396 
    397 DocumentMarkerVector DocumentMarkerController::markersFor(Node* node, DocumentMarker::MarkerTypes markerTypes)
    398 {
    399     DocumentMarkerVector result;
    400 
    401     MarkerLists* markers = m_markers.get(node);
    402     if (!markers)
    403         return result;
    404 
    405     for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    406         OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    407         if (!list || list->isEmpty() || !markerTypes.contains((*list->begin())->type()))
    408             continue;
    409 
    410         for (size_t i = 0; i < list->size(); ++i)
    411             result.append(list->at(i).get());
    412     }
    413 
    414     std::sort(result.begin(), result.end(), compareByStart);
    415     return result;
    416 }
    417 
    418 DocumentMarkerVector DocumentMarkerController::markers()
    419 {
    420     DocumentMarkerVector result;
    421     for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) {
    422         MarkerLists* markers = i->value.get();
    423         for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    424             OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    425             for (size_t j = 0; list.get() && j < list->size(); ++j)
    426                 result.append(list->at(j).get());
    427         }
    428     }
    429     std::sort(result.begin(), result.end(), compareByStart);
    430     return result;
    431 }
    432 
    433 DocumentMarkerVector DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerTypes markerTypes)
    434 {
    435     if (!possiblyHasMarkers(markerTypes))
    436         return DocumentMarkerVector();
    437 
    438     DocumentMarkerVector foundMarkers;
    439 
    440     Node* startContainer = range->startContainer();
    441     ASSERT(startContainer);
    442     Node* endContainer = range->endContainer();
    443     ASSERT(endContainer);
    444 
    445     Node* pastLastNode = range->pastLastNode();
    446     for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) {
    447         DocumentMarkerVector markers = markersFor(node);
    448         DocumentMarkerVector::const_iterator end = markers.end();
    449         for (DocumentMarkerVector::const_iterator it = markers.begin(); it != end; ++it) {
    450             DocumentMarker* marker = *it;
    451             if (!markerTypes.contains(marker->type()))
    452                 continue;
    453             if (node == startContainer && marker->endOffset() <= static_cast<unsigned>(range->startOffset()))
    454                 continue;
    455             if (node == endContainer && marker->startOffset() >= static_cast<unsigned>(range->endOffset()))
    456                 continue;
    457             foundMarkers.append(marker);
    458         }
    459     }
    460     return foundMarkers;
    461 }
    462 
    463 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
    464 {
    465     Vector<IntRect> result;
    466 
    467     if (!possiblyHasMarkers(markerType))
    468         return result;
    469     ASSERT(!(m_markers.isEmpty()));
    470 
    471     // outer loop: process each node
    472     MarkerMap::iterator end = m_markers.end();
    473     for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
    474         // inner loop; process each marker in this node
    475         MarkerLists* markers = nodeIterator->value.get();
    476         for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    477             OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    478             if (!list || list->isEmpty() || (*list->begin())->type() != markerType)
    479                 continue;
    480             for (unsigned markerIndex = 0; markerIndex < list->size(); ++markerIndex) {
    481                 RenderedDocumentMarker* marker = list->at(markerIndex).get();
    482                 if (!marker->isRendered())
    483                     continue;
    484                 result.append(marker->renderedRect());
    485             }
    486         }
    487     }
    488 
    489     return result;
    490 }
    491 
    492 void DocumentMarkerController::trace(Visitor* visitor)
    493 {
    494 #if ENABLE(OILPAN)
    495     visitor->trace(m_markers);
    496 #endif
    497 }
    498 
    499 void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerTypes markerTypes)
    500 {
    501     if (!possiblyHasMarkers(markerTypes))
    502         return;
    503     ASSERT(!m_markers.isEmpty());
    504 
    505     MarkerMap::iterator iterator = m_markers.find(node);
    506     if (iterator != m_markers.end())
    507         removeMarkersFromList(iterator, markerTypes);
    508 }
    509 
    510 void DocumentMarkerController::removeMarkers(const MarkerRemoverPredicate& shouldRemoveMarker)
    511 {
    512     for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) {
    513         MarkerLists* markers = i->value.get();
    514         for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    515             OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    516 
    517             WillBeHeapVector<RawPtrWillBeMember<RenderedDocumentMarker> > markersToBeRemoved;
    518             for (size_t j = 0; list.get() && j < list->size(); ++j) {
    519                 if (i->key->isTextNode() && shouldRemoveMarker(*list->at(j).get(), static_cast<const Text&>(*i->key)))
    520                     markersToBeRemoved.append(list->at(j).get());
    521             }
    522 
    523             for (size_t j = 0; j < markersToBeRemoved.size(); ++j)
    524                 list->remove(list->find(markersToBeRemoved[j].get()));
    525         }
    526     }
    527 }
    528 
    529 void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerTypes)
    530 {
    531     if (!possiblyHasMarkers(markerTypes))
    532         return;
    533     ASSERT(!m_markers.isEmpty());
    534 
    535     Vector<const Node*> nodesWithMarkers;
    536     copyKeysToVector(m_markers, nodesWithMarkers);
    537     unsigned size = nodesWithMarkers.size();
    538     for (unsigned i = 0; i < size; ++i) {
    539         MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]);
    540         if (iterator != m_markers.end())
    541             removeMarkersFromList(iterator, markerTypes);
    542     }
    543 
    544     m_possiblyExistingMarkerTypes.remove(markerTypes);
    545 }
    546 
    547 void DocumentMarkerController::removeMarkersFromList(MarkerMap::iterator iterator, DocumentMarker::MarkerTypes markerTypes)
    548 {
    549     bool needsRepainting = false;
    550     bool nodeCanBeRemoved;
    551 
    552     size_t emptyListsCount = 0;
    553     if (markerTypes == DocumentMarker::AllMarkers()) {
    554         needsRepainting = true;
    555         nodeCanBeRemoved = true;
    556     } else {
    557         MarkerLists* markers = iterator->value.get();
    558 
    559         for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    560             OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    561             if (!list || list->isEmpty()) {
    562                 if (list.get() && list->isEmpty())
    563                     list.clear();
    564                 ++emptyListsCount;
    565                 continue;
    566             }
    567             if (markerTypes.contains((*list->begin())->type())) {
    568                 list->clear();
    569                 list.clear();
    570                 ++emptyListsCount;
    571                 needsRepainting = true;
    572             }
    573         }
    574 
    575         nodeCanBeRemoved = emptyListsCount == DocumentMarker::MarkerTypeIndexesCount;
    576     }
    577 
    578     if (needsRepainting) {
    579         if (RenderObject* renderer = iterator->key->renderer())
    580             renderer->setShouldDoFullPaintInvalidation(true);
    581     }
    582 
    583     if (nodeCanBeRemoved) {
    584         m_markers.remove(iterator);
    585         if (m_markers.isEmpty())
    586             m_possiblyExistingMarkerTypes = 0;
    587     }
    588 }
    589 
    590 void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes markerTypes)
    591 {
    592     if (!possiblyHasMarkers(markerTypes))
    593         return;
    594     ASSERT(!m_markers.isEmpty());
    595 
    596     // outer loop: process each markered node in the document
    597     MarkerMap::iterator end = m_markers.end();
    598     for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
    599         const Node* node = i->key;
    600 
    601         // inner loop: process each marker in the current node
    602         MarkerLists* markers = i->value.get();
    603         for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    604             OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    605             if (!list || list->isEmpty() || !markerTypes.contains((*list->begin())->type()))
    606                 continue;
    607 
    608             // cause the node to be redrawn
    609             if (RenderObject* renderer = node->renderer()) {
    610                 renderer->setShouldDoFullPaintInvalidation(true);
    611                 break;
    612             }
    613         }
    614     }
    615 }
    616 
    617 void DocumentMarkerController::invalidateRenderedRectsForMarkersInRect(const LayoutRect& r)
    618 {
    619     // outer loop: process each markered node in the document
    620     MarkerMap::iterator end = m_markers.end();
    621     for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
    622 
    623         // inner loop: process each rect in the current node
    624         MarkerLists* markers = i->value.get();
    625         for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    626             OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    627             for (size_t markerIndex = 0; list.get() && markerIndex < list->size(); ++markerIndex)
    628                 list->at(markerIndex)->invalidate(r);
    629         }
    630     }
    631 }
    632 
    633 void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta)
    634 {
    635     if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
    636         return;
    637     ASSERT(!m_markers.isEmpty());
    638 
    639     MarkerLists* markers = m_markers.get(node);
    640     if (!markers)
    641         return;
    642 
    643     bool docDirty = false;
    644     for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    645         OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    646         if (!list)
    647             continue;
    648         MarkerList::iterator startPos = std::lower_bound(list->begin(), list->end(), startOffset, startsAfter);
    649         for (MarkerList::iterator marker = startPos; marker != list->end(); ++marker) {
    650 #if ENABLE(ASSERT)
    651             int startOffset = (*marker)->startOffset();
    652             ASSERT(startOffset + delta >= 0);
    653 #endif
    654             (*marker)->shiftOffsets(delta);
    655             docDirty = true;
    656 
    657             // Marker moved, so previously-computed rendered rectangle is now invalid
    658             (*marker)->invalidate();
    659         }
    660     }
    661 
    662     // repaint the affected node
    663     if (docDirty && node->renderer())
    664         node->renderer()->setShouldDoFullPaintInvalidation(true);
    665 }
    666 
    667 void DocumentMarkerController::setMarkersActive(Range* range, bool active)
    668 {
    669     if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
    670         return;
    671     ASSERT(!m_markers.isEmpty());
    672 
    673     Node* startContainer = range->startContainer();
    674     Node* endContainer = range->endContainer();
    675 
    676     Node* pastLastNode = range->pastLastNode();
    677 
    678     for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) {
    679         int startOffset = node == startContainer ? range->startOffset() : 0;
    680         int endOffset = node == endContainer ? range->endOffset() : INT_MAX;
    681         setMarkersActive(node, startOffset, endOffset, active);
    682     }
    683 }
    684 
    685 void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active)
    686 {
    687     MarkerLists* markers = m_markers.get(node);
    688     if (!markers)
    689         return;
    690 
    691     bool docDirty = false;
    692     OwnPtrWillBeMember<MarkerList>& list = (*markers)[MarkerTypeToMarkerIndex(DocumentMarker::TextMatch)];
    693     if (!list)
    694         return;
    695     MarkerList::iterator startPos = std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
    696     for (MarkerList::iterator marker = startPos; marker != list->end(); ++marker) {
    697 
    698         // Markers are returned in order, so stop if we are now past the specified range.
    699         if ((*marker)->startOffset() >= endOffset)
    700             break;
    701 
    702         (*marker)->setActiveMatch(active);
    703         docDirty = true;
    704     }
    705 
    706     // repaint the affected node
    707     if (docDirty && node->renderer())
    708         node->renderer()->setShouldDoFullPaintInvalidation(true);
    709 }
    710 
    711 bool DocumentMarkerController::hasMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes)
    712 {
    713     if (!possiblyHasMarkers(markerTypes))
    714         return false;
    715     ASSERT(!m_markers.isEmpty());
    716 
    717     Node* startContainer = range->startContainer();
    718     ASSERT(startContainer);
    719     Node* endContainer = range->endContainer();
    720     ASSERT(endContainer);
    721 
    722     Node* pastLastNode = range->pastLastNode();
    723     for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) {
    724         DocumentMarkerVector markers = markersFor(node);
    725         DocumentMarkerVector::const_iterator end = markers.end();
    726         for (DocumentMarkerVector::const_iterator it = markers.begin(); it != end; ++it) {
    727             DocumentMarker* marker = *it;
    728             if (!markerTypes.contains(marker->type()))
    729                 continue;
    730             if (node == startContainer && marker->endOffset() <= static_cast<unsigned>(range->startOffset()))
    731                 continue;
    732             if (node == endContainer && marker->startOffset() >= static_cast<unsigned>(range->endOffset()))
    733                 continue;
    734             return true;
    735         }
    736     }
    737     return false;
    738 }
    739 
    740 #ifndef NDEBUG
    741 void DocumentMarkerController::showMarkers() const
    742 {
    743     fprintf(stderr, "%d nodes have markers:\n", m_markers.size());
    744     MarkerMap::const_iterator end = m_markers.end();
    745     for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
    746         const Node* node = nodeIterator->key;
    747         fprintf(stderr, "%p", node);
    748         MarkerLists* markers = m_markers.get(node);
    749         for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
    750             OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
    751             for (unsigned markerIndex = 0; list.get() && markerIndex < list->size(); ++markerIndex) {
    752                 DocumentMarker* marker = list->at(markerIndex).get();
    753                 fprintf(stderr, " %d:[%d:%d](%d)", marker->type(), marker->startOffset(), marker->endOffset(), marker->activeMatch());
    754             }
    755         }
    756 
    757         fprintf(stderr, "\n");
    758     }
    759 }
    760 #endif
    761 
    762 } // namespace blink
    763 
    764 #ifndef NDEBUG
    765 void showDocumentMarkers(const blink::DocumentMarkerController* controller)
    766 {
    767     if (controller)
    768         controller->showMarkers();
    769 }
    770 #endif
    771