OLD | NEW |
| (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 | |
OLD | NEW |