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

Side by Side Diff: third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp

Issue 2723663002: Refactor DocumentMarkerController (Closed)
Patch Set: Make requested changes, rebase (HashMap::remove() => HashMap::erase()) Created 3 years, 9 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
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org) 5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights
7 * reserved. 7 * reserved.
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/) 9 * (http://www.torchmobile.com/)
10 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 10 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
(...skipping 10 matching lines...) Expand all
21 * 21 *
22 * You should have received a copy of the GNU Library General Public License 22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to 23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA. 25 * Boston, MA 02110-1301, USA.
26 * 26 *
27 */ 27 */
28 28
29 #include "core/editing/markers/DocumentMarkerController.h" 29 #include "core/editing/markers/DocumentMarkerController.h"
30 30
31 #include <algorithm>
31 #include "core/dom/Node.h" 32 #include "core/dom/Node.h"
32 #include "core/dom/NodeTraversal.h" 33 #include "core/dom/NodeTraversal.h"
33 #include "core/dom/Range.h" 34 #include "core/dom/Range.h"
34 #include "core/dom/Text.h" 35 #include "core/dom/Text.h"
35 #include "core/editing/iterators/TextIterator.h" 36 #include "core/editing/iterators/TextIterator.h"
36 #include "core/editing/markers/RenderedDocumentMarker.h" 37 #include "core/editing/markers/CompositionMarkerList.h"
38 #include "core/editing/markers/DocumentMarkerList.h"
39 #include "core/editing/markers/EditingMarkerList.h"
40 #include "core/editing/markers/SpellCheckMarkerList.h"
41 #include "core/editing/markers/TextMatchMarkerList.h"
37 #include "core/frame/FrameView.h" 42 #include "core/frame/FrameView.h"
38 #include "core/layout/LayoutObject.h" 43 #include "core/layout/LayoutObject.h"
39 #include <algorithm>
40 44
41 #ifndef NDEBUG 45 #ifndef NDEBUG
42 #include <stdio.h> 46 #include <stdio.h>
43 #endif 47 #endif
44 48
45 namespace blink { 49 namespace blink {
46 50
47 MarkerRemoverPredicate::MarkerRemoverPredicate(const Vector<String>& words) 51 MarkerRemoverPredicate::MarkerRemoverPredicate(const Vector<String>& words)
48 : m_words(words) {} 52 : m_words(words) {}
49 53
50 bool MarkerRemoverPredicate::operator()(const DocumentMarker& documentMarker, 54 bool MarkerRemoverPredicate::operator()(const DocumentMarker& documentMarker,
51 const Text& textNode) const { 55 const Text& textNode) const {
52 unsigned start = documentMarker.startOffset(); 56 unsigned start = documentMarker.startOffset();
53 unsigned length = documentMarker.endOffset() - documentMarker.startOffset(); 57 unsigned length = documentMarker.endOffset() - documentMarker.startOffset();
54 58
55 String markerText = textNode.data().substring(start, length); 59 String markerText = textNode.data().substring(start, length);
56 return m_words.contains(markerText); 60 return m_words.contains(markerText);
57 } 61 }
58 62
59 namespace { 63 DocumentMarkerController::DocumentMarkerController(Document& document)
60 64 : m_document(&document) {
61 DocumentMarker::MarkerTypeIndex MarkerTypeToMarkerIndex( 65 setContext(&document);
62 DocumentMarker::MarkerType type) {
63 switch (type) {
64 case DocumentMarker::Spelling:
65 return DocumentMarker::SpellingMarkerIndex;
66 case DocumentMarker::Grammar:
67 return DocumentMarker::GrammarMarkerIndex;
68 case DocumentMarker::TextMatch:
69 return DocumentMarker::TextMatchMarkerIndex;
70 case DocumentMarker::Composition:
71 return DocumentMarker::CompositionMarkerIndex;
72 }
73
74 NOTREACHED();
75 return DocumentMarker::SpellingMarkerIndex;
76 } 66 }
77 67
78 } // namespace
79
80 inline bool DocumentMarkerController::possiblyHasMarkers(
81 DocumentMarker::MarkerTypes types) {
82 return m_possiblyExistingMarkerTypes.intersects(types);
83 }
84
85 DocumentMarkerController::DocumentMarkerController(const Document& document)
86 : m_possiblyExistingMarkerTypes(0), m_document(&document) {}
87
88 void DocumentMarkerController::clear() { 68 void DocumentMarkerController::clear() {
89 m_markers.clear(); 69 m_spelling.clear();
90 m_possiblyExistingMarkerTypes = 0; 70 m_grammar.clear();
71 m_textMatches.clear();
72 m_compositions.clear();
91 } 73 }
92 74
93 void DocumentMarkerController::addMarker(const Position& start, 75 void DocumentMarkerController::addMarker(const Position& start,
94 const Position& end, 76 const Position& end,
95 DocumentMarker::MarkerType type, 77 DocumentMarker::MarkerType type,
96 const String& description) { 78 const String& description) {
97 // Use a TextIterator to visit the potentially multiple nodes the range 79 // Use a TextIterator to visit the potentially multiple nodes the range
98 // covers. 80 // covers.
99 for (TextIterator markedText(start, end); !markedText.atEnd(); 81 for (TextIterator markedText(start, end); !markedText.atEnd();
100 markedText.advance()) { 82 markedText.advance()) {
101 addMarker( 83 addMarker(markedText.currentContainer(),
102 markedText.currentContainer(), 84 new DocumentMarker(
103 DocumentMarker(type, markedText.startOffsetInCurrentContainer(), 85 type, markedText.startOffsetInCurrentContainer(),
104 markedText.endOffsetInCurrentContainer(), description)); 86 markedText.endOffsetInCurrentContainer(), description));
105 } 87 }
106 } 88 }
107 89
108 void DocumentMarkerController::addTextMatchMarker(const EphemeralRange& range, 90 void DocumentMarkerController::addTextMatchMarker(const EphemeralRange& range,
109 bool activeMatch) { 91 bool activeMatch) {
110 DCHECK(!m_document->needsLayoutTreeUpdate()); 92 DCHECK(!m_document->needsLayoutTreeUpdate());
111 93
112 // Use a TextIterator to visit the potentially multiple nodes the range 94 // Use a TextIterator to visit the potentially multiple nodes the range
113 // covers. 95 // covers.
114 for (TextIterator markedText(range.startPosition(), range.endPosition()); 96 for (TextIterator markedText(range.startPosition(), range.endPosition());
115 !markedText.atEnd(); markedText.advance()) 97 !markedText.atEnd(); markedText.advance()) {
116 addMarker( 98 addMarker(markedText.currentContainer(),
117 markedText.currentContainer(), 99 new DocumentMarker(markedText.startOffsetInCurrentContainer(),
118 DocumentMarker(markedText.startOffsetInCurrentContainer(), 100 markedText.endOffsetInCurrentContainer(),
119 markedText.endOffsetInCurrentContainer(), activeMatch)); 101 activeMatch));
102 }
120 // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a 103 // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a
121 // throttling algorithm. crbug.com/6819. 104 // throttling algorithm. crbug.com/6819.
122 } 105 }
123 106
124 void DocumentMarkerController::addCompositionMarker(const Position& start, 107 void DocumentMarkerController::addCompositionMarker(const Position& start,
125 const Position& end, 108 const Position& end,
126 Color underlineColor, 109 Color underlineColor,
127 bool thick, 110 bool thick,
128 Color backgroundColor) { 111 Color backgroundColor) {
129 DCHECK(!m_document->needsLayoutTreeUpdate()); 112 DCHECK(!m_document->needsLayoutTreeUpdate());
130 113
131 for (TextIterator markedText(start, end); !markedText.atEnd(); 114 for (TextIterator markedText(start, end); !markedText.atEnd();
132 markedText.advance()) 115 markedText.advance()) {
133 addMarker(markedText.currentContainer(), 116 addMarker(markedText.currentContainer(),
134 DocumentMarker(markedText.startOffsetInCurrentContainer(), 117 new DocumentMarker(markedText.startOffsetInCurrentContainer(),
135 markedText.endOffsetInCurrentContainer(), 118 markedText.endOffsetInCurrentContainer(),
136 underlineColor, thick, backgroundColor)); 119 underlineColor, thick, backgroundColor));
120 }
137 } 121 }
138 122
139 void DocumentMarkerController::prepareForDestruction() { 123 void DocumentMarkerController::prepareForDestruction() {
140 clear(); 124 clear();
141 } 125 }
142 126
143 void DocumentMarkerController::removeMarkers( 127 void DocumentMarkerController::removeMarkers(
144 TextIterator& markedText,
145 DocumentMarker::MarkerTypes markerTypes,
146 RemovePartiallyOverlappingMarkerOrNot
147 shouldRemovePartiallyOverlappingMarker) {
148 for (; !markedText.atEnd(); markedText.advance()) {
149 if (!possiblyHasMarkers(markerTypes))
150 return;
151 DCHECK(!m_markers.isEmpty());
152
153 int startOffset = markedText.startOffsetInCurrentContainer();
154 int endOffset = markedText.endOffsetInCurrentContainer();
155 removeMarkers(markedText.currentContainer(), startOffset,
156 endOffset - startOffset, markerTypes,
157 shouldRemovePartiallyOverlappingMarker);
158 }
159 }
160
161 void DocumentMarkerController::removeMarkers(
162 const EphemeralRange& range, 128 const EphemeralRange& range,
163 DocumentMarker::MarkerTypes markerTypes, 129 DocumentMarker::MarkerTypes markerTypes,
164 RemovePartiallyOverlappingMarkerOrNot 130 RemovePartiallyOverlappingMarkerOrNot
165 shouldRemovePartiallyOverlappingMarker) { 131 shouldRemovePartiallyOverlappingMarker) {
166 DCHECK(!m_document->needsLayoutTreeUpdate()); 132 DCHECK(!m_document->needsLayoutTreeUpdate());
167 133
168 TextIterator markedText(range.startPosition(), range.endPosition()); 134 TextIterator markedText(range.startPosition(), range.endPosition());
169 DocumentMarkerController::removeMarkers( 135 DocumentMarkerController::removeMarkers(
170 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); 136 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
171 } 137 }
172 138
173 static bool startsFurther(const Member<RenderedDocumentMarker>& lhv,
174 const DocumentMarker* rhv) {
175 return lhv->startOffset() < rhv->startOffset();
176 }
177
178 static bool startsAfter(const Member<RenderedDocumentMarker>& marker,
179 size_t startOffset) {
180 return marker->startOffset() < startOffset;
181 }
182
183 static bool endsBefore(size_t startOffset,
184 const Member<RenderedDocumentMarker>& rhv) {
185 return startOffset < rhv->endOffset();
186 }
187
188 static bool compareByStart(const Member<DocumentMarker>& lhv, 139 static bool compareByStart(const Member<DocumentMarker>& lhv,
189 const Member<DocumentMarker>& rhv) { 140 const Member<DocumentMarker>& rhv) {
190 return lhv->startOffset() < rhv->startOffset(); 141 return lhv->startOffset() < rhv->startOffset();
191 } 142 }
192 143
193 static bool doesNotOverlap(const Member<RenderedDocumentMarker>& lhv,
194 const DocumentMarker* rhv) {
195 return lhv->endOffset() < rhv->startOffset();
196 }
197
198 static bool doesNotInclude(const Member<RenderedDocumentMarker>& marker,
199 size_t startOffset) {
200 return marker->endOffset() < startOffset;
201 }
202
203 static void updateMarkerRenderedRect(const Node& node,
204 RenderedDocumentMarker& marker) {
205 Range* range = Range::create(node.document());
206 // The offsets of the marker may be out-dated, so check for exceptions.
207 DummyExceptionStateForTesting exceptionState;
208 range->setStart(&const_cast<Node&>(node), marker.startOffset(),
209 exceptionState);
210 if (!exceptionState.hadException()) {
211 range->setEnd(&const_cast<Node&>(node), marker.endOffset(),
212 IGNORE_EXCEPTION_FOR_TESTING);
213 }
214 if (!exceptionState.hadException()) {
215 // TODO(yosin): Once we have a |EphemeralRange| version of |boundingBox()|,
216 // we should use it instead of |Range| version.
217 marker.setRenderedRect(LayoutRect(range->boundingBox()));
218 } else {
219 marker.nullifyRenderedRect();
220 }
221 range->dispose();
222 }
223
224 // Markers are stored in order sorted by their start offset.
225 // Markers of the same type do not overlap each other.
226
227 void DocumentMarkerController::addMarker(Node* node, 144 void DocumentMarkerController::addMarker(Node* node,
228 const DocumentMarker& newMarker) { 145 DocumentMarker* newMarker) {
229 DCHECK_GE(newMarker.endOffset(), newMarker.startOffset()); 146 DCHECK_GE(newMarker->endOffset(), newMarker->startOffset());
230 if (newMarker.endOffset() == newMarker.startOffset()) 147 if (newMarker->endOffset() == newMarker->startOffset())
231 return; 148 return;
232 149
233 m_possiblyExistingMarkerTypes.add(newMarker.type()); 150 switch (newMarker->type()) {
234 151 case DocumentMarker::TextMatch: {
235 Member<MarkerLists>& markers = 152 auto it = m_textMatches.find(node);
236 m_markers.insert(node, nullptr).storedValue->value; 153 if (it == m_textMatches.end()) {
237 if (!markers) { 154 m_textMatches.insert(node, new TextMatchMarkerList(this));
238 markers = new MarkerLists; 155 it = m_textMatches.find(node);
239 markers->grow(DocumentMarker::MarkerTypeIndexesCount); 156 }
240 } 157 static_cast<TextMatchMarkerList*>(it->value.get())->push_back(newMarker);
241 158 break;
242 DocumentMarker::MarkerTypeIndex markerListIndex = 159 }
243 MarkerTypeToMarkerIndex(newMarker.type()); 160 default: {
244 if (!markers->at(markerListIndex)) { 161 MarkerMap& markerMap = markerMapForType(newMarker->type());
245 markers->at(markerListIndex) = new MarkerList; 162 auto it = markerMap.find(node);
246 } 163 if (it == markerMap.end()) {
247 164 markerMap.insert(node, createMarkerListOfType(newMarker->type()));
248 Member<MarkerList>& list = markers->at(markerListIndex); 165 it = markerMap.find(node);
249 RenderedDocumentMarker* newRenderedMarker = 166 }
250 RenderedDocumentMarker::create(newMarker); 167 static_cast<EditingMarkerList*>(it->value.get())->insert(newMarker);
251 if (list->isEmpty() || list->back()->endOffset() < newMarker.startOffset()) {
252 list->push_back(newRenderedMarker);
253 } else {
254 if (newMarker.type() != DocumentMarker::TextMatch &&
255 newMarker.type() != DocumentMarker::Composition) {
256 mergeOverlapping(list.get(), newRenderedMarker);
257 } else {
258 MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(),
259 &newMarker, startsFurther);
260 list->insert(pos - list->begin(), newRenderedMarker);
261 } 168 }
262 } 169 }
263 170
264 // repaint the affected node 171 // repaint the affected node
265 if (node->layoutObject()) { 172 if (node->layoutObject()) {
266 node->layoutObject()->setShouldDoFullPaintInvalidation( 173 node->layoutObject()->setShouldDoFullPaintInvalidation(
267 PaintInvalidationDocumentMarkerChange); 174 PaintInvalidationDocumentMarkerChange);
268 } 175 }
269 } 176 }
270 177
271 void DocumentMarkerController::mergeOverlapping(
272 MarkerList* list,
273 RenderedDocumentMarker* toInsert) {
274 MarkerList::iterator firstOverlapping =
275 std::lower_bound(list->begin(), list->end(), toInsert, doesNotOverlap);
276 size_t index = firstOverlapping - list->begin();
277 list->insert(index, toInsert);
278 MarkerList::iterator inserted = list->begin() + index;
279 firstOverlapping = inserted + 1;
280 for (MarkerList::iterator i = firstOverlapping;
281 i != list->end() && (*i)->startOffset() <= (*inserted)->endOffset();) {
282 (*inserted)->setStartOffset(
283 std::min((*inserted)->startOffset(), (*i)->startOffset()));
284 (*inserted)->setEndOffset(
285 std::max((*inserted)->endOffset(), (*i)->endOffset()));
286 list->remove(i - list->begin());
287 }
288 }
289
290 // copies markers from srcNode to dstNode, applying the specified shift delta to 178 // copies markers from srcNode to dstNode, applying the specified shift delta to
291 // the copies. The shift is useful if, e.g., the caller has created the dstNode 179 // the copies. The shift is useful if, e.g., the caller has created the dstNode
292 // from a non-prefix substring of the srcNode. 180 // from a non-prefix substring of the srcNode.
293 void DocumentMarkerController::copyMarkers(Node* srcNode, 181 void DocumentMarkerController::copyMarkers(Node* srcNode,
294 unsigned startOffset, 182 unsigned startOffset,
295 int length, 183 int length,
296 Node* dstNode, 184 Node* dstNode,
297 int delta) { 185 int delta) {
298 if (length <= 0) 186 if (length <= 0)
299 return; 187 return;
300 188
301 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 189 bool docDirty = false;
302 return;
303 DCHECK(!m_markers.isEmpty());
304 190
305 MarkerLists* markers = m_markers.at(srcNode); 191 for (Member<DocumentMarkerList> list : getMarkerListsForNode(srcNode)) {
306 if (!markers) 192 docDirty =
307 return; 193 list->copyMarkers(startOffset, length, dstNode, delta) || docDirty;
308
309 bool docDirty = false;
310 for (size_t markerListIndex = 0;
311 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
312 ++markerListIndex) {
313 Member<MarkerList>& list = (*markers)[markerListIndex];
314 if (!list)
315 continue;
316
317 unsigned endOffset = startOffset + length - 1;
318 MarkerList::iterator startPos = std::lower_bound(
319 list->begin(), list->end(), startOffset, doesNotInclude);
320 for (MarkerList::iterator i = startPos; i != list->end(); ++i) {
321 DocumentMarker* marker = i->get();
322
323 // stop if we are now past the specified range
324 if (marker->startOffset() > endOffset)
325 break;
326
327 // pin the marker to the specified range and apply the shift delta
328 docDirty = true;
329 if (marker->startOffset() < startOffset)
330 marker->setStartOffset(startOffset);
331 if (marker->endOffset() > endOffset)
332 marker->setEndOffset(endOffset);
333 marker->shiftOffsets(delta);
334
335 addMarker(dstNode, *marker);
336 }
337 } 194 }
338 195
339 // repaint the affected node 196 // repaint the affected node
340 if (docDirty && dstNode->layoutObject()) { 197 if (docDirty && dstNode->layoutObject()) {
341 dstNode->layoutObject()->setShouldDoFullPaintInvalidation( 198 dstNode->layoutObject()->setShouldDoFullPaintInvalidation(
342 PaintInvalidationDocumentMarkerChange); 199 PaintInvalidationDocumentMarkerChange);
343 } 200 }
344 } 201 }
345 202
346 void DocumentMarkerController::removeMarkers( 203 void DocumentMarkerController::removeMarkers(
347 Node* node, 204 Node* node,
348 unsigned startOffset, 205 unsigned startOffset,
349 int length, 206 int length,
350 DocumentMarker::MarkerTypes markerTypes, 207 DocumentMarker::MarkerTypes markerTypes,
351 RemovePartiallyOverlappingMarkerOrNot 208 RemovePartiallyOverlappingMarkerOrNot
352 shouldRemovePartiallyOverlappingMarker) { 209 shouldRemovePartiallyOverlappingMarker) {
353 if (length <= 0) 210 if (length <= 0)
354 return; 211 return;
355 212
356 if (!possiblyHasMarkers(markerTypes))
357 return;
358 DCHECK(!(m_markers.isEmpty()));
359
360 MarkerLists* markers = m_markers.at(node);
361 if (!markers)
362 return;
363
364 bool docDirty = false; 213 bool docDirty = false;
365 size_t emptyListsCount = 0; 214 for (size_t markerListIndex = static_cast<DocumentMarker::MarkerType>(0);
366 for (size_t markerListIndex = 0;
367 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 215 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
368 ++markerListIndex) { 216 ++markerListIndex) {
369 Member<MarkerList>& list = (*markers)[markerListIndex]; 217 DocumentMarker::MarkerType type =
370 if (!list || list->isEmpty()) { 218 static_cast<DocumentMarker::MarkerType>(1 << markerListIndex);
rlanday 2017/03/21 21:19:06 Iterating over the MarkerTypes like this feels slo
371 if (list.get() && list->isEmpty()) 219 if (markerTypes.contains(type)) {
372 list.clear(); 220 MarkerMap& markerMap = markerMapForType(type);
373 ++emptyListsCount; 221 auto it = markerMap.find(node);
374 continue; 222 if (it != markerMap.end()) {
375 } 223 it->value->removeMarkers(startOffset, length,
376 if (!markerTypes.contains((*list->begin())->type())) 224 shouldRemovePartiallyOverlappingMarker,
377 continue; 225 &docDirty);
378 unsigned endOffset = startOffset + length; 226 if (it->value->empty())
379 MarkerList::iterator startPos = 227 markerMap.erase(node);
380 std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
381 for (MarkerList::iterator i = startPos; i != list->end();) {
382 DocumentMarker marker(*i->get());
383
384 // markers are returned in order, so stop if we are now past the specified
385 // range
386 if (marker.startOffset() >= endOffset)
387 break;
388
389 // at this point we know that marker and target intersect in some way
390 docDirty = true;
391
392 // pitch the old marker
393 list->remove(i - list->begin());
394
395 if (shouldRemovePartiallyOverlappingMarker) {
396 // Stop here. Don't add resulting slices back.
397 continue;
398 }
399
400 // add either of the resulting slices that are left after removing target
401 if (startOffset > marker.startOffset()) {
402 DocumentMarker newLeft = marker;
403 newLeft.setEndOffset(startOffset);
404 size_t insertIndex = i - list->begin();
405 list->insert(insertIndex, RenderedDocumentMarker::create(newLeft));
406 // Move to the marker after the inserted one.
407 i = list->begin() + insertIndex + 1;
408 }
409 if (marker.endOffset() > endOffset) {
410 DocumentMarker newRight = marker;
411 newRight.setStartOffset(endOffset);
412 size_t insertIndex = i - list->begin();
413 list->insert(insertIndex, RenderedDocumentMarker::create(newRight));
414 // Move to the marker after the inserted one.
415 i = list->begin() + insertIndex + 1;
416 } 228 }
417 } 229 }
418
419 if (list->isEmpty()) {
420 list.clear();
421 ++emptyListsCount;
422 }
423 }
424
425 if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) {
426 m_markers.erase(node);
427 if (m_markers.isEmpty())
428 m_possiblyExistingMarkerTypes = 0;
429 } 230 }
430 231
431 // repaint the affected node 232 // repaint the affected node
432 if (docDirty && node->layoutObject()) { 233 if (docDirty && node->layoutObject()) {
433 node->layoutObject()->setShouldDoFullPaintInvalidation( 234 node->layoutObject()->setShouldDoFullPaintInvalidation(
434 PaintInvalidationDocumentMarkerChange); 235 PaintInvalidationDocumentMarkerChange);
435 } 236 }
436 } 237 }
437 238
438 DocumentMarkerVector DocumentMarkerController::markersFor( 239 DocumentMarkerVector DocumentMarkerController::markersFor(
439 Node* node, 240 Node* node,
440 DocumentMarker::MarkerTypes markerTypes) { 241 DocumentMarker::MarkerTypes markerTypes) {
441 DocumentMarkerVector result; 242 DocumentMarkerVector result;
442 243
443 MarkerLists* markers = m_markers.at(node); 244 for (Member<DocumentMarkerList> list :
444 if (!markers) 245 getMarkerListsForNode(node, markerTypes)) {
445 return result; 246 list->appendMarkersToInputList(&result);
446
447 for (size_t markerListIndex = 0;
448 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
449 ++markerListIndex) {
450 Member<MarkerList>& list = (*markers)[markerListIndex];
451 if (!list || list->isEmpty() ||
452 !markerTypes.contains((*list->begin())->type()))
453 continue;
454
455 for (size_t i = 0; i < list->size(); ++i)
456 result.push_back(list->at(i).get());
457 } 247 }
458 248
459 std::sort(result.begin(), result.end(), compareByStart); 249 std::sort(result.begin(), result.end(), compareByStart);
460 return result; 250 return result;
461 } 251 }
462 252
463 DocumentMarkerVector DocumentMarkerController::markers() { 253 DocumentMarkerVector DocumentMarkerController::markers() {
464 DocumentMarkerVector result; 254 DocumentMarkerVector result;
465 for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) { 255 for (auto it = m_spelling.begin(); it != m_spelling.end(); ++it)
466 MarkerLists* markers = i->value.get(); 256 it->value->appendMarkersToInputList(&result);
467 for (size_t markerListIndex = 0; 257
468 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 258 for (auto it = m_grammar.begin(); it != m_grammar.end(); ++it)
469 ++markerListIndex) { 259 it->value->appendMarkersToInputList(&result);
470 Member<MarkerList>& list = (*markers)[markerListIndex]; 260
471 for (size_t j = 0; list.get() && j < list->size(); ++j) 261 for (auto it = m_textMatches.begin(); it != m_textMatches.end(); ++it)
472 result.push_back(list->at(j).get()); 262 it->value->appendMarkersToInputList(&result);
473 } 263
474 } 264 for (auto it = m_compositions.begin(); it != m_compositions.end(); ++it)
265 it->value->appendMarkersToInputList(&result);
266
475 std::sort(result.begin(), result.end(), compareByStart); 267 std::sort(result.begin(), result.end(), compareByStart);
476 return result; 268 return result;
477 } 269 }
478 270
479 DocumentMarkerVector DocumentMarkerController::markersInRange( 271 DocumentMarkerVector DocumentMarkerController::markersInRange(
480 const EphemeralRange& range, 272 const EphemeralRange& range,
481 DocumentMarker::MarkerTypes markerTypes) { 273 DocumentMarker::MarkerTypes markerTypes) {
482 if (!possiblyHasMarkers(markerTypes))
483 return DocumentMarkerVector();
484 274
485 DocumentMarkerVector foundMarkers; 275 DocumentMarkerVector foundMarkers;
486 276
487 Node* startContainer = range.startPosition().computeContainerNode(); 277 Node* startContainer = range.startPosition().computeContainerNode();
488 DCHECK(startContainer); 278 DCHECK(startContainer);
489 unsigned startOffset = static_cast<unsigned>( 279 unsigned startOffset = static_cast<unsigned>(
490 range.startPosition().computeOffsetInContainerNode()); 280 range.startPosition().computeOffsetInContainerNode());
491 Node* endContainer = range.endPosition().computeContainerNode(); 281 Node* endContainer = range.endPosition().computeContainerNode();
492 DCHECK(endContainer); 282 DCHECK(endContainer);
493 unsigned endOffset = 283 unsigned endOffset =
494 static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode()); 284 static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode());
495 285
496 for (Node& node : range.nodes()) { 286 for (Node& node : range.nodes()) {
497 for (DocumentMarker* marker : markersFor(&node)) { 287 for (DocumentMarker* marker : markersFor(&node)) {
498 if (!markerTypes.contains(marker->type())) 288 if (!markerTypes.contains(marker->type()))
499 continue; 289 continue;
500 if (node == startContainer && marker->endOffset() <= startOffset) 290 if (node == startContainer && marker->endOffset() <= startOffset)
501 continue; 291 continue;
502 if (node == endContainer && marker->startOffset() >= endOffset) 292 if (node == endContainer && marker->startOffset() >= endOffset)
503 continue; 293 continue;
504 foundMarkers.push_back(marker); 294 foundMarkers.push_back(marker);
505 } 295 }
506 } 296 }
507 return foundMarkers; 297 return foundMarkers;
508 } 298 }
509 299
300 // This method is only ever called with the type DocumentMarker::TextMatch
301 // TODO(rlanday): remove the param
510 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers( 302 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(
511 DocumentMarker::MarkerType markerType) { 303 DocumentMarker::MarkerType) {
512 Vector<IntRect> result; 304 Vector<IntRect> result;
513 305 for (auto nodeIterator = m_textMatches.begin();
514 if (!possiblyHasMarkers(markerType)) 306 nodeIterator != m_textMatches.end(); ++nodeIterator) {
515 return result;
516 DCHECK(!(m_markers.isEmpty()));
517
518 // outer loop: process each node
519 MarkerMap::iterator end = m_markers.end();
520 for (MarkerMap::iterator nodeIterator = m_markers.begin();
521 nodeIterator != end; ++nodeIterator) {
522 // inner loop; process each marker in this node
523 const Node& node = *nodeIterator->key; 307 const Node& node = *nodeIterator->key;
524 MarkerLists* markers = nodeIterator->value.get(); 308 TextMatchMarkerList* list =
525 for (size_t markerListIndex = 0; 309 static_cast<TextMatchMarkerList*>(nodeIterator->value.get());
526 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 310 #if DCHECK_IS_ON()
527 ++markerListIndex) { 311 if (!list->empty()) {
528 Member<MarkerList>& list = (*markers)[markerListIndex]; 312 DCHECK(!m_document->view() || !m_document->view()->needsLayout());
529 if (!list || list->isEmpty() || (*list->begin())->type() != markerType) 313 DCHECK(!m_document->needsLayoutTreeUpdate());
530 continue;
531 for (unsigned markerIndex = 0; markerIndex < list->size();
532 ++markerIndex) {
533 RenderedDocumentMarker* marker = list->at(markerIndex).get();
534 updateMarkerRenderedRectIfNeeded(node, *marker);
535 if (!marker->isRendered())
536 continue;
537 result.push_back(marker->renderedRect());
538 }
539 } 314 }
315 #endif
316 list->appendRenderedRectsToInputList(node, &result);
540 } 317 }
541 318
542 return result; 319 return result;
543 } 320 }
544 321
545 static void invalidatePaintForTickmarks(const Node& node) { 322 static void invalidatePaintForTickmarks(const Node& node) {
546 if (FrameView* frameView = node.document().view()) 323 if (FrameView* frameView = node.document().view())
547 frameView->invalidatePaintForTickmarks(); 324 frameView->invalidatePaintForTickmarks();
548 } 325 }
549 326
550 void DocumentMarkerController::updateMarkerRenderedRectIfNeeded( 327 void DocumentMarkerController::invalidateRectsForMarkersInNode(Node& node) {
551 const Node& node, 328 if (!m_textMatches.contains(&node))
552 RenderedDocumentMarker& marker) { 329 return;
553 DCHECK(!m_document->view() || !m_document->view()->needsLayout());
554 DCHECK(!m_document->needsLayoutTreeUpdate());
555 if (!marker.isValid())
556 updateMarkerRenderedRect(node, marker);
557 }
558 330
559 void DocumentMarkerController::invalidateRectsForMarkersInNode( 331 static_cast<TextMatchMarkerList*>(m_textMatches.find(&node)->value.get())
560 const Node& node) { 332 ->invalidateRects();
561 MarkerLists* markers = m_markers.at(&node); 333 invalidatePaintForTickmarks(node);
562
563 for (auto& markerList : *markers) {
564 if (!markerList || markerList->isEmpty())
565 continue;
566
567 for (auto& marker : *markerList)
568 marker->invalidate();
569
570 if (markerList->front()->type() == DocumentMarker::TextMatch)
571 invalidatePaintForTickmarks(node);
572 }
573 } 334 }
574 335
575 void DocumentMarkerController::invalidateRectsForAllMarkers() { 336 void DocumentMarkerController::invalidateRectsForAllMarkers() {
576 for (auto& nodeMarkers : m_markers) { 337 for (auto& nodeMarkers : m_textMatches)
577 const Node& node = *nodeMarkers.key; 338 invalidateRectsForMarkersInNode(*nodeMarkers.key);
578 for (auto& markerList : *nodeMarkers.value) {
579 if (!markerList || markerList->isEmpty())
580 continue;
581
582 for (auto& marker : *markerList)
583 marker->invalidate();
584
585 if (markerList->front()->type() == DocumentMarker::TextMatch)
586 invalidatePaintForTickmarks(node);
587 }
588 }
589 } 339 }
590 340
591 DEFINE_TRACE(DocumentMarkerController) { 341 DEFINE_TRACE(DocumentMarkerController) {
592 visitor->trace(m_markers); 342 visitor->trace(m_spelling);
343 visitor->trace(m_grammar);
344 visitor->trace(m_textMatches);
345 visitor->trace(m_compositions);
593 visitor->trace(m_document); 346 visitor->trace(m_document);
347 SynchronousMutationObserver::trace(visitor);
594 } 348 }
595 349
596 void DocumentMarkerController::removeMarkers( 350 void DocumentMarkerController::removeMarkers(
597 Node* node, 351 Node* node,
598 DocumentMarker::MarkerTypes markerTypes) { 352 DocumentMarker::MarkerTypes markerTypes) {
599 if (!possiblyHasMarkers(markerTypes)) 353 if (markerTypes.contains(DocumentMarker::Spelling))
600 return; 354 m_spelling.erase(node);
601 DCHECK(!m_markers.isEmpty());
602 355
603 MarkerMap::iterator iterator = m_markers.find(node); 356 if (markerTypes.contains(DocumentMarker::Grammar))
604 if (iterator != m_markers.end()) 357 m_grammar.erase(node);
605 removeMarkersFromList(iterator, markerTypes); 358
359 if (markerTypes.contains(DocumentMarker::TextMatch))
360 m_textMatches.erase(node);
361
362 if (markerTypes.contains(DocumentMarker::Composition))
363 m_compositions.erase(node);
364 }
365
366 void DocumentMarkerController::removeMarkers(
367 DocumentMarker::MarkerTypes markerTypes) {
368 if (markerTypes.contains(DocumentMarker::Spelling))
369 m_spelling.clear();
370
371 if (markerTypes.contains(DocumentMarker::Grammar))
372 m_grammar.clear();
373
374 if (markerTypes.contains(DocumentMarker::TextMatch))
375 m_textMatches.clear();
376
377 if (markerTypes.contains(DocumentMarker::Composition))
378 m_compositions.clear();
606 } 379 }
607 380
608 void DocumentMarkerController::removeMarkers( 381 void DocumentMarkerController::removeMarkers(
609 const MarkerRemoverPredicate& shouldRemoveMarker) { 382 const MarkerRemoverPredicate& shouldRemoveMarker) {
610 for (auto& nodeMarkers : m_markers) { 383 for (auto& nodeMarkers : m_spelling) {
611 const Node& node = *nodeMarkers.key; 384 const Node& node = *nodeMarkers.key;
612 if (!node.isTextNode()) // MarkerRemoverPredicate requires a Text node. 385 if (!node.isTextNode())
613 continue; 386 continue;
614 MarkerLists& markers = *nodeMarkers.value; 387 static_cast<SpellCheckMarkerList*>(nodeMarkers.value.get())
615 for (size_t markerListIndex = 0; 388 ->removeMarkersForWords(static_cast<const Text&>(node),
616 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 389 shouldRemoveMarker.m_words);
617 ++markerListIndex) {
618 Member<MarkerList>& list = markers[markerListIndex];
619 if (!list)
620 continue;
621 bool removedMarkers = false;
622 for (size_t j = list->size(); j > 0; --j) {
623 if (shouldRemoveMarker(*list->at(j - 1),
624 static_cast<const Text&>(node))) {
625 list->remove(j - 1);
626 removedMarkers = true;
627 }
628 }
629 if (removedMarkers &&
630 markerListIndex == DocumentMarker::TextMatchMarkerIndex)
631 invalidatePaintForTickmarks(node);
632 }
633 }
634 }
635
636 void DocumentMarkerController::removeMarkers(
637 DocumentMarker::MarkerTypes markerTypes) {
638 if (!possiblyHasMarkers(markerTypes))
639 return;
640 DCHECK(!m_markers.isEmpty());
641
642 HeapVector<Member<const Node>> nodesWithMarkers;
643 copyKeysToVector(m_markers, nodesWithMarkers);
644 unsigned size = nodesWithMarkers.size();
645 for (unsigned i = 0; i < size; ++i) {
646 MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]);
647 if (iterator != m_markers.end())
648 removeMarkersFromList(iterator, markerTypes);
649 }
650
651 m_possiblyExistingMarkerTypes.remove(markerTypes);
652 }
653
654 void DocumentMarkerController::removeMarkersFromList(
655 MarkerMap::iterator iterator,
656 DocumentMarker::MarkerTypes markerTypes) {
657 bool needsRepainting = false;
658 bool nodeCanBeRemoved;
659
660 size_t emptyListsCount = 0;
661 if (markerTypes == DocumentMarker::AllMarkers()) {
662 needsRepainting = true;
663 nodeCanBeRemoved = true;
664 } else {
665 MarkerLists* markers = iterator->value.get();
666
667 for (size_t markerListIndex = 0;
668 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
669 ++markerListIndex) {
670 Member<MarkerList>& list = (*markers)[markerListIndex];
671 if (!list || list->isEmpty()) {
672 if (list.get() && list->isEmpty())
673 list.clear();
674 ++emptyListsCount;
675 continue;
676 }
677 if (markerTypes.contains((*list->begin())->type())) {
678 list->clear();
679 list.clear();
680 ++emptyListsCount;
681 needsRepainting = true;
682 }
683 }
684
685 nodeCanBeRemoved =
686 emptyListsCount == DocumentMarker::MarkerTypeIndexesCount;
687 }
688
689 if (needsRepainting) {
690 const Node& node = *iterator->key;
691 if (LayoutObject* layoutObject = node.layoutObject()) {
692 layoutObject->setShouldDoFullPaintInvalidation(
693 PaintInvalidationDocumentMarkerChange);
694 }
695 invalidatePaintForTickmarks(node);
696 }
697
698 if (nodeCanBeRemoved) {
699 m_markers.erase(iterator);
700 if (m_markers.isEmpty())
701 m_possiblyExistingMarkerTypes = 0;
702 } 390 }
703 } 391 }
704 392
705 void DocumentMarkerController::repaintMarkers( 393 void DocumentMarkerController::repaintMarkers(
706 DocumentMarker::MarkerTypes markerTypes) { 394 DocumentMarker::MarkerTypes markerTypes) {
707 if (!possiblyHasMarkers(markerTypes)) 395 HeapHashSet<Member<Node>> nodesToRepaint;
708 return; 396 for (auto& nodeMarkers : m_spelling) {
709 DCHECK(!m_markers.isEmpty()); 397 if (!nodeMarkers.value->empty())
710 398 nodesToRepaint.insert(nodeMarkers.key.get());
711 // outer loop: process each markered node in the document
712 MarkerMap::iterator end = m_markers.end();
713 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
714 const Node* node = i->key;
715
716 // inner loop: process each marker in the current node
717 MarkerLists* markers = i->value.get();
718 for (size_t markerListIndex = 0;
719 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
720 ++markerListIndex) {
721 Member<MarkerList>& list = (*markers)[markerListIndex];
722 if (!list || list->isEmpty() ||
723 !markerTypes.contains((*list->begin())->type()))
724 continue;
725
726 // cause the node to be redrawn
727 if (LayoutObject* layoutObject = node->layoutObject()) {
728 layoutObject->setShouldDoFullPaintInvalidation(
729 PaintInvalidationDocumentMarkerChange);
730 break;
731 }
732 }
733 }
734 }
735
736 void DocumentMarkerController::shiftMarkers(Node* node,
737 unsigned startOffset,
738 int delta) {
739 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
740 return;
741 DCHECK(!m_markers.isEmpty());
742
743 MarkerLists* markers = m_markers.at(node);
744 if (!markers)
745 return;
746
747 bool didShiftMarker = false;
748 for (size_t markerListIndex = 0;
749 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
750 ++markerListIndex) {
751 Member<MarkerList>& list = (*markers)[markerListIndex];
752 if (!list)
753 continue;
754 MarkerList::iterator startPos =
755 std::lower_bound(list->begin(), list->end(), startOffset, startsAfter);
756 for (MarkerList::iterator marker = startPos; marker != list->end();
757 ++marker) {
758 #if DCHECK_IS_ON()
759 int startOffset = (*marker)->startOffset();
760 DCHECK_GE(startOffset + delta, 0);
761 #endif
762 (*marker)->shiftOffsets(delta);
763 didShiftMarker = true;
764 }
765 } 399 }
766 400
767 if (didShiftMarker) { 401 for (auto& nodeMarkers : m_grammar) {
768 invalidateRectsForMarkersInNode(*node); 402 if (!nodeMarkers.value->empty())
769 // repaint the affected node 403 nodesToRepaint.insert(nodeMarkers.key.get());
770 if (node->layoutObject()) { 404 }
771 node->layoutObject()->setShouldDoFullPaintInvalidation( 405
406 for (auto& nodeMarkers : m_textMatches) {
407 if (!nodeMarkers.value->empty())
408 nodesToRepaint.insert(nodeMarkers.key.get());
409 }
410
411 for (auto& nodeMarkers : m_compositions) {
412 if (!nodeMarkers.value->empty())
413 nodesToRepaint.insert(nodeMarkers.key.get());
414 }
415
416 for (Member<Node> node : nodesToRepaint) {
417 // cause the node to be redrawn
418 if (LayoutObject* layoutObject = node->layoutObject()) {
419 layoutObject->setShouldDoFullPaintInvalidation(
772 PaintInvalidationDocumentMarkerChange); 420 PaintInvalidationDocumentMarkerChange);
421 break;
773 } 422 }
774 } 423 }
775 } 424 }
776 425
777 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, 426 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
778 bool active) { 427 bool active) {
779 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
780 return false;
781
782 DCHECK(!m_markers.isEmpty());
783
784 Node* const startContainer = range.startPosition().computeContainerNode(); 428 Node* const startContainer = range.startPosition().computeContainerNode();
785 DCHECK(startContainer); 429 DCHECK(startContainer);
786 Node* const endContainer = range.endPosition().computeContainerNode(); 430 Node* const endContainer = range.endPosition().computeContainerNode();
787 DCHECK(endContainer); 431 DCHECK(endContainer);
788 432
789 const unsigned containerStartOffset = 433 const unsigned containerStartOffset =
790 range.startPosition().computeOffsetInContainerNode(); 434 range.startPosition().computeOffsetInContainerNode();
791 const unsigned containerEndOffset = 435 const unsigned containerEndOffset =
792 range.endPosition().computeOffsetInContainerNode(); 436 range.endPosition().computeOffsetInContainerNode();
793 437
794 bool markerFound = false; 438 bool markerFound = false;
795 for (Node& node : range.nodes()) { 439 for (Node& node : range.nodes()) {
796 int startOffset = node == startContainer ? containerStartOffset : 0; 440 int startOffset = node == startContainer ? containerStartOffset : 0;
797 int endOffset = node == endContainer ? containerEndOffset : INT_MAX; 441 int endOffset = node == endContainer ? containerEndOffset : INT_MAX;
798 markerFound |= setMarkersActive(&node, startOffset, endOffset, active); 442 markerFound |= setMarkersActive(&node, startOffset, endOffset, active);
799 } 443 }
800 return markerFound; 444 return markerFound;
801 } 445 }
802 446
447 bool DocumentMarkerController::hasMarkers(Node* node) const {
448 return m_spelling.contains(node) || m_grammar.contains(node) ||
449 m_textMatches.contains(node) || m_compositions.contains(node);
450 }
451
803 bool DocumentMarkerController::setMarkersActive(Node* node, 452 bool DocumentMarkerController::setMarkersActive(Node* node,
804 unsigned startOffset, 453 unsigned startOffset,
805 unsigned endOffset, 454 unsigned endOffset,
806 bool active) { 455 bool active) {
807 MarkerLists* markers = m_markers.at(node);
808 if (!markers)
809 return false;
810
811 bool docDirty = false; 456 bool docDirty = false;
812 Member<MarkerList>& list = 457 if (m_textMatches.contains(node)) {
813 (*markers)[MarkerTypeToMarkerIndex(DocumentMarker::TextMatch)]; 458 docDirty = static_cast<TextMatchMarkerList*>(m_textMatches.at(node))
814 if (!list) 459 ->setTextMatchMarkersActive(startOffset, endOffset, active);
815 return false; 460 }
816 MarkerList::iterator startPos = 461
817 std::upper_bound(list->begin(), list->end(), startOffset, endsBefore); 462 if (docDirty && node->layoutObject())
818 for (MarkerList::iterator marker = startPos; marker != list->end();
819 ++marker) {
820 // Markers are returned in order, so stop if we are now past the specified
821 // range.
822 if ((*marker)->startOffset() >= endOffset)
823 break;
824
825 (*marker)->setActiveMatch(active);
826 docDirty = true;
827 }
828
829 // repaint the affected node
830 if (docDirty && node->layoutObject()) {
831 node->layoutObject()->setShouldDoFullPaintInvalidation( 463 node->layoutObject()->setShouldDoFullPaintInvalidation(
832 PaintInvalidationDocumentMarkerChange); 464 PaintInvalidationDocumentMarkerChange);
833 } 465
834 return docDirty; 466 return docDirty;
835 } 467 }
836 468
837 #ifndef NDEBUG 469 #ifndef NDEBUG
470 static String showMarkerHelper(const DocumentMarkerVector& markers) {
471 StringBuilder builder;
472
473 for (const Member<DocumentMarker> marker : markers) {
474 builder.append(" ");
475 builder.appendNumber(marker->type());
476 builder.append(":[");
477 builder.appendNumber(marker->startOffset());
478 builder.append(":");
479 builder.appendNumber(marker->endOffset());
480 builder.append("](");
481 builder.appendNumber(marker->activeMatch());
482 builder.append(")");
483 }
484
485 return builder.toString();
486 }
487
838 void DocumentMarkerController::showMarkers() const { 488 void DocumentMarkerController::showMarkers() const {
839 StringBuilder builder; 489 StringBuilder builder;
840 MarkerMap::const_iterator end = m_markers.end(); 490
841 for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); 491 HeapHashSet<Member<Node>> nodes;
842 nodeIterator != end; ++nodeIterator) { 492 for (const auto& nodeMarkers : m_spelling)
843 const Node* node = nodeIterator->key; 493 nodes.insert(nodeMarkers.key);
494 for (const auto& nodeMarkers : m_grammar)
495 nodes.insert(nodeMarkers.key);
496 for (const auto& nodeMarkers : m_textMatches)
497 nodes.insert(nodeMarkers.key);
498 for (const auto& nodeMarkers : m_compositions)
499 nodes.insert(nodeMarkers.key);
500
501 HeapHashSet<Member<const Node>> nodesWithMarkers;
502 for (Node* node : nodes) {
844 builder.append(String::format("%p", node)); 503 builder.append(String::format("%p", node));
845 MarkerLists* markers = m_markers.at(node); 504
846 for (size_t markerListIndex = 0; 505 if (m_spelling.contains(node)) {
847 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 506 DocumentMarkerVector markers;
848 ++markerListIndex) { 507 m_spelling.at(node)->appendMarkersToInputList(&markers);
849 Member<MarkerList>& list = (*markers)[markerListIndex]; 508 if (!markers.isEmpty()) {
850 for (unsigned markerIndex = 0; list.get() && markerIndex < list->size(); 509 builder.append(showMarkerHelper(markers));
851 ++markerIndex) { 510 nodesWithMarkers.insert(node);
852 DocumentMarker* marker = list->at(markerIndex).get(); 511 }
853 builder.append(" "); 512 }
854 builder.appendNumber(marker->type()); 513
855 builder.append(":["); 514 if (m_grammar.contains(node)) {
856 builder.appendNumber(marker->startOffset()); 515 DocumentMarkerVector markers;
857 builder.append(":"); 516 m_grammar.at(node)->appendMarkersToInputList(&markers);
858 builder.appendNumber(marker->endOffset()); 517 if (!markers.isEmpty()) {
859 builder.append("]("); 518 builder.append(showMarkerHelper(markers));
860 builder.appendNumber(marker->activeMatch()); 519 nodesWithMarkers.insert(node);
861 builder.append(")"); 520 }
862 } 521 }
863 } 522
523 if (m_textMatches.contains(node)) {
524 DocumentMarkerVector markers;
525 m_textMatches.at(node)->appendMarkersToInputList(&markers);
526 if (!markers.isEmpty()) {
527 builder.append(showMarkerHelper(markers));
528 nodesWithMarkers.insert(node);
529 }
530 }
531
532 if (m_compositions.contains(node)) {
533 DocumentMarkerVector markers;
534 m_compositions.at(node)->appendMarkersToInputList(&markers);
535 if (!markers.isEmpty()) {
536 builder.append(showMarkerHelper(markers));
537 nodesWithMarkers.insert(node);
538 }
539 }
540
864 builder.append("\n"); 541 builder.append("\n");
865 } 542 }
866 LOG(INFO) << m_markers.size() << " nodes have markers:\n" 543 LOG(INFO) << nodesWithMarkers.size() << " nodes have markers:\n"
867 << builder.toString().utf8().data(); 544 << builder.toString().utf8().data();
868 } 545 }
869 #endif 546 #endif
870 547
548 DocumentMarkerList* DocumentMarkerController::createMarkerListOfType(
549 DocumentMarker::MarkerType type) {
550 switch (type) {
551 case DocumentMarker::Spelling:
552 return new SpellCheckMarkerList(this, DocumentMarker::Spelling);
553 case DocumentMarker::Grammar:
554 return new SpellCheckMarkerList(this, DocumentMarker::Grammar);
555 case DocumentMarker::TextMatch:
556 return new TextMatchMarkerList(this);
557 case DocumentMarker::Composition:
558 return new CompositionMarkerList(this);
559 }
560 }
561
562 HeapVector<Member<DocumentMarkerList>>
563 DocumentMarkerController::getMarkerListsForNode(
564 Node* node,
565 DocumentMarker::MarkerTypes markerTypes) {
566 HeapVector<Member<DocumentMarkerList>> markerLists;
567
568 if (markerTypes.contains(DocumentMarker::Spelling)) {
569 auto spellingIt = m_spelling.find(node);
570 if (spellingIt != m_spelling.end())
571 markerLists.push_back(spellingIt->value);
572 }
573
574 if (markerTypes.contains(DocumentMarker::Grammar)) {
575 auto grammarIt = m_grammar.find(node);
576 if (grammarIt != m_grammar.end())
577 markerLists.push_back(grammarIt->value);
578 }
579
580 if (markerTypes.contains(DocumentMarker::TextMatch)) {
581 auto textMatchesIt = m_textMatches.find(node);
582 if (textMatchesIt != m_textMatches.end())
583 markerLists.push_back(textMatchesIt->value);
584 }
585
586 if (markerTypes.contains(DocumentMarker::Composition)) {
587 auto compositionsIt = m_compositions.find(node);
588 if (compositionsIt != m_compositions.end())
589 markerLists.push_back(compositionsIt->value);
590 }
591
592 return markerLists;
593 }
594
595 DocumentMarkerController::MarkerMap& DocumentMarkerController::markerMapForType(
596 DocumentMarker::MarkerType type) {
597 switch (type) {
598 case DocumentMarker::Spelling:
599 return m_spelling;
600 case DocumentMarker::Grammar:
601 return m_grammar;
602 case DocumentMarker::TextMatch:
603 return m_textMatches;
604 case DocumentMarker::Composition:
605 return m_compositions;
606 }
607 }
608
609 void DocumentMarkerController::removeMarkers(
610 TextIterator& markedText,
611 DocumentMarker::MarkerTypes markerTypes,
612 RemovePartiallyOverlappingMarkerOrNot
613 shouldRemovePartiallyOverlappingMarker) {
614 for (; !markedText.atEnd(); markedText.advance()) {
615 int startOffset = markedText.startOffsetInCurrentContainer();
616 int endOffset = markedText.endOffsetInCurrentContainer();
617 removeMarkers(markedText.currentContainer(), startOffset,
618 endOffset - startOffset, markerTypes,
619 shouldRemovePartiallyOverlappingMarker);
620 }
621 }
622
623 // SynchronousMutationObserver
624 void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
625 unsigned offset,
626 unsigned oldLength,
627 unsigned newLength) {
628 bool didShiftMarker = false;
629 for (size_t markerListIndex = static_cast<DocumentMarker::MarkerType>(0);
630 markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
631 ++markerListIndex) {
632 DocumentMarker::MarkerType type =
633 static_cast<DocumentMarker::MarkerType>(1 << markerListIndex);
634 MarkerMap& markerMap = markerMapForType(type);
635
636 auto it = markerMap.find(node);
637 if (it != markerMap.end()) {
638 didShiftMarker = it->value->shiftMarkers(offset, oldLength, newLength) ||
639 didShiftMarker;
640 }
641 }
642
643 if (didShiftMarker) {
644 invalidateRectsForMarkersInNode(*node);
645 // repaint the affected node
646 if (node->layoutObject()) {
647 node->layoutObject()->setShouldDoFullPaintInvalidation(
648 PaintInvalidationDocumentMarkerChange);
649 }
650 }
651 }
652
871 } // namespace blink 653 } // namespace blink
872 654
873 #ifndef NDEBUG 655 #ifndef NDEBUG
874 void showDocumentMarkers(const blink::DocumentMarkerController* controller) { 656 void showDocumentMarkers(const blink::DocumentMarkerController* controller) {
875 if (controller) 657 if (controller)
876 controller->showMarkers(); 658 controller->showMarkers();
877 } 659 }
878 #endif 660 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698