Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: Source/core/dom/DocumentMarkerController.cpp

Issue 1293683003: Move DocumentMarker related files to editing/markers/ from dom/ (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: 2015-08-14T22:49:39 Rebase Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.t orchmobile.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/iterators/TextIterator.h"
36 #include "core/frame/FrameView.h"
37 #include "core/layout/LayoutObject.h"
38
39 #ifndef NDEBUG
40 #include <stdio.h>
41 #endif
42
43 namespace blink {
44
45 MarkerRemoverPredicate::MarkerRemoverPredicate(const Vector<String>& words)
46 : m_words(words)
47 {
48 }
49
50 bool MarkerRemoverPredicate::operator()(const DocumentMarker& documentMarker, co nst Text& textNode) const
51 {
52 unsigned start = documentMarker.startOffset();
53 unsigned length = documentMarker.endOffset() - documentMarker.startOffset();
54
55 String markerText = textNode.data().substring(start, length);
56 return m_words.contains(markerText);
57 }
58
59 namespace {
60
61 DocumentMarker::MarkerTypeIndex MarkerTypeToMarkerIndex(DocumentMarker::MarkerTy pe type)
62 {
63 switch (type) {
64 case DocumentMarker::Spelling:
65 return DocumentMarker::SpellingMarkerIndex;
66 case DocumentMarker::Grammar:
67 return DocumentMarker::GramarMarkerIndex;
68 case DocumentMarker::TextMatch:
69 return DocumentMarker::TextMatchMarkerIndex;
70 case DocumentMarker::InvisibleSpellcheck:
71 return DocumentMarker::InvisibleSpellcheckMarkerIndex;
72 }
73
74 ASSERT_NOT_REACHED();
75 return DocumentMarker::SpellingMarkerIndex;
76 }
77
78 } // namespace
79
80 inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerT ypes types)
81 {
82 return m_possiblyExistingMarkerTypes.intersects(types);
83 }
84
85 DocumentMarkerController::DocumentMarkerController()
86 : m_possiblyExistingMarkerTypes(0)
87 {
88 }
89
90 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(DocumentMarkerController);
91
92 void DocumentMarkerController::clear()
93 {
94 m_markers.clear();
95 m_possiblyExistingMarkerTypes = 0;
96 }
97
98 void DocumentMarkerController::addMarker(const Position& start, const Position& end, DocumentMarker::MarkerType type, const String& description, uint32_t hash)
99 {
100 // Use a TextIterator to visit the potentially multiple nodes the range cove rs.
101 for (TextIterator markedText(start, end); !markedText.atEnd(); markedText.ad vance()) {
102 addMarker(markedText.currentContainer(), DocumentMarker(type, markedText .startOffsetInCurrentContainer(), markedText.endOffsetInCurrentContainer(), desc ription, hash));
103 }
104 }
105
106 void DocumentMarkerController::addTextMatchMarker(const Range* range, bool activ eMatch)
107 {
108 // Use a TextIterator to visit the potentially multiple nodes the range cove rs.
109 for (TextIterator markedText(range->startPosition(), range->endPosition()); !markedText.atEnd(); markedText.advance())
110 addMarker(markedText.currentContainer(), DocumentMarker(markedText.start OffsetInCurrentContainer(), markedText.endOffsetInCurrentContainer(), activeMatc h));
111 // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a throttling algorithm. crbug.com/6819.
112 }
113
114 void DocumentMarkerController::prepareForDestruction()
115 {
116 clear();
117 }
118
119 void DocumentMarkerController::removeMarkers(TextIterator& markedText, DocumentM arker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemo vePartiallyOverlappingMarker)
120 {
121 for (; !markedText.atEnd(); markedText.advance()) {
122 if (!possiblyHasMarkers(markerTypes))
123 return;
124 ASSERT(!m_markers.isEmpty());
125
126 int startOffset = markedText.startOffsetInCurrentContainer();
127 int endOffset = markedText.endOffsetInCurrentContainer();
128 removeMarkers(markedText.currentContainer(), startOffset, endOffset - st artOffset, markerTypes, shouldRemovePartiallyOverlappingMarker);
129 }
130 }
131
132 void DocumentMarkerController::removeMarkers(const EphemeralRange& range, Docume ntMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldR emovePartiallyOverlappingMarker)
133 {
134 TextIterator markedText(range.startPosition(), range.endPosition());
135 DocumentMarkerController::removeMarkers(markedText, markerTypes, shouldRemov ePartiallyOverlappingMarker);
136 }
137
138 static bool startsFurther(const OwnPtrWillBeMember<RenderedDocumentMarker>& lhv, const DocumentMarker* rhv)
139 {
140 return lhv->startOffset() < rhv->startOffset();
141 }
142
143 static bool startsAfter(const OwnPtrWillBeMember<RenderedDocumentMarker>& marker , size_t startOffset)
144 {
145 return marker->startOffset() < startOffset;
146 }
147
148 static bool endsBefore(size_t startOffset, const OwnPtrWillBeMember<RenderedDocu mentMarker>& rhv)
149 {
150 return startOffset < rhv->endOffset();
151 }
152
153 static bool compareByStart(const RawPtrWillBeMember<DocumentMarker>& lhv, const RawPtrWillBeMember<DocumentMarker>& rhv)
154 {
155 return lhv->startOffset() < rhv->startOffset();
156 }
157
158 static bool doesNotOverlap(const OwnPtrWillBeMember<RenderedDocumentMarker>& lhv , const DocumentMarker* rhv)
159 {
160 return lhv->endOffset() < rhv->startOffset();
161 }
162
163 static bool doesNotInclude(const OwnPtrWillBeMember<RenderedDocumentMarker>& mar ker, size_t startOffset)
164 {
165 return marker->endOffset() < startOffset;
166 }
167
168 static bool updateMarkerRenderedRect(Node* node, RenderedDocumentMarker& marker)
169 {
170 RefPtrWillBeRawPtr<Range> range = Range::create(node->document());
171 // The offsets of the marker may be out-dated, so check for exceptions.
172 TrackExceptionState exceptionState;
173 range->setStart(node, marker.startOffset(), exceptionState);
174 if (!exceptionState.hadException())
175 range->setEnd(node, marker.endOffset(), IGNORE_EXCEPTION);
176 if (exceptionState.hadException())
177 return marker.invalidateRenderedRect();
178 return marker.setRenderedRect(LayoutRect(range->boundingBox()));
179 }
180
181 // Markers are stored in order sorted by their start offset.
182 // Markers of the same type do not overlap each other.
183
184 void DocumentMarkerController::addMarker(Node* node, const DocumentMarker& newMa rker)
185 {
186 ASSERT(newMarker.endOffset() >= newMarker.startOffset());
187 if (newMarker.endOffset() == newMarker.startOffset())
188 return;
189
190 m_possiblyExistingMarkerTypes.add(newMarker.type());
191
192 OwnPtrWillBeMember<MarkerLists>& markers = m_markers.add(node, nullptr).stor edValue->value;
193 if (!markers) {
194 markers = adoptPtrWillBeNoop(new MarkerLists);
195 markers->grow(DocumentMarker::MarkerTypeIndexesCount);
196 }
197
198 DocumentMarker::MarkerTypeIndex markerListIndex = MarkerTypeToMarkerIndex(ne wMarker.type());
199 if (!markers->at(markerListIndex)) {
200 markers->insert(markerListIndex, adoptPtrWillBeNoop(new MarkerList));
201 }
202
203 OwnPtrWillBeMember<MarkerList>& list = markers->at(markerListIndex);
204 OwnPtrWillBeRawPtr<RenderedDocumentMarker> newRenderedMarker = RenderedDocum entMarker::create(newMarker);
205 updateMarkerRenderedRect(node, *newRenderedMarker);
206 if (list->isEmpty() || list->last()->endOffset() < newMarker.startOffset()) {
207 list->append(newRenderedMarker.release());
208 } else {
209 if (newMarker.type() != DocumentMarker::TextMatch) {
210 mergeOverlapping(list.get(), newRenderedMarker.release());
211 } else {
212 MarkerList::iterator pos = std::lower_bound(list->begin(), list->end (), &newMarker, startsFurther);
213 list->insert(pos - list->begin(), newRenderedMarker.release());
214 }
215 }
216
217 // repaint the affected node
218 if (node->layoutObject())
219 node->layoutObject()->setShouldDoFullPaintInvalidation();
220 }
221
222 void DocumentMarkerController::mergeOverlapping(MarkerList* list, PassOwnPtrWill BeRawPtr<RenderedDocumentMarker> toInsert)
223 {
224 MarkerList::iterator firstOverlapping = std::lower_bound(list->begin(), list ->end(), toInsert.get(), doesNotOverlap);
225 size_t index = firstOverlapping - list->begin();
226 list->insert(index, toInsert);
227 MarkerList::iterator inserted = list->begin() + index;
228 firstOverlapping = inserted + 1;
229 for (MarkerList::iterator i = firstOverlapping; i != list->end() && (*i)->st artOffset() <= (*inserted)->endOffset(); ) {
230 (*inserted)->setStartOffset(std::min((*inserted)->startOffset(), (*i)->s tartOffset()));
231 (*inserted)->setEndOffset(std::max((*inserted)->endOffset(), (*i)->endOf fset()));
232 list->remove(i - list->begin());
233 }
234 }
235
236 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
237 // useful if, e.g., the caller has created the dstNode from a non-prefix substri ng of the srcNode.
238 void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta)
239 {
240 if (length <= 0)
241 return;
242
243 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
244 return;
245 ASSERT(!m_markers.isEmpty());
246
247 MarkerLists* markers = m_markers.get(srcNode);
248 if (!markers)
249 return;
250
251 bool docDirty = false;
252 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTyp eIndexesCount; ++markerListIndex) {
253 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
254 if (!list)
255 continue;
256
257 unsigned endOffset = startOffset + length - 1;
258 MarkerList::iterator startPos = std::lower_bound(list->begin(), list->en d(), startOffset, doesNotInclude);
259 for (MarkerList::iterator i = startPos; i != list->end(); ++i) {
260 DocumentMarker* marker = i->get();
261
262 // stop if we are now past the specified range
263 if (marker->startOffset() > endOffset)
264 break;
265
266 // pin the marker to the specified range and apply the shift delta
267 docDirty = true;
268 if (marker->startOffset() < startOffset)
269 marker->setStartOffset(startOffset);
270 if (marker->endOffset() > endOffset)
271 marker->setEndOffset(endOffset);
272 marker->shiftOffsets(delta);
273
274 addMarker(dstNode, *marker);
275 }
276 }
277
278 // repaint the affected node
279 if (docDirty && dstNode->layoutObject())
280 dstNode->layoutObject()->setShouldDoFullPaintInvalidation();
281 }
282
283 void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, i nt length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMa rkerOrNot shouldRemovePartiallyOverlappingMarker)
284 {
285 if (length <= 0)
286 return;
287
288 if (!possiblyHasMarkers(markerTypes))
289 return;
290 ASSERT(!(m_markers.isEmpty()));
291
292 MarkerLists* markers = m_markers.get(node);
293 if (!markers)
294 return;
295
296 bool docDirty = false;
297 size_t emptyListsCount = 0;
298 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTyp eIndexesCount; ++markerListIndex) {
299 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
300 if (!list || list->isEmpty()) {
301 if (list.get() && list->isEmpty())
302 list.clear();
303 ++emptyListsCount;
304 continue;
305 }
306 if (!markerTypes.contains((*list->begin())->type()))
307 continue;
308 unsigned endOffset = startOffset + length;
309 MarkerList::iterator startPos = std::upper_bound(list->begin(), list->en d(), startOffset, endsBefore);
310 for (MarkerList::iterator i = startPos; i != list->end(); ) {
311 DocumentMarker marker(*i->get());
312
313 // markers are returned in order, so stop if we are now past the spe cified range
314 if (marker.startOffset() >= endOffset)
315 break;
316
317 // at this point we know that marker and target intersect in some wa y
318 docDirty = true;
319
320 // pitch the old marker
321 list->remove(i - list->begin());
322
323 if (shouldRemovePartiallyOverlappingMarker) {
324 // Stop here. Don't add resulting slices back.
325 continue;
326 }
327
328 // add either of the resulting slices that are left after removing t arget
329 if (startOffset > marker.startOffset()) {
330 DocumentMarker newLeft = marker;
331 newLeft.setEndOffset(startOffset);
332 size_t insertIndex = i - list->begin();
333 list->insert(insertIndex, RenderedDocumentMarker::create(newLeft ));
334 // Move to the marker after the inserted one.
335 i = list->begin() + insertIndex + 1;
336 }
337 if (marker.endOffset() > endOffset) {
338 DocumentMarker newRight = marker;
339 newRight.setStartOffset(endOffset);
340 size_t insertIndex = i - list->begin();
341 list->insert(insertIndex, RenderedDocumentMarker::create(newRigh t));
342 // Move to the marker after the inserted one.
343 i = list->begin() + insertIndex + 1;
344 }
345 }
346
347 if (list->isEmpty()) {
348 list.clear();
349 ++emptyListsCount;
350 }
351 }
352
353 if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) {
354 m_markers.remove(node);
355 if (m_markers.isEmpty())
356 m_possiblyExistingMarkerTypes = 0;
357 }
358
359 // repaint the affected node
360 if (docDirty && node->layoutObject())
361 node->layoutObject()->setShouldDoFullPaintInvalidation();
362 }
363
364 DocumentMarker* DocumentMarkerController::markerContainingPoint(const LayoutPoin t& point, DocumentMarker::MarkerType markerType)
365 {
366 if (!possiblyHasMarkers(markerType))
367 return 0;
368 ASSERT(!(m_markers.isEmpty()));
369
370 // outer loop: process each node that contains any markers
371 MarkerMap::iterator end = m_markers.end();
372 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != e nd; ++nodeIterator) {
373 // inner loop; process each marker in this node
374 MarkerLists* markers = nodeIterator->value.get();
375 OwnPtrWillBeMember<MarkerList>& list = (*markers)[MarkerTypeToMarkerInde x(markerType)];
376 unsigned markerCount = list.get() ? list->size() : 0;
377 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
378 RenderedDocumentMarker* marker = list->at(markerIndex).get();
379 if (marker->contains(point))
380 return marker;
381 }
382 }
383
384 return 0;
385 }
386
387 DocumentMarkerVector DocumentMarkerController::markersFor(Node* node, DocumentMa rker::MarkerTypes markerTypes)
388 {
389 DocumentMarkerVector result;
390
391 MarkerLists* markers = m_markers.get(node);
392 if (!markers)
393 return result;
394
395 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTyp eIndexesCount; ++markerListIndex) {
396 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
397 if (!list || list->isEmpty() || !markerTypes.contains((*list->begin())-> type()))
398 continue;
399
400 for (size_t i = 0; i < list->size(); ++i)
401 result.append(list->at(i).get());
402 }
403
404 std::sort(result.begin(), result.end(), compareByStart);
405 return result;
406 }
407
408 DocumentMarkerVector DocumentMarkerController::markers()
409 {
410 DocumentMarkerVector result;
411 for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) {
412 MarkerLists* markers = i->value.get();
413 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::Marke rTypeIndexesCount; ++markerListIndex) {
414 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
415 for (size_t j = 0; list.get() && j < list->size(); ++j)
416 result.append(list->at(j).get());
417 }
418 }
419 std::sort(result.begin(), result.end(), compareByStart);
420 return result;
421 }
422
423 DocumentMarkerVector DocumentMarkerController::markersInRange(const EphemeralRan ge& range, DocumentMarker::MarkerTypes markerTypes)
424 {
425 if (!possiblyHasMarkers(markerTypes))
426 return DocumentMarkerVector();
427
428 DocumentMarkerVector foundMarkers;
429
430 Node* startContainer = range.startPosition().computeContainerNode();
431 ASSERT(startContainer);
432 unsigned startOffset = static_cast<unsigned>(range.startPosition().computeOf fsetInContainerNode());
433 Node* endContainer = range.endPosition().computeContainerNode();
434 ASSERT(endContainer);
435 unsigned endOffset = static_cast<unsigned>(range.endPosition().computeOffset InContainerNode());
436
437 Node* pastLastNode = range.endPosition().nodeAsRangePastLastNode();
438 for (Node* node = range.startPosition().nodeAsRangeFirstNode(); node != past LastNode; node = NodeTraversal::next(*node)) {
439 for (DocumentMarker* marker : markersFor(node)) {
440 if (!markerTypes.contains(marker->type()))
441 continue;
442 if (node == startContainer && marker->endOffset() <= startOffset)
443 continue;
444 if (node == endContainer && marker->startOffset() >= endOffset)
445 continue;
446 foundMarkers.append(marker);
447 }
448 }
449 return foundMarkers;
450 }
451
452 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker ::MarkerType markerType)
453 {
454 Vector<IntRect> result;
455
456 if (!possiblyHasMarkers(markerType))
457 return result;
458 ASSERT(!(m_markers.isEmpty()));
459
460 // outer loop: process each node
461 MarkerMap::iterator end = m_markers.end();
462 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != e nd; ++nodeIterator) {
463 // inner loop; process each marker in this node
464 MarkerLists* markers = nodeIterator->value.get();
465 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::Marke rTypeIndexesCount; ++markerListIndex) {
466 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
467 if (!list || list->isEmpty() || (*list->begin())->type() != markerTy pe)
468 continue;
469 for (unsigned markerIndex = 0; markerIndex < list->size(); ++markerI ndex) {
470 RenderedDocumentMarker* marker = list->at(markerIndex).get();
471 if (!marker->isRendered())
472 continue;
473 result.append(marker->renderedRect());
474 }
475 }
476 }
477
478 return result;
479 }
480
481 static void invalidatePaintForTickmarks(const Node& node)
482 {
483 if (FrameView* frameView = node.document().view())
484 frameView->invalidatePaintForTickmarks();
485 }
486
487 void DocumentMarkerController::updateRenderedRectsForMarkers()
488 {
489 for (auto& nodeMarkers : m_markers) {
490 const Node* node = nodeMarkers.key;
491 for (auto& markerList : *nodeMarkers.value) {
492 if (!markerList)
493 continue;
494 bool markersChanged = false;
495 for (auto& marker : *markerList)
496 markersChanged |= updateMarkerRenderedRect(const_cast<Node*>(nod e), *marker);
497
498 if (markersChanged && markerList->first()->type() == DocumentMarker: :TextMatch)
499 invalidatePaintForTickmarks(*node);
500 }
501 }
502 }
503
504 DEFINE_TRACE(DocumentMarkerController)
505 {
506 #if ENABLE(OILPAN)
507 visitor->trace(m_markers);
508 #endif
509 }
510
511 void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerT ypes markerTypes)
512 {
513 if (!possiblyHasMarkers(markerTypes))
514 return;
515 ASSERT(!m_markers.isEmpty());
516
517 MarkerMap::iterator iterator = m_markers.find(node);
518 if (iterator != m_markers.end())
519 removeMarkersFromList(iterator, markerTypes);
520 }
521
522 void DocumentMarkerController::removeMarkers(const MarkerRemoverPredicate& shoul dRemoveMarker)
523 {
524 for (auto& nodeMarkers : m_markers) {
525 const Node& node = *nodeMarkers.key;
526 if (!node.isTextNode()) // MarkerRemoverPredicate requires a Text node.
527 continue;
528 MarkerLists& markers = *nodeMarkers.value;
529 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::Marke rTypeIndexesCount; ++markerListIndex) {
530 OwnPtrWillBeMember<MarkerList>& list = markers[markerListIndex];
531 if (!list)
532 continue;
533 bool removedMarkers = false;
534 for (size_t j = list->size(); j > 0; --j) {
535 if (shouldRemoveMarker(*list->at(j - 1), static_cast<const Text& >(node))) {
536 list->remove(j - 1);
537 removedMarkers = true;
538 }
539 }
540 if (removedMarkers && markerListIndex == DocumentMarker::TextMatchMa rkerIndex)
541 invalidatePaintForTickmarks(node);
542 }
543 }
544 }
545
546 void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerT ypes)
547 {
548 if (!possiblyHasMarkers(markerTypes))
549 return;
550 ASSERT(!m_markers.isEmpty());
551
552 Vector<const Node*> nodesWithMarkers;
553 copyKeysToVector(m_markers, nodesWithMarkers);
554 unsigned size = nodesWithMarkers.size();
555 for (unsigned i = 0; i < size; ++i) {
556 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]);
557 if (iterator != m_markers.end())
558 removeMarkersFromList(iterator, markerTypes);
559 }
560
561 m_possiblyExistingMarkerTypes.remove(markerTypes);
562 }
563
564 void DocumentMarkerController::removeMarkersFromList(MarkerMap::iterator iterato r, DocumentMarker::MarkerTypes markerTypes)
565 {
566 bool needsRepainting = false;
567 bool nodeCanBeRemoved;
568
569 size_t emptyListsCount = 0;
570 if (markerTypes == DocumentMarker::AllMarkers()) {
571 needsRepainting = true;
572 nodeCanBeRemoved = true;
573 } else {
574 MarkerLists* markers = iterator->value.get();
575
576 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::Marke rTypeIndexesCount; ++markerListIndex) {
577 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
578 if (!list || list->isEmpty()) {
579 if (list.get() && list->isEmpty())
580 list.clear();
581 ++emptyListsCount;
582 continue;
583 }
584 if (markerTypes.contains((*list->begin())->type())) {
585 list->clear();
586 list.clear();
587 ++emptyListsCount;
588 needsRepainting = true;
589 }
590 }
591
592 nodeCanBeRemoved = emptyListsCount == DocumentMarker::MarkerTypeIndexesC ount;
593 }
594
595 if (needsRepainting) {
596 const Node& node = *iterator->key;
597 if (LayoutObject* layoutObject = node.layoutObject())
598 layoutObject->setShouldDoFullPaintInvalidation();
599 invalidatePaintForTickmarks(node);
600 }
601
602 if (nodeCanBeRemoved) {
603 m_markers.remove(iterator);
604 if (m_markers.isEmpty())
605 m_possiblyExistingMarkerTypes = 0;
606 }
607 }
608
609 void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes marker Types)
610 {
611 if (!possiblyHasMarkers(markerTypes))
612 return;
613 ASSERT(!m_markers.isEmpty());
614
615 // outer loop: process each markered node in the document
616 MarkerMap::iterator end = m_markers.end();
617 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
618 const Node* node = i->key;
619
620 // inner loop: process each marker in the current node
621 MarkerLists* markers = i->value.get();
622 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::Marke rTypeIndexesCount; ++markerListIndex) {
623 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
624 if (!list || list->isEmpty() || !markerTypes.contains((*list->begin( ))->type()))
625 continue;
626
627 // cause the node to be redrawn
628 if (LayoutObject* layoutObject = node->layoutObject()) {
629 layoutObject->setShouldDoFullPaintInvalidation();
630 break;
631 }
632 }
633 }
634 }
635
636 void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, in t delta)
637 {
638 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
639 return;
640 ASSERT(!m_markers.isEmpty());
641
642 MarkerLists* markers = m_markers.get(node);
643 if (!markers)
644 return;
645
646 bool docDirty = false;
647 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTyp eIndexesCount; ++markerListIndex) {
648 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
649 if (!list)
650 continue;
651 MarkerList::iterator startPos = std::lower_bound(list->begin(), list->en d(), startOffset, startsAfter);
652 for (MarkerList::iterator marker = startPos; marker != list->end(); ++ma rker) {
653 #if ENABLE(ASSERT)
654 int startOffset = (*marker)->startOffset();
655 ASSERT(startOffset + delta >= 0);
656 #endif
657 (*marker)->shiftOffsets(delta);
658 docDirty = true;
659
660 updateMarkerRenderedRect(node, **marker);
661 }
662 }
663
664 // repaint the affected node
665 if (docDirty && node->layoutObject())
666 node->layoutObject()->setShouldDoFullPaintInvalidation();
667 }
668
669 void DocumentMarkerController::setMarkersActive(Range* range, bool active)
670 {
671 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
672 return;
673 ASSERT(!m_markers.isEmpty());
674
675 Node* startContainer = range->startContainer();
676 Node* endContainer = range->endContainer();
677
678 Node* pastLastNode = range->pastLastNode();
679
680 for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTrave rsal::next(*node)) {
681 int startOffset = node == startContainer ? range->startOffset() : 0;
682 int endOffset = node == endContainer ? range->endOffset() : INT_MAX;
683 setMarkersActive(node, startOffset, endOffset, active);
684 }
685 }
686
687 void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset , unsigned endOffset, bool active)
688 {
689 MarkerLists* markers = m_markers.get(node);
690 if (!markers)
691 return;
692
693 bool docDirty = false;
694 OwnPtrWillBeMember<MarkerList>& list = (*markers)[MarkerTypeToMarkerIndex(Do cumentMarker::TextMatch)];
695 if (!list)
696 return;
697 MarkerList::iterator startPos = std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
698 for (MarkerList::iterator marker = startPos; marker != list->end(); ++marker ) {
699
700 // Markers are returned in order, so stop if we are now past the specifi ed range.
701 if ((*marker)->startOffset() >= endOffset)
702 break;
703
704 (*marker)->setActiveMatch(active);
705 docDirty = true;
706 }
707
708 // repaint the affected node
709 if (docDirty && node->layoutObject())
710 node->layoutObject()->setShouldDoFullPaintInvalidation();
711 }
712
713 #ifndef NDEBUG
714 void DocumentMarkerController::showMarkers() const
715 {
716 fprintf(stderr, "%d nodes have markers:\n", m_markers.size());
717 MarkerMap::const_iterator end = m_markers.end();
718 for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); nodeIterato r != end; ++nodeIterator) {
719 const Node* node = nodeIterator->key;
720 fprintf(stderr, "%p", node);
721 MarkerLists* markers = m_markers.get(node);
722 for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::Marke rTypeIndexesCount; ++markerListIndex) {
723 OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
724 for (unsigned markerIndex = 0; list.get() && markerIndex < list->siz e(); ++markerIndex) {
725 DocumentMarker* marker = list->at(markerIndex).get();
726 fprintf(stderr, " %d:[%d:%d](%d)", marker->type(), marker->start Offset(), marker->endOffset(), marker->activeMatch());
727 }
728 }
729
730 fprintf(stderr, "\n");
731 }
732 }
733 #endif
734
735 } // namespace blink
736
737 #ifndef NDEBUG
738 void showDocumentMarkers(const blink::DocumentMarkerController* controller)
739 {
740 if (controller)
741 controller->showMarkers();
742 }
743 #endif
OLDNEW
« no previous file with comments | « Source/core/dom/DocumentMarkerController.h ('k') | Source/core/dom/DocumentMarkerControllerTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698