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

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

Issue 2723663002: Refactor DocumentMarkerController (Closed)
Patch Set: Remove logging 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) 52 MarkerRemoverPredicate::MarkerRemoverPredicate(const Vector<String>& words)
48 : m_words(words) {} 53 : m_words(words) {}
49 54
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) 55 DocumentMarkerController::DocumentMarkerController(const Document& document)
86 : m_possiblyExistingMarkerTypes(0), m_document(&document) {} 56 : m_document(&document) {}
87 57
88 void DocumentMarkerController::clear() { 58 void DocumentMarkerController::clear() {
89 m_markers.clear(); 59 m_spelling.clear();
90 m_possiblyExistingMarkerTypes = 0; 60 m_grammar.clear();
61 m_textMatches.clear();
62 m_compositions.clear();
91 } 63 }
92 64
93 void DocumentMarkerController::addMarker(const Position& start, 65 void DocumentMarkerController::addMarker(const Position& start,
94 const Position& end, 66 const Position& end,
95 DocumentMarker::MarkerType type, 67 DocumentMarker::MarkerType type,
96 const String& description) { 68 const String& description) {
97 // Use a TextIterator to visit the potentially multiple nodes the range 69 // Use a TextIterator to visit the potentially multiple nodes the range
98 // covers. 70 // covers.
99 for (TextIterator markedText(start, end); !markedText.atEnd(); 71 for (TextIterator markedText(start, end); !markedText.atEnd();
100 markedText.advance()) { 72 markedText.advance()) {
101 addMarker( 73 addMarker(markedText.currentContainer(),
102 markedText.currentContainer(), 74 new DocumentMarker(
103 DocumentMarker(type, markedText.startOffsetInCurrentContainer(), 75 type, markedText.startOffsetInCurrentContainer(),
104 markedText.endOffsetInCurrentContainer(), description)); 76 markedText.endOffsetInCurrentContainer(), description));
105 } 77 }
106 } 78 }
107 79
108 void DocumentMarkerController::addTextMatchMarker(const EphemeralRange& range, 80 void DocumentMarkerController::addTextMatchMarker(const EphemeralRange& range,
109 bool activeMatch) { 81 bool activeMatch) {
110 DCHECK(!m_document->needsLayoutTreeUpdate()); 82 DCHECK(!m_document->needsLayoutTreeUpdate());
111 83
112 // Use a TextIterator to visit the potentially multiple nodes the range 84 // Use a TextIterator to visit the potentially multiple nodes the range
113 // covers. 85 // covers.
114 for (TextIterator markedText(range.startPosition(), range.endPosition()); 86 for (TextIterator markedText(range.startPosition(), range.endPosition());
115 !markedText.atEnd(); markedText.advance()) 87 !markedText.atEnd(); markedText.advance()) {
116 addMarker( 88 addMarker(markedText.currentContainer(),
117 markedText.currentContainer(), 89 new DocumentMarker(markedText.startOffsetInCurrentContainer(),
118 DocumentMarker(markedText.startOffsetInCurrentContainer(), 90 markedText.endOffsetInCurrentContainer(),
119 markedText.endOffsetInCurrentContainer(), activeMatch)); 91 activeMatch));
92 }
120 // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a 93 // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a
121 // throttling algorithm. crbug.com/6819. 94 // throttling algorithm. crbug.com/6819.
122 } 95 }
123 96
124 void DocumentMarkerController::addCompositionMarker(const Position& start, 97 void DocumentMarkerController::addCompositionMarker(const Position& start,
125 const Position& end, 98 const Position& end,
126 Color underlineColor, 99 Color underlineColor,
127 bool thick, 100 bool thick,
128 Color backgroundColor) { 101 Color backgroundColor) {
129 DCHECK(!m_document->needsLayoutTreeUpdate()); 102 DCHECK(!m_document->needsLayoutTreeUpdate());
130 103
131 for (TextIterator markedText(start, end); !markedText.atEnd(); 104 for (TextIterator markedText(start, end); !markedText.atEnd();
132 markedText.advance()) 105 markedText.advance()) {
133 addMarker(markedText.currentContainer(), 106 addMarker(markedText.currentContainer(),
134 DocumentMarker(markedText.startOffsetInCurrentContainer(), 107 new DocumentMarker(markedText.startOffsetInCurrentContainer(),
135 markedText.endOffsetInCurrentContainer(), 108 markedText.endOffsetInCurrentContainer(),
136 underlineColor, thick, backgroundColor)); 109 underlineColor, thick, backgroundColor));
110 }
137 } 111 }
138 112
139 void DocumentMarkerController::prepareForDestruction() { 113 void DocumentMarkerController::prepareForDestruction() {
140 clear(); 114 clear();
141 } 115 }
142 116
143 void DocumentMarkerController::removeMarkers( 117 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, 118 const EphemeralRange& range,
163 DocumentMarker::MarkerTypes markerTypes, 119 DocumentMarker::MarkerTypes markerTypes,
164 RemovePartiallyOverlappingMarkerOrNot 120 RemovePartiallyOverlappingMarkerOrNot
165 shouldRemovePartiallyOverlappingMarker) { 121 shouldRemovePartiallyOverlappingMarker) {
166 DCHECK(!m_document->needsLayoutTreeUpdate()); 122 DCHECK(!m_document->needsLayoutTreeUpdate());
167 123
168 TextIterator markedText(range.startPosition(), range.endPosition()); 124 TextIterator markedText(range.startPosition(), range.endPosition());
169 DocumentMarkerController::removeMarkers( 125 DocumentMarkerController::removeMarkers(
170 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); 126 markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
171 } 127 }
172 128
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, 129 static bool compareByStart(const Member<DocumentMarker>& lhv,
189 const Member<DocumentMarker>& rhv) { 130 const Member<DocumentMarker>& rhv) {
190 return lhv->startOffset() < rhv->startOffset(); 131 return lhv->startOffset() < rhv->startOffset();
191 } 132 }
192 133
193 static bool doesNotOverlap(const Member<RenderedDocumentMarker>& lhv, 134 static void updateTextMatchMarkerRenderedRect(const Node& node,
194 const DocumentMarker* rhv) { 135 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()); 136 Range* range = Range::create(node.document());
206 // The offsets of the marker may be out-dated, so check for exceptions. 137 // The offsets of the marker may be out-dated, so check for exceptions.
207 DummyExceptionStateForTesting exceptionState; 138 DummyExceptionStateForTesting exceptionState;
208 range->setStart(&const_cast<Node&>(node), marker.startOffset(), 139 range->setStart(&const_cast<Node&>(node), marker.startOffset(),
209 exceptionState); 140 exceptionState);
210 if (!exceptionState.hadException()) { 141 if (!exceptionState.hadException()) {
211 range->setEnd(&const_cast<Node&>(node), marker.endOffset(), 142 range->setEnd(&const_cast<Node&>(node), marker.endOffset(),
212 IGNORE_EXCEPTION_FOR_TESTING); 143 IGNORE_EXCEPTION_FOR_TESTING);
213 } 144 }
214 if (!exceptionState.hadException()) { 145 if (!exceptionState.hadException()) {
215 // TODO(yosin): Once we have a |EphemeralRange| version of |boundingBox()|, 146 // TODO(yosin): Once we have a |EphemeralRange| version of |boundingBox()|,
216 // we should use it instead of |Range| version. 147 // we should use it instead of |Range| version.
217 marker.setRenderedRect(LayoutRect(range->boundingBox())); 148 marker.setRenderedRect(LayoutRect(range->boundingBox()));
218 } else { 149 } else {
219 marker.nullifyRenderedRect(); 150 marker.nullifyRenderedRect();
220 } 151 }
221 range->dispose(); 152 range->dispose();
222 } 153 }
223 154
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, 155 void DocumentMarkerController::addMarker(Node* node,
228 const DocumentMarker& newMarker) { 156 DocumentMarker* newMarker) {
229 DCHECK_GE(newMarker.endOffset(), newMarker.startOffset()); 157 DCHECK_GE(newMarker->endOffset(), newMarker->startOffset());
230 if (newMarker.endOffset() == newMarker.startOffset()) 158 if (newMarker->endOffset() == newMarker->startOffset())
231 return; 159 return;
232 160
233 m_possiblyExistingMarkerTypes.add(newMarker.type()); 161 switch (newMarker->type()) {
234 162 case DocumentMarker::Spelling: {
235 Member<MarkerLists>& markers = 163 auto it = m_spelling.find(node);
236 m_markers.insert(node, nullptr).storedValue->value; 164 if (it == m_spelling.end()) {
237 if (!markers) { 165 m_spelling.insert(node, new SpellingMarkerList(this));
238 markers = new MarkerLists; 166 it = m_spelling.find(node);
239 markers->grow(DocumentMarker::MarkerTypeIndexesCount); 167 }
240 } 168 it->value->insert(newMarker);
241 169 break;
242 DocumentMarker::MarkerTypeIndex markerListIndex = 170 }
243 MarkerTypeToMarkerIndex(newMarker.type()); 171 case DocumentMarker::Grammar: {
244 if (!markers->at(markerListIndex)) { 172 auto it = m_grammar.find(node);
245 markers->at(markerListIndex) = new MarkerList; 173 if (it == m_grammar.end()) {
246 } 174 m_grammar.insert(node, new GrammarMarkerList(this));
247 175 it = m_grammar.find(node);
248 Member<MarkerList>& list = markers->at(markerListIndex); 176 }
249 RenderedDocumentMarker* newRenderedMarker = 177 it->value->insert(newMarker);
250 RenderedDocumentMarker::create(newMarker); 178 break;
251 if (list->isEmpty() || list->back()->endOffset() < newMarker.startOffset()) { 179 }
252 list->push_back(newRenderedMarker); 180 case DocumentMarker::TextMatch: {
253 } else { 181 auto it = m_textMatches.find(node);
254 if (newMarker.type() != DocumentMarker::TextMatch && 182 if (it == m_textMatches.end()) {
255 newMarker.type() != DocumentMarker::Composition) { 183 m_textMatches.insert(node, new TextMatchMarkerList(this));
256 mergeOverlapping(list.get(), newRenderedMarker); 184 it = m_textMatches.find(node);
257 } else { 185 }
258 MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(), 186 it->value->push_back(static_cast<TextMatchMarker*>(newMarker));
259 &newMarker, startsFurther); 187 break;
260 list->insert(pos - list->begin(), newRenderedMarker); 188 }
189 case DocumentMarker::Composition: {
190 auto it = m_compositions.find(node);
191 if (it == m_compositions.end()) {
192 m_compositions.insert(node, new CompositionMarkerList(this));
193 it = m_compositions.find(node);
194 }
195 it->value->insert(newMarker);
196 break;
261 } 197 }
262 } 198 }
263 199
264 // repaint the affected node 200 // repaint the affected node
265 if (node->layoutObject()) 201 if (node->layoutObject())
266 node->layoutObject()->setShouldDoFullPaintInvalidation(); 202 node->layoutObject()->setShouldDoFullPaintInvalidation();
267 } 203 }
268 204
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 205 // 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 206 // the copies. The shift is useful if, e.g., the caller has created the dstNode
290 // from a non-prefix substring of the srcNode. 207 // from a non-prefix substring of the srcNode.
291 void DocumentMarkerController::copyMarkers(Node* srcNode, 208 void DocumentMarkerController::copyMarkers(Node* srcNode,
292 unsigned startOffset, 209 unsigned startOffset,
293 int length, 210 int length,
294 Node* dstNode, 211 Node* dstNode,
295 int delta) { 212 int delta) {
296 if (length <= 0) 213 if (length <= 0)
297 return; 214 return;
298 215
299 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 216 bool docDirty = false;
300 return;
301 DCHECK(!m_markers.isEmpty());
302 217
303 MarkerLists* markers = m_markers.at(srcNode); 218 auto spellingIt = m_spelling.find(srcNode);
304 if (!markers) 219 if (spellingIt != m_spelling.end()) {
305 return; 220 docDirty = docDirty || spellingIt->value->copyMarkers(startOffset, length,
rlanday 2017/03/17 01:40:15 There's a bug here, I need to order these checks t
306 221 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 } 222 }
336 223 auto grammarIt = m_grammar.find(srcNode);
224 if (grammarIt != m_grammar.end()) {
225 docDirty = docDirty || grammarIt->value->copyMarkers(startOffset, length,
226 dstNode, delta);
227 }
228 auto textMatchesIt = m_textMatches.find(srcNode);
229 if (textMatchesIt != m_textMatches.end()) {
230 docDirty = docDirty || textMatchesIt->value->copyMarkers(
231 startOffset, length, dstNode, delta);
232 }
233 auto compositionsIt = m_compositions.find(srcNode);
234 if (compositionsIt != m_compositions.end()) {
235 docDirty = docDirty || compositionsIt->value->copyMarkers(
236 startOffset, length, dstNode, delta);
237 }
337 // repaint the affected node 238 // repaint the affected node
338 if (docDirty && dstNode->layoutObject()) 239 if (docDirty && dstNode->layoutObject())
339 dstNode->layoutObject()->setShouldDoFullPaintInvalidation(); 240 dstNode->layoutObject()->setShouldDoFullPaintInvalidation();
340 } 241 }
341 242
342 void DocumentMarkerController::removeMarkers( 243 void DocumentMarkerController::removeMarkers(
343 Node* node, 244 Node* node,
344 unsigned startOffset, 245 unsigned startOffset,
345 int length, 246 int length,
346 DocumentMarker::MarkerTypes markerTypes, 247 DocumentMarker::MarkerTypes markerTypes,
347 RemovePartiallyOverlappingMarkerOrNot 248 RemovePartiallyOverlappingMarkerOrNot
348 shouldRemovePartiallyOverlappingMarker) { 249 shouldRemovePartiallyOverlappingMarker) {
349 if (length <= 0) 250 if (length <= 0)
350 return; 251 return;
351 252
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; 253 bool docDirty = false;
361 size_t emptyListsCount = 0; 254 if (markerTypes.contains(DocumentMarker::Spelling)) {
362 for (size_t markerListIndex = 0; 255 if (m_spelling.contains(node)) {
363 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 256 m_spelling.at(node)->removeMarkers(startOffset, length,
364 ++markerListIndex) { 257 shouldRemovePartiallyOverlappingMarker,
365 Member<MarkerList>& list = (*markers)[markerListIndex]; 258 &docDirty);
366 if (!list || list->isEmpty()) { 259 if (m_spelling.at(node)->empty())
367 if (list.get() && list->isEmpty()) 260 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 } 261 }
419 } 262 }
420 263
421 if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) { 264 if (markerTypes.contains(DocumentMarker::Grammar)) {
422 m_markers.erase(node); 265 if (m_grammar.contains(node)) {
423 if (m_markers.isEmpty()) 266 m_grammar.at(node)->removeMarkers(startOffset, length,
424 m_possiblyExistingMarkerTypes = 0; 267 shouldRemovePartiallyOverlappingMarker,
268 &docDirty);
269 if (m_grammar.at(node)->empty())
270 m_grammar.remove(node);
271 }
272 }
273
274 if (markerTypes.contains(DocumentMarker::TextMatch)) {
275 if (m_textMatches.contains(node)) {
276 m_textMatches.at(node)->removeMarkers(
277 startOffset, length, shouldRemovePartiallyOverlappingMarker,
278 &docDirty);
279 if (m_textMatches.at(node)->empty())
280 m_textMatches.remove(node);
281 }
282 }
283
284 if (markerTypes.contains(DocumentMarker::Composition)) {
285 if (m_compositions.contains(node)) {
286 m_compositions.at(node)->removeMarkers(
287 startOffset, length, shouldRemovePartiallyOverlappingMarker,
288 &docDirty);
289 if (m_compositions.at(node)->empty())
290 m_compositions.remove(node);
291 }
425 } 292 }
426 293
427 // repaint the affected node 294 // repaint the affected node
428 if (docDirty && node->layoutObject()) 295 if (docDirty && node->layoutObject())
429 node->layoutObject()->setShouldDoFullPaintInvalidation(); 296 node->layoutObject()->setShouldDoFullPaintInvalidation();
430 } 297 }
431 298
432 DocumentMarkerVector DocumentMarkerController::markersFor( 299 DocumentMarkerVector DocumentMarkerController::markersFor(
433 Node* node, 300 Node* node,
434 DocumentMarker::MarkerTypes markerTypes) { 301 DocumentMarker::MarkerTypes markerTypes) {
435 DocumentMarkerVector result; 302 DocumentMarkerVector result;
436 303
437 MarkerLists* markers = m_markers.at(node); 304 if (markerTypes.contains(DocumentMarker::Spelling)) {
438 if (!markers) 305 if (m_spelling.contains(node))
439 return result; 306 m_spelling.at(node)->appendMarkersToInputList(&result);
307 }
440 308
441 for (size_t markerListIndex = 0; 309 if (markerTypes.contains(DocumentMarker::Grammar)) {
442 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 310 if (m_grammar.contains(node))
443 ++markerListIndex) { 311 m_grammar.at(node)->appendMarkersToInputList(&result);
444 Member<MarkerList>& list = (*markers)[markerListIndex]; 312 }
445 if (!list || list->isEmpty() ||
446 !markerTypes.contains((*list->begin())->type()))
447 continue;
448 313
449 for (size_t i = 0; i < list->size(); ++i) 314 if (markerTypes.contains(DocumentMarker::TextMatch)) {
450 result.push_back(list->at(i).get()); 315 if (m_textMatches.contains(node))
316 m_textMatches.at(node)->appendMarkersToInputList(&result);
317 }
318
319 if (markerTypes.contains(DocumentMarker::Composition)) {
320 if (m_compositions.contains(node))
321 m_compositions.at(node)->appendMarkersToInputList(&result);
451 } 322 }
452 323
453 std::sort(result.begin(), result.end(), compareByStart); 324 std::sort(result.begin(), result.end(), compareByStart);
454 return result; 325 return result;
455 } 326 }
456 327
457 DocumentMarkerVector DocumentMarkerController::markers() { 328 DocumentMarkerVector DocumentMarkerController::markers() {
458 DocumentMarkerVector result; 329 DocumentMarkerVector result;
459 for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) { 330 for (auto it = m_spelling.begin(); it != m_spelling.end(); ++it) {
460 MarkerLists* markers = i->value.get(); 331 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 } 332 }
333
334 for (auto it = m_grammar.begin(); it != m_grammar.end(); ++it) {
335 it->value->appendMarkersToInputList(&result);
336 }
337
338 for (auto it = m_textMatches.begin(); it != m_textMatches.end(); ++it) {
339 it->value->appendMarkersToInputList(&result);
340 }
341
342 for (auto it = m_compositions.begin(); it != m_compositions.end(); ++it) {
343 it->value->appendMarkersToInputList(&result);
344 }
345
469 std::sort(result.begin(), result.end(), compareByStart); 346 std::sort(result.begin(), result.end(), compareByStart);
470 return result; 347 return result;
471 } 348 }
472 349
473 DocumentMarkerVector DocumentMarkerController::markersInRange( 350 DocumentMarkerVector DocumentMarkerController::markersInRange(
474 const EphemeralRange& range, 351 const EphemeralRange& range,
475 DocumentMarker::MarkerTypes markerTypes) { 352 DocumentMarker::MarkerTypes markerTypes) {
476 if (!possiblyHasMarkers(markerTypes))
477 return DocumentMarkerVector();
478 353
479 DocumentMarkerVector foundMarkers; 354 DocumentMarkerVector foundMarkers;
480 355
481 Node* startContainer = range.startPosition().computeContainerNode(); 356 Node* startContainer = range.startPosition().computeContainerNode();
482 DCHECK(startContainer); 357 DCHECK(startContainer);
483 unsigned startOffset = static_cast<unsigned>( 358 unsigned startOffset = static_cast<unsigned>(
484 range.startPosition().computeOffsetInContainerNode()); 359 range.startPosition().computeOffsetInContainerNode());
485 Node* endContainer = range.endPosition().computeContainerNode(); 360 Node* endContainer = range.endPosition().computeContainerNode();
486 DCHECK(endContainer); 361 DCHECK(endContainer);
487 unsigned endOffset = 362 unsigned endOffset =
488 static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode()); 363 static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode());
489 364
490 for (Node& node : range.nodes()) { 365 for (Node& node : range.nodes()) {
491 for (DocumentMarker* marker : markersFor(&node)) { 366 for (DocumentMarker* marker : markersFor(&node)) {
492 if (!markerTypes.contains(marker->type())) 367 if (!markerTypes.contains(marker->type()))
493 continue; 368 continue;
494 if (node == startContainer && marker->endOffset() <= startOffset) 369 if (node == startContainer && marker->endOffset() <= startOffset)
495 continue; 370 continue;
496 if (node == endContainer && marker->startOffset() >= endOffset) 371 if (node == endContainer && marker->startOffset() >= endOffset)
497 continue; 372 continue;
498 foundMarkers.push_back(marker); 373 foundMarkers.push_back(marker);
499 } 374 }
500 } 375 }
501 return foundMarkers; 376 return foundMarkers;
502 } 377 }
503 378
504 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers( 379 Vector<IntRect> DocumentMarkerController::renderedRectsForTextMatchMarkers() {
505 DocumentMarker::MarkerType markerType) {
506 Vector<IntRect> result; 380 Vector<IntRect> result;
507 381
508 if (!possiblyHasMarkers(markerType))
509 return result;
510 DCHECK(!(m_markers.isEmpty()));
511
512 // outer loop: process each node 382 // outer loop: process each node
513 MarkerMap::iterator end = m_markers.end(); 383 for (auto nodeIterator = m_textMatches.begin();
514 for (MarkerMap::iterator nodeIterator = m_markers.begin(); 384 nodeIterator != m_textMatches.end(); ++nodeIterator) {
515 nodeIterator != end; ++nodeIterator) {
516 // inner loop; process each marker in this node 385 // inner loop; process each marker in this node
517 const Node& node = *nodeIterator->key; 386 const Node& node = *nodeIterator->key;
518 MarkerLists* markers = nodeIterator->value.get(); 387 TextMatchMarkerList* list = nodeIterator->value.get();
519 for (size_t markerListIndex = 0; 388 for (unsigned markerIndex = 0; markerIndex < list->size(); ++markerIndex) {
520 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 389 RenderedTextMatchMarker* marker = list->at(markerIndex);
521 ++markerListIndex) { 390 updateTextMatchMarkerRenderedRectIfNeeded(node, *marker);
522 Member<MarkerList>& list = (*markers)[markerListIndex]; 391 if (!marker->isRendered())
523 if (!list || list->isEmpty() || (*list->begin())->type() != markerType)
524 continue; 392 continue;
525 for (unsigned markerIndex = 0; markerIndex < list->size(); 393 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 } 394 }
534 } 395 }
535 396
536 return result; 397 return result;
537 } 398 }
538 399
539 static void invalidatePaintForTickmarks(const Node& node) { 400 static void invalidatePaintForTickmarks(const Node& node) {
540 if (FrameView* frameView = node.document().view()) 401 if (FrameView* frameView = node.document().view())
541 frameView->invalidatePaintForTickmarks(); 402 frameView->invalidatePaintForTickmarks();
542 } 403 }
543 404
544 void DocumentMarkerController::updateMarkerRenderedRectIfNeeded( 405 void DocumentMarkerController::updateTextMatchMarkerRenderedRectIfNeeded(
545 const Node& node, 406 const Node& node,
546 RenderedDocumentMarker& marker) { 407 RenderedTextMatchMarker& marker) {
547 DCHECK(!m_document->view() || !m_document->view()->needsLayout()); 408 DCHECK(!m_document->view() || !m_document->view()->needsLayout());
548 DCHECK(!m_document->needsLayoutTreeUpdate()); 409 DCHECK(!m_document->needsLayoutTreeUpdate());
549 if (!marker.isValid()) 410 if (!marker.isValid())
550 updateMarkerRenderedRect(node, marker); 411 updateTextMatchMarkerRenderedRect(node, marker);
551 } 412 }
552 413
553 void DocumentMarkerController::invalidateRectsForMarkersInNode( 414 void DocumentMarkerController::invalidateRectsForMarkersInNode(Node& node) {
554 const Node& node) { 415 if (!m_textMatches.contains(&node))
555 MarkerLists* markers = m_markers.at(&node); 416 return;
556 417
557 for (auto& markerList : *markers) { 418 TextMatchMarkerList& markerList = *(m_textMatches.find(&node)->value);
558 if (!markerList || markerList->isEmpty())
559 continue;
560 419
561 for (auto& marker : *markerList) 420 for (Member<DocumentMarker> marker : markerList) {
562 marker->invalidate(); 421 auto renderedTextMatchMarker =
422 static_cast<RenderedTextMatchMarker*>(marker.get());
423 renderedTextMatchMarker->invalidate();
424 }
563 425
564 if (markerList->front()->type() == DocumentMarker::TextMatch) 426 invalidatePaintForTickmarks(node);
565 invalidatePaintForTickmarks(node);
566 }
567 } 427 }
568 428
569 void DocumentMarkerController::invalidateRectsForAllMarkers() { 429 void DocumentMarkerController::invalidateRectsForAllMarkers() {
570 for (auto& nodeMarkers : m_markers) { 430 for (auto& nodeMarkers : m_textMatches)
571 const Node& node = *nodeMarkers.key; 431 invalidateRectsForMarkersInNode(*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 } 432 }
584 433
585 DEFINE_TRACE(DocumentMarkerController) { 434 DEFINE_TRACE(DocumentMarkerController) {
586 visitor->trace(m_markers); 435 visitor->trace(m_spelling);
436 visitor->trace(m_grammar);
437 visitor->trace(m_textMatches);
438 visitor->trace(m_compositions);
587 visitor->trace(m_document); 439 visitor->trace(m_document);
588 } 440 }
589 441
590 void DocumentMarkerController::removeMarkers( 442 void DocumentMarkerController::removeMarkers(
591 Node* node, 443 Node* node,
592 DocumentMarker::MarkerTypes markerTypes) { 444 DocumentMarker::MarkerTypes markerTypes) {
593 if (!possiblyHasMarkers(markerTypes)) 445 if (markerTypes.contains(DocumentMarker::Spelling))
594 return; 446 m_spelling.remove(node);
595 DCHECK(!m_markers.isEmpty());
596 447
597 MarkerMap::iterator iterator = m_markers.find(node); 448 if (markerTypes.contains(DocumentMarker::Grammar))
598 if (iterator != m_markers.end()) 449 m_grammar.remove(node);
599 removeMarkersFromList(iterator, markerTypes); 450
451 if (markerTypes.contains(DocumentMarker::TextMatch))
452 m_textMatches.remove(node);
453
454 if (markerTypes.contains(DocumentMarker::Composition))
455 m_compositions.remove(node);
600 } 456 }
601 457
602 void DocumentMarkerController::removeMarkers( 458 void DocumentMarkerController::removeMarkers(
603 const MarkerRemoverPredicate& shouldRemoveMarker) { 459 const MarkerRemoverPredicate& shouldRemoveMarker) {
604 for (auto& nodeMarkers : m_markers) { 460 for (auto& nodeMarkers : m_spelling) {
605 const Node& node = *nodeMarkers.key; 461 const Node& node = *nodeMarkers.key;
606 if (!node.isTextNode()) // MarkerRemoverPredicate requires a Text node. 462 if (!node.isTextNode())
607 continue; 463 continue;
608 MarkerLists& markers = *nodeMarkers.value; 464 nodeMarkers.value->removeMarkersForWords(static_cast<const Text&>(node),
609 for (size_t markerListIndex = 0; 465 shouldRemoveMarker.m_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 } 466 }
628 } 467 }
629 468
630 void DocumentMarkerController::removeMarkers( 469 void DocumentMarkerController::removeMarkers(
631 DocumentMarker::MarkerTypes markerTypes) { 470 DocumentMarker::MarkerTypes markerTypes) {
632 if (!possiblyHasMarkers(markerTypes)) 471 if (markerTypes.contains(DocumentMarker::Spelling))
633 return; 472 m_spelling.clear();
634 DCHECK(!m_markers.isEmpty());
635 473
636 HeapVector<Member<const Node>> nodesWithMarkers; 474 if (markerTypes.contains(DocumentMarker::Grammar))
637 copyKeysToVector(m_markers, nodesWithMarkers); 475 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 476
645 m_possiblyExistingMarkerTypes.remove(markerTypes); 477 if (markerTypes.contains(DocumentMarker::TextMatch))
646 } 478 m_textMatches.clear();
647 479
648 void DocumentMarkerController::removeMarkersFromList( 480 if (markerTypes.contains(DocumentMarker::Composition))
649 MarkerMap::iterator iterator, 481 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 } 482 }
696 483
697 void DocumentMarkerController::repaintMarkers( 484 void DocumentMarkerController::repaintMarkers(
698 DocumentMarker::MarkerTypes markerTypes) { 485 DocumentMarker::MarkerTypes markerTypes) {
699 if (!possiblyHasMarkers(markerTypes)) 486 HeapHashSet<Member<Node>> nodesToRepaint;
700 return; 487 for (auto& nodeMarkers : m_spelling) {
701 DCHECK(!m_markers.isEmpty()); 488 if (!nodeMarkers.value->empty())
489 nodesToRepaint.insert(nodeMarkers.key.get());
490 }
702 491
703 // outer loop: process each markered node in the document 492 for (auto& nodeMarkers : m_grammar) {
704 MarkerMap::iterator end = m_markers.end(); 493 if (!nodeMarkers.value->empty())
705 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { 494 nodesToRepaint.insert(nodeMarkers.key.get());
706 const Node* node = i->key; 495 }
707 496
708 // inner loop: process each marker in the current node 497 for (auto& nodeMarkers : m_textMatches) {
709 MarkerLists* markers = i->value.get(); 498 if (!nodeMarkers.value->empty())
710 for (size_t markerListIndex = 0; 499 nodesToRepaint.insert(nodeMarkers.key.get());
711 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 500 }
712 ++markerListIndex) {
713 Member<MarkerList>& list = (*markers)[markerListIndex];
714 if (!list || list->isEmpty() ||
715 !markerTypes.contains((*list->begin())->type()))
716 continue;
717 501
718 // cause the node to be redrawn 502 for (auto& nodeMarkers : m_compositions) {
719 if (LayoutObject* layoutObject = node->layoutObject()) { 503 if (!nodeMarkers.value->empty())
720 layoutObject->setShouldDoFullPaintInvalidation(); 504 nodesToRepaint.insert(nodeMarkers.key.get());
721 break; 505 }
722 } 506
507 for (Member<Node> node : nodesToRepaint) {
508 // cause the node to be redrawn
509 if (LayoutObject* layoutObject = node->layoutObject()) {
510 layoutObject->setShouldDoFullPaintInvalidation();
511 break;
723 } 512 }
724 } 513 }
725 } 514 }
726 515
727 void DocumentMarkerController::shiftMarkers(Node* node, 516 void DocumentMarkerController::shiftMarkers(Node* node,
728 unsigned startOffset, 517 unsigned startOffset,
729 int delta) { 518 int delta) {
730 if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) 519 bool didShiftMarker = false;
731 return; 520 for (auto& nodeMarkers : m_spelling) {
732 DCHECK(!m_markers.isEmpty()); 521 didShiftMarker =
522 didShiftMarker || nodeMarkers.value->shiftMarkers(startOffset, delta);
rlanday 2017/03/17 01:40:15 Same bug here
523 }
733 524
734 MarkerLists* markers = m_markers.at(node); 525 for (auto& nodeMarkers : m_grammar) {
735 if (!markers) 526 didShiftMarker =
736 return; 527 didShiftMarker || nodeMarkers.value->shiftMarkers(startOffset, delta);
528 }
737 529
738 bool didShiftMarker = false; 530 for (auto& nodeMarkers : m_textMatches) {
739 for (size_t markerListIndex = 0; 531 didShiftMarker =
740 markerListIndex < DocumentMarker::MarkerTypeIndexesCount; 532 didShiftMarker || nodeMarkers.value->shiftMarkers(startOffset, delta);
741 ++markerListIndex) { 533 }
742 Member<MarkerList>& list = (*markers)[markerListIndex]; 534
743 if (!list) 535 for (auto& nodeMarkers : m_compositions) {
744 continue; 536 didShiftMarker =
745 MarkerList::iterator startPos = 537 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 } 538 }
757 539
758 if (didShiftMarker) { 540 if (didShiftMarker) {
759 invalidateRectsForMarkersInNode(*node); 541 invalidateRectsForMarkersInNode(*node);
760 // repaint the affected node 542 // repaint the affected node
761 if (node->layoutObject()) 543 if (node->layoutObject())
762 node->layoutObject()->setShouldDoFullPaintInvalidation(); 544 node->layoutObject()->setShouldDoFullPaintInvalidation();
763 } 545 }
764 } 546 }
765 547
766 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range, 548 bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
767 bool active) { 549 bool active) {
768 if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
769 return false;
770
771 DCHECK(!m_markers.isEmpty());
772
773 Node* const startContainer = range.startPosition().computeContainerNode(); 550 Node* const startContainer = range.startPosition().computeContainerNode();
774 DCHECK(startContainer); 551 DCHECK(startContainer);
775 Node* const endContainer = range.endPosition().computeContainerNode(); 552 Node* const endContainer = range.endPosition().computeContainerNode();
776 DCHECK(endContainer); 553 DCHECK(endContainer);
777 554
778 const unsigned containerStartOffset = 555 const unsigned containerStartOffset =
779 range.startPosition().computeOffsetInContainerNode(); 556 range.startPosition().computeOffsetInContainerNode();
780 const unsigned containerEndOffset = 557 const unsigned containerEndOffset =
781 range.endPosition().computeOffsetInContainerNode(); 558 range.endPosition().computeOffsetInContainerNode();
782 559
783 bool markerFound = false; 560 bool markerFound = false;
784 for (Node& node : range.nodes()) { 561 for (Node& node : range.nodes()) {
785 int startOffset = node == startContainer ? containerStartOffset : 0; 562 int startOffset = node == startContainer ? containerStartOffset : 0;
786 int endOffset = node == endContainer ? containerEndOffset : INT_MAX; 563 int endOffset = node == endContainer ? containerEndOffset : INT_MAX;
787 markerFound |= setMarkersActive(&node, startOffset, endOffset, active); 564 markerFound |= setMarkersActive(&node, startOffset, endOffset, active);
788 } 565 }
789 return markerFound; 566 return markerFound;
790 } 567 }
791 568
569 bool DocumentMarkerController::hasMarkers(Node* node) const {
570 return m_spelling.contains(node) || m_grammar.contains(node) ||
571 m_textMatches.contains(node) || m_compositions.contains(node);
572 }
573
792 bool DocumentMarkerController::setMarkersActive(Node* node, 574 bool DocumentMarkerController::setMarkersActive(Node* node,
793 unsigned startOffset, 575 unsigned startOffset,
794 unsigned endOffset, 576 unsigned endOffset,
795 bool active) { 577 bool active) {
796 MarkerLists* markers = m_markers.at(node);
797 if (!markers)
798 return false;
799
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