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

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

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

Powered by Google App Engine
This is Rietveld 408576698