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

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

Issue 2723663002: Refactor DocumentMarkerController (Closed)
Patch Set: Use correct base commit 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
index dc1e08194faa0e5e3de94bdb46020662681f6b2d..29b60dbcc9004d172e795b27681167b60f0da4af 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -28,15 +28,20 @@
#include "core/editing/markers/DocumentMarkerController.h"
+#include <algorithm>
#include "core/dom/Node.h"
#include "core/dom/NodeTraversal.h"
#include "core/dom/Range.h"
#include "core/dom/Text.h"
#include "core/editing/iterators/TextIterator.h"
-#include "core/editing/markers/RenderedDocumentMarker.h"
+#include "core/editing/markers/CompositionMarkerList.h"
+#include "core/editing/markers/DocumentMarkerList.h"
+#include "core/editing/markers/GrammarMarkerList.h"
+#include "core/editing/markers/RenderedTextMatchMarker.h"
+#include "core/editing/markers/SpellingMarkerList.h"
+#include "core/editing/markers/TextMatchMarkerList.h"
#include "core/frame/FrameView.h"
#include "core/layout/LayoutObject.h"
-#include <algorithm>
#ifndef NDEBUG
#include <stdio.h>
@@ -56,40 +61,16 @@ bool MarkerRemoverPredicate::operator()(const DocumentMarker& documentMarker,
return m_words.contains(markerText);
}
-namespace {
-
-DocumentMarker::MarkerTypeIndex MarkerTypeToMarkerIndex(
- DocumentMarker::MarkerType type) {
- switch (type) {
- case DocumentMarker::Spelling:
- return DocumentMarker::SpellingMarkerIndex;
- case DocumentMarker::Grammar:
- return DocumentMarker::GrammarMarkerIndex;
- case DocumentMarker::TextMatch:
- return DocumentMarker::TextMatchMarkerIndex;
- case DocumentMarker::Composition:
- return DocumentMarker::CompositionMarkerIndex;
- }
-
- NOTREACHED();
- return DocumentMarker::SpellingMarkerIndex;
-}
-
-} // namespace
-
-inline bool DocumentMarkerController::possiblyHasMarkers(
- DocumentMarker::MarkerTypes types) {
- return m_possiblyExistingMarkerTypes.intersects(types);
-}
-
DocumentMarkerController::DocumentMarkerController(Document& document)
- : m_possiblyExistingMarkerTypes(0), m_document(&document) {
+ : m_document(&document) {
setContext(&document);
}
void DocumentMarkerController::clear() {
- m_markers.clear();
- m_possiblyExistingMarkerTypes = 0;
+ m_spelling.clear();
+ m_grammar.clear();
+ m_textMatches.clear();
+ m_compositions.clear();
}
void DocumentMarkerController::addMarker(const Position& start,
@@ -100,10 +81,10 @@ void DocumentMarkerController::addMarker(const Position& start,
// covers.
for (TextIterator markedText(start, end); !markedText.atEnd();
markedText.advance()) {
- addMarker(
- markedText.currentContainer(),
- DocumentMarker(type, markedText.startOffsetInCurrentContainer(),
- markedText.endOffsetInCurrentContainer(), description));
+ addMarker(markedText.currentContainer(),
+ new DocumentMarker(
+ type, markedText.startOffsetInCurrentContainer(),
+ markedText.endOffsetInCurrentContainer(), description));
}
}
@@ -114,11 +95,12 @@ void DocumentMarkerController::addTextMatchMarker(const EphemeralRange& range,
// Use a TextIterator to visit the potentially multiple nodes the range
// covers.
for (TextIterator markedText(range.startPosition(), range.endPosition());
- !markedText.atEnd(); markedText.advance())
- addMarker(
- markedText.currentContainer(),
- DocumentMarker(markedText.startOffsetInCurrentContainer(),
- markedText.endOffsetInCurrentContainer(), activeMatch));
+ !markedText.atEnd(); markedText.advance()) {
+ addMarker(markedText.currentContainer(),
+ new DocumentMarker(markedText.startOffsetInCurrentContainer(),
+ markedText.endOffsetInCurrentContainer(),
+ activeMatch));
+ }
// Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a
// throttling algorithm. crbug.com/6819.
}
@@ -131,11 +113,12 @@ void DocumentMarkerController::addCompositionMarker(const Position& start,
DCHECK(!m_document->needsLayoutTreeUpdate());
for (TextIterator markedText(start, end); !markedText.atEnd();
- markedText.advance())
+ markedText.advance()) {
addMarker(markedText.currentContainer(),
- DocumentMarker(markedText.startOffsetInCurrentContainer(),
- markedText.endOffsetInCurrentContainer(),
- underlineColor, thick, backgroundColor));
+ new DocumentMarker(markedText.startOffsetInCurrentContainer(),
+ markedText.endOffsetInCurrentContainer(),
+ underlineColor, thick, backgroundColor));
+ }
}
void DocumentMarkerController::prepareForDestruction() {
@@ -143,24 +126,6 @@ void DocumentMarkerController::prepareForDestruction() {
}
void DocumentMarkerController::removeMarkers(
- TextIterator& markedText,
- DocumentMarker::MarkerTypes markerTypes,
- RemovePartiallyOverlappingMarkerOrNot
- shouldRemovePartiallyOverlappingMarker) {
- for (; !markedText.atEnd(); markedText.advance()) {
- if (!possiblyHasMarkers(markerTypes))
- return;
- DCHECK(!m_markers.isEmpty());
-
- int startOffset = markedText.startOffsetInCurrentContainer();
- int endOffset = markedText.endOffsetInCurrentContainer();
- removeMarkers(markedText.currentContainer(), startOffset,
- endOffset - startOffset, markerTypes,
- shouldRemovePartiallyOverlappingMarker);
- }
-}
-
-void DocumentMarkerController::removeMarkers(
const EphemeralRange& range,
DocumentMarker::MarkerTypes markerTypes,
RemovePartiallyOverlappingMarkerOrNot
@@ -172,90 +137,36 @@ void DocumentMarkerController::removeMarkers(
markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
}
-static bool startsFurther(const Member<RenderedDocumentMarker>& lhv,
- const DocumentMarker* rhv) {
- return lhv->startOffset() < rhv->startOffset();
-}
-
-static bool endsBefore(size_t startOffset,
- const Member<RenderedDocumentMarker>& rhv) {
- return startOffset < rhv->endOffset();
-}
-
static bool compareByStart(const Member<DocumentMarker>& lhv,
const Member<DocumentMarker>& rhv) {
return lhv->startOffset() < rhv->startOffset();
}
-static bool doesNotOverlap(const Member<RenderedDocumentMarker>& lhv,
- const DocumentMarker* rhv) {
- return lhv->endOffset() < rhv->startOffset();
-}
-
-static bool doesNotInclude(const Member<RenderedDocumentMarker>& marker,
- size_t startOffset) {
- return marker->endOffset() < startOffset;
-}
-
-static void updateMarkerRenderedRect(const Node& node,
- RenderedDocumentMarker& marker) {
- Range* range = Range::create(node.document());
- // The offsets of the marker may be out-dated, so check for exceptions.
- DummyExceptionStateForTesting exceptionState;
- range->setStart(&const_cast<Node&>(node), marker.startOffset(),
- exceptionState);
- if (!exceptionState.hadException()) {
- range->setEnd(&const_cast<Node&>(node), marker.endOffset(),
- IGNORE_EXCEPTION_FOR_TESTING);
- }
- if (!exceptionState.hadException()) {
- // TODO(yosin): Once we have a |EphemeralRange| version of |boundingBox()|,
- // we should use it instead of |Range| version.
- marker.setRenderedRect(LayoutRect(range->boundingBox()));
- } else {
- marker.nullifyRenderedRect();
- }
- range->dispose();
-}
-
-// Markers are stored in order sorted by their start offset.
-// Markers of the same type do not overlap each other.
-
void DocumentMarkerController::addMarker(Node* node,
- const DocumentMarker& newMarker) {
- DCHECK_GE(newMarker.endOffset(), newMarker.startOffset());
- if (newMarker.endOffset() == newMarker.startOffset())
+ DocumentMarker* newMarker) {
+ DCHECK_GE(newMarker->endOffset(), newMarker->startOffset());
+ if (newMarker->endOffset() == newMarker->startOffset())
return;
- m_possiblyExistingMarkerTypes.add(newMarker.type());
-
- Member<MarkerLists>& markers =
- m_markers.insert(node, nullptr).storedValue->value;
- if (!markers) {
- markers = new MarkerLists;
- markers->grow(DocumentMarker::MarkerTypeIndexesCount);
- }
-
- DocumentMarker::MarkerTypeIndex markerListIndex =
- MarkerTypeToMarkerIndex(newMarker.type());
- if (!markers->at(markerListIndex)) {
- markers->at(markerListIndex) = new MarkerList;
- }
-
- Member<MarkerList>& list = markers->at(markerListIndex);
- RenderedDocumentMarker* newRenderedMarker =
- RenderedDocumentMarker::create(newMarker);
- if (list->isEmpty() || list->back()->endOffset() < newMarker.startOffset()) {
- list->push_back(newRenderedMarker);
- } else {
- if (newMarker.type() != DocumentMarker::TextMatch &&
- newMarker.type() != DocumentMarker::Composition) {
- mergeOverlapping(list.get(), newRenderedMarker);
- } else {
- MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(),
- &newMarker, startsFurther);
- list->insert(pos - list->begin(), newRenderedMarker);
+ switch (newMarker->type()) {
+ case DocumentMarker::Spelling:
+ addIntoMarkerMap(&m_spelling, node, newMarker);
+ break;
+ case DocumentMarker::Grammar:
+ addIntoMarkerMap(&m_grammar, node, newMarker);
+ break;
+ case DocumentMarker::TextMatch: {
+ auto it = m_textMatches.find(node);
+ if (it == m_textMatches.end()) {
+ m_textMatches.insert(node, new TextMatchMarkerList(this));
+ it = m_textMatches.find(node);
+ }
+ it->value->push_back(newMarker);
+ break;
}
+ case DocumentMarker::Composition:
+ addIntoMarkerMap(&m_compositions, node, newMarker);
+ break;
}
// repaint the affected node
@@ -265,25 +176,6 @@ void DocumentMarkerController::addMarker(Node* node,
}
}
-void DocumentMarkerController::mergeOverlapping(
- MarkerList* list,
- RenderedDocumentMarker* toInsert) {
- MarkerList::iterator firstOverlapping =
- std::lower_bound(list->begin(), list->end(), toInsert, doesNotOverlap);
- size_t index = firstOverlapping - list->begin();
- list->insert(index, toInsert);
- MarkerList::iterator inserted = list->begin() + index;
- firstOverlapping = inserted + 1;
- for (MarkerList::iterator i = firstOverlapping;
- i != list->end() && (*i)->startOffset() <= (*inserted)->endOffset();) {
- (*inserted)->setStartOffset(
- std::min((*inserted)->startOffset(), (*i)->startOffset()));
- (*inserted)->setEndOffset(
- std::max((*inserted)->endOffset(), (*i)->endOffset()));
- list->remove(i - list->begin());
- }
-}
-
// copies markers from srcNode to dstNode, applying the specified shift delta to
// the copies. The shift is useful if, e.g., the caller has created the dstNode
// from a non-prefix substring of the srcNode.
@@ -295,39 +187,11 @@ void DocumentMarkerController::copyMarkers(Node* srcNode,
if (length <= 0)
return;
- if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
- return;
- DCHECK(!m_markers.isEmpty());
-
- MarkerLists* markers = m_markers.at(srcNode);
- if (!markers)
- return;
-
bool docDirty = false;
- for (Member<MarkerList> list : *markers) {
- if (!list)
- continue;
- unsigned endOffset = startOffset + length - 1;
- MarkerList::iterator startPos = std::lower_bound(
- list->begin(), list->end(), startOffset, doesNotInclude);
- for (MarkerList::iterator i = startPos; i != list->end(); ++i) {
- DocumentMarker* marker = i->get();
-
- // stop if we are now past the specified range
- if (marker->startOffset() > endOffset)
- break;
-
- // pin the marker to the specified range and apply the shift delta
- docDirty = true;
- if (marker->startOffset() < startOffset)
- marker->setStartOffset(startOffset);
- if (marker->endOffset() > endOffset)
- marker->setEndOffset(endOffset);
- marker->shiftOffsets(delta);
-
- addMarker(dstNode, *marker);
- }
+ for (Member<DocumentMarkerList> list : getMarkerListsForNode(srcNode)) {
+ docDirty =
+ list->copyMarkers(startOffset, length, dstNode, delta) || docDirty;
}
// repaint the affected node
@@ -347,79 +211,29 @@ void DocumentMarkerController::removeMarkers(
if (length <= 0)
return;
- if (!possiblyHasMarkers(markerTypes))
- return;
- DCHECK(!(m_markers.isEmpty()));
-
- MarkerLists* markers = m_markers.at(node);
- if (!markers)
- return;
-
bool docDirty = false;
- size_t emptyListsCount = 0;
- for (size_t markerListIndex = 0;
- markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
- ++markerListIndex) {
- Member<MarkerList>& list = (*markers)[markerListIndex];
- if (!list || list->isEmpty()) {
- if (list.get() && list->isEmpty())
- list.clear();
- ++emptyListsCount;
- continue;
- }
- if (!markerTypes.contains((*list->begin())->type()))
- continue;
- unsigned endOffset = startOffset + length;
- MarkerList::iterator startPos =
- std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
- for (MarkerList::iterator i = startPos; i != list->end();) {
- DocumentMarker marker(*i->get());
-
- // markers are returned in order, so stop if we are now past the specified
- // range
- if (marker.startOffset() >= endOffset)
- break;
-
- // at this point we know that marker and target intersect in some way
- docDirty = true;
-
- // pitch the old marker
- list->remove(i - list->begin());
-
- if (shouldRemovePartiallyOverlappingMarker) {
- // Stop here. Don't add resulting slices back.
- continue;
- }
+ if (markerTypes.contains(DocumentMarker::Spelling)) {
+ removeMarkersInRangeFromNode(&m_spelling, node, startOffset, length,
+ shouldRemovePartiallyOverlappingMarker,
+ &docDirty);
+ }
- // add either of the resulting slices that are left after removing target
- if (startOffset > marker.startOffset()) {
- DocumentMarker newLeft = marker;
- newLeft.setEndOffset(startOffset);
- size_t insertIndex = i - list->begin();
- list->insert(insertIndex, RenderedDocumentMarker::create(newLeft));
- // Move to the marker after the inserted one.
- i = list->begin() + insertIndex + 1;
- }
- if (marker.endOffset() > endOffset) {
- DocumentMarker newRight = marker;
- newRight.setStartOffset(endOffset);
- size_t insertIndex = i - list->begin();
- list->insert(insertIndex, RenderedDocumentMarker::create(newRight));
- // Move to the marker after the inserted one.
- i = list->begin() + insertIndex + 1;
- }
- }
+ if (markerTypes.contains(DocumentMarker::Grammar)) {
+ removeMarkersInRangeFromNode(&m_grammar, node, startOffset, length,
+ shouldRemovePartiallyOverlappingMarker,
+ &docDirty);
+ }
- if (list->isEmpty()) {
- list.clear();
- ++emptyListsCount;
- }
+ if (markerTypes.contains(DocumentMarker::TextMatch)) {
+ removeMarkersInRangeFromNode(&m_textMatches, node, startOffset, length,
+ shouldRemovePartiallyOverlappingMarker,
+ &docDirty);
}
- if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) {
- m_markers.erase(node);
- if (m_markers.isEmpty())
- m_possiblyExistingMarkerTypes = 0;
+ if (markerTypes.contains(DocumentMarker::Composition)) {
+ removeMarkersInRangeFromNode(&m_compositions, node, startOffset, length,
+ shouldRemovePartiallyOverlappingMarker,
+ &docDirty);
}
// repaint the affected node
@@ -434,20 +248,9 @@ DocumentMarkerVector DocumentMarkerController::markersFor(
DocumentMarker::MarkerTypes markerTypes) {
DocumentMarkerVector result;
- MarkerLists* markers = m_markers.at(node);
- if (!markers)
- return result;
-
- for (size_t markerListIndex = 0;
- markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
- ++markerListIndex) {
- Member<MarkerList>& list = (*markers)[markerListIndex];
- if (!list || list->isEmpty() ||
- !markerTypes.contains((*list->begin())->type()))
- continue;
-
- for (size_t i = 0; i < list->size(); ++i)
- result.push_back(list->at(i).get());
+ for (Member<DocumentMarkerList> list :
+ getMarkerListsForNode(node, markerTypes)) {
+ list->appendMarkersToInputList(&result);
}
std::sort(result.begin(), result.end(), compareByStart);
@@ -456,16 +259,18 @@ DocumentMarkerVector DocumentMarkerController::markersFor(
DocumentMarkerVector DocumentMarkerController::markers() {
DocumentMarkerVector result;
- for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) {
- MarkerLists* markers = i->value.get();
- for (size_t markerListIndex = 0;
- markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
- ++markerListIndex) {
- Member<MarkerList>& list = (*markers)[markerListIndex];
- for (size_t j = 0; list.get() && j < list->size(); ++j)
- result.push_back(list->at(j).get());
- }
- }
+ for (auto it = m_spelling.begin(); it != m_spelling.end(); ++it)
+ it->value->appendMarkersToInputList(&result);
+
+ for (auto it = m_grammar.begin(); it != m_grammar.end(); ++it)
+ it->value->appendMarkersToInputList(&result);
+
+ for (auto it = m_textMatches.begin(); it != m_textMatches.end(); ++it)
+ it->value->appendMarkersToInputList(&result);
+
+ for (auto it = m_compositions.begin(); it != m_compositions.end(); ++it)
+ it->value->appendMarkersToInputList(&result);
+
std::sort(result.begin(), result.end(), compareByStart);
return result;
}
@@ -473,8 +278,6 @@ DocumentMarkerVector DocumentMarkerController::markers() {
DocumentMarkerVector DocumentMarkerController::markersInRange(
const EphemeralRange& range,
DocumentMarker::MarkerTypes markerTypes) {
- if (!possiblyHasMarkers(markerTypes))
- return DocumentMarkerVector();
DocumentMarkerVector foundMarkers;
@@ -502,34 +305,27 @@ DocumentMarkerVector DocumentMarkerController::markersInRange(
}
Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(
- DocumentMarker::MarkerType markerType) {
+ DocumentMarker::MarkerType) {
Xiaocheng 2017/03/21 19:12:11 I think it's better to: 1. Add a comment that thi
Vector<IntRect> result;
- if (!possiblyHasMarkers(markerType))
- return result;
- DCHECK(!(m_markers.isEmpty()));
-
// outer loop: process each node
- MarkerMap::iterator end = m_markers.end();
- for (MarkerMap::iterator nodeIterator = m_markers.begin();
- nodeIterator != end; ++nodeIterator) {
+ for (auto nodeIterator = m_textMatches.begin();
+ nodeIterator != m_textMatches.end(); ++nodeIterator) {
// inner loop; process each marker in this node
const Node& node = *nodeIterator->key;
- MarkerLists* markers = nodeIterator->value.get();
- for (size_t markerListIndex = 0;
- markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
- ++markerListIndex) {
- Member<MarkerList>& list = (*markers)[markerListIndex];
- if (!list || list->isEmpty() || (*list->begin())->type() != markerType)
+ TextMatchMarkerList* list = nodeIterator->value.get();
+#if DCHECK_IS_ON()
+ if (!list->empty()) {
+ DCHECK(!m_document->view() || !m_document->view()->needsLayout());
+ DCHECK(!m_document->needsLayoutTreeUpdate());
+ }
+#endif
+ for (unsigned markerIndex = 0; markerIndex < list->size(); ++markerIndex) {
+ RenderedTextMatchMarker* marker = list->at(markerIndex);
+ marker->updateRenderedRectIfNeeded(node);
+ if (!marker->isRendered())
continue;
- for (unsigned markerIndex = 0; markerIndex < list->size();
- ++markerIndex) {
- RenderedDocumentMarker* marker = list->at(markerIndex).get();
- updateMarkerRenderedRectIfNeeded(node, *marker);
- if (!marker->isRendered())
- continue;
- result.push_back(marker->renderedRect());
- }
+ result.push_back(marker->renderedRect());
}
}
@@ -541,49 +337,30 @@ static void invalidatePaintForTickmarks(const Node& node) {
frameView->invalidatePaintForTickmarks();
}
-void DocumentMarkerController::updateMarkerRenderedRectIfNeeded(
- const Node& node,
- RenderedDocumentMarker& marker) {
- DCHECK(!m_document->view() || !m_document->view()->needsLayout());
- DCHECK(!m_document->needsLayoutTreeUpdate());
- if (!marker.isValid())
- updateMarkerRenderedRect(node, marker);
-}
-
-void DocumentMarkerController::invalidateRectsForMarkersInNode(
- const Node& node) {
- MarkerLists* markers = m_markers.at(&node);
-
- for (auto& markerList : *markers) {
- if (!markerList || markerList->isEmpty())
- continue;
+void DocumentMarkerController::invalidateRectsForMarkersInNode(Node& node) {
Xiaocheng 2017/03/21 19:12:11 Implementation of this function should also be mov
+ if (!m_textMatches.contains(&node))
+ return;
- for (auto& marker : *markerList)
- marker->invalidate();
+ TextMatchMarkerList& markerList = *(m_textMatches.find(&node)->value);
- if (markerList->front()->type() == DocumentMarker::TextMatch)
- invalidatePaintForTickmarks(node);
+ for (Member<DocumentMarker> marker : markerList) {
+ auto renderedTextMatchMarker = toRenderedTextMatchMarkerOrDie(marker.get());
+ renderedTextMatchMarker->invalidate();
}
+
+ invalidatePaintForTickmarks(node);
}
void DocumentMarkerController::invalidateRectsForAllMarkers() {
Xiaocheng 2017/03/21 19:12:11 Ditto.
- for (auto& nodeMarkers : m_markers) {
- const Node& node = *nodeMarkers.key;
- for (auto& markerList : *nodeMarkers.value) {
- if (!markerList || markerList->isEmpty())
- continue;
-
- for (auto& marker : *markerList)
- marker->invalidate();
-
- if (markerList->front()->type() == DocumentMarker::TextMatch)
- invalidatePaintForTickmarks(node);
- }
- }
+ for (auto& nodeMarkers : m_textMatches)
+ invalidateRectsForMarkersInNode(*nodeMarkers.key);
}
DEFINE_TRACE(DocumentMarkerController) {
- visitor->trace(m_markers);
+ visitor->trace(m_spelling);
+ visitor->trace(m_grammar);
+ visitor->trace(m_textMatches);
+ visitor->trace(m_compositions);
visitor->trace(m_document);
SynchronousMutationObserver::trace(visitor);
}
@@ -591,150 +368,80 @@ DEFINE_TRACE(DocumentMarkerController) {
void DocumentMarkerController::removeMarkers(
Node* node,
DocumentMarker::MarkerTypes markerTypes) {
- if (!possiblyHasMarkers(markerTypes))
- return;
- DCHECK(!m_markers.isEmpty());
+ if (markerTypes.contains(DocumentMarker::Spelling))
+ m_spelling.remove(node);
- MarkerMap::iterator iterator = m_markers.find(node);
- if (iterator != m_markers.end())
- removeMarkersFromList(iterator, markerTypes);
+ if (markerTypes.contains(DocumentMarker::Grammar))
+ m_grammar.remove(node);
+
+ if (markerTypes.contains(DocumentMarker::TextMatch))
+ m_textMatches.remove(node);
+
+ if (markerTypes.contains(DocumentMarker::Composition))
+ m_compositions.remove(node);
+}
+
+void DocumentMarkerController::removeMarkers(
+ DocumentMarker::MarkerTypes markerTypes) {
+ if (markerTypes.contains(DocumentMarker::Spelling))
+ m_spelling.clear();
+
+ if (markerTypes.contains(DocumentMarker::Grammar))
+ m_grammar.clear();
+
+ if (markerTypes.contains(DocumentMarker::TextMatch))
+ m_textMatches.clear();
+
+ if (markerTypes.contains(DocumentMarker::Composition))
+ m_compositions.clear();
}
void DocumentMarkerController::removeMarkers(
const MarkerRemoverPredicate& shouldRemoveMarker) {
- for (auto& nodeMarkers : m_markers) {
+ for (auto& nodeMarkers : m_spelling) {
const Node& node = *nodeMarkers.key;
- if (!node.isTextNode()) // MarkerRemoverPredicate requires a Text node.
+ if (!node.isTextNode())
continue;
- MarkerLists& markers = *nodeMarkers.value;
- for (size_t markerListIndex = 0;
- markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
- ++markerListIndex) {
- Member<MarkerList>& list = markers[markerListIndex];
- if (!list)
- continue;
- bool removedMarkers = false;
- for (size_t j = list->size(); j > 0; --j) {
- if (shouldRemoveMarker(*list->at(j - 1),
- static_cast<const Text&>(node))) {
- list->remove(j - 1);
- removedMarkers = true;
- }
- }
- if (removedMarkers &&
- markerListIndex == DocumentMarker::TextMatchMarkerIndex)
- invalidatePaintForTickmarks(node);
- }
+ nodeMarkers.value->removeMarkersForWords(static_cast<const Text&>(node),
+ shouldRemoveMarker.m_words);
}
}
-void DocumentMarkerController::removeMarkers(
+void DocumentMarkerController::repaintMarkers(
DocumentMarker::MarkerTypes markerTypes) {
- if (!possiblyHasMarkers(markerTypes))
- return;
- DCHECK(!m_markers.isEmpty());
-
- HeapVector<Member<const Node>> nodesWithMarkers;
- copyKeysToVector(m_markers, nodesWithMarkers);
- unsigned size = nodesWithMarkers.size();
- for (unsigned i = 0; i < size; ++i) {
- MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]);
- if (iterator != m_markers.end())
- removeMarkersFromList(iterator, markerTypes);
+ HeapHashSet<Member<Node>> nodesToRepaint;
+ for (auto& nodeMarkers : m_spelling) {
+ if (!nodeMarkers.value->empty())
+ nodesToRepaint.insert(nodeMarkers.key.get());
}
- m_possiblyExistingMarkerTypes.remove(markerTypes);
-}
-
-void DocumentMarkerController::removeMarkersFromList(
- MarkerMap::iterator iterator,
- DocumentMarker::MarkerTypes markerTypes) {
- bool needsRepainting = false;
- bool nodeCanBeRemoved;
-
- size_t emptyListsCount = 0;
- if (markerTypes == DocumentMarker::AllMarkers()) {
- needsRepainting = true;
- nodeCanBeRemoved = true;
- } else {
- MarkerLists* markers = iterator->value.get();
-
- for (size_t markerListIndex = 0;
- markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
- ++markerListIndex) {
- Member<MarkerList>& list = (*markers)[markerListIndex];
- if (!list || list->isEmpty()) {
- if (list.get() && list->isEmpty())
- list.clear();
- ++emptyListsCount;
- continue;
- }
- if (markerTypes.contains((*list->begin())->type())) {
- list->clear();
- list.clear();
- ++emptyListsCount;
- needsRepainting = true;
- }
- }
-
- nodeCanBeRemoved =
- emptyListsCount == DocumentMarker::MarkerTypeIndexesCount;
+ for (auto& nodeMarkers : m_grammar) {
+ if (!nodeMarkers.value->empty())
+ nodesToRepaint.insert(nodeMarkers.key.get());
}
- if (needsRepainting) {
- const Node& node = *iterator->key;
- if (LayoutObject* layoutObject = node.layoutObject()) {
- layoutObject->setShouldDoFullPaintInvalidation(
- PaintInvalidationDocumentMarkerChange);
- }
- invalidatePaintForTickmarks(node);
+ for (auto& nodeMarkers : m_textMatches) {
+ if (!nodeMarkers.value->empty())
+ nodesToRepaint.insert(nodeMarkers.key.get());
}
- if (nodeCanBeRemoved) {
- m_markers.remove(iterator);
- if (m_markers.isEmpty())
- m_possiblyExistingMarkerTypes = 0;
+ for (auto& nodeMarkers : m_compositions) {
+ if (!nodeMarkers.value->empty())
+ nodesToRepaint.insert(nodeMarkers.key.get());
}
-}
-void DocumentMarkerController::repaintMarkers(
- DocumentMarker::MarkerTypes markerTypes) {
- if (!possiblyHasMarkers(markerTypes))
- return;
- DCHECK(!m_markers.isEmpty());
-
- // outer loop: process each markered node in the document
- MarkerMap::iterator end = m_markers.end();
- for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
- const Node* node = i->key;
-
- // inner loop: process each marker in the current node
- MarkerLists* markers = i->value.get();
- for (size_t markerListIndex = 0;
- markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
- ++markerListIndex) {
- Member<MarkerList>& list = (*markers)[markerListIndex];
- if (!list || list->isEmpty() ||
- !markerTypes.contains((*list->begin())->type()))
- continue;
-
- // cause the node to be redrawn
- if (LayoutObject* layoutObject = node->layoutObject()) {
- layoutObject->setShouldDoFullPaintInvalidation(
- PaintInvalidationDocumentMarkerChange);
- break;
- }
+ for (Member<Node> node : nodesToRepaint) {
+ // cause the node to be redrawn
+ if (LayoutObject* layoutObject = node->layoutObject()) {
+ layoutObject->setShouldDoFullPaintInvalidation(
+ PaintInvalidationDocumentMarkerChange);
+ break;
}
}
}
bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
bool active) {
- if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
- return false;
-
- DCHECK(!m_markers.isEmpty());
-
Node* const startContainer = range.startPosition().computeContainerNode();
DCHECK(startContainer);
Node* const endContainer = range.endPosition().computeContainerNode();
@@ -754,147 +461,177 @@ bool DocumentMarkerController::setMarkersActive(const EphemeralRange& range,
return markerFound;
}
+bool DocumentMarkerController::hasMarkers(Node* node) const {
+ return m_spelling.contains(node) || m_grammar.contains(node) ||
+ m_textMatches.contains(node) || m_compositions.contains(node);
+}
+
bool DocumentMarkerController::setMarkersActive(Node* node,
unsigned startOffset,
unsigned endOffset,
bool active) {
- MarkerLists* markers = m_markers.at(node);
- if (!markers)
- return false;
-
bool docDirty = false;
- Member<MarkerList>& list =
- (*markers)[MarkerTypeToMarkerIndex(DocumentMarker::TextMatch)];
- if (!list)
- return false;
- MarkerList::iterator startPos =
- std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
- for (MarkerList::iterator marker = startPos; marker != list->end();
- ++marker) {
- // Markers are returned in order, so stop if we are now past the specified
- // range.
- if ((*marker)->startOffset() >= endOffset)
- break;
-
- (*marker)->setActiveMatch(active);
- docDirty = true;
+ if (m_textMatches.contains(node)) {
+ docDirty = m_textMatches.at(node)->setTextMatchMarkersActive(
+ startOffset, endOffset, active);
}
- // repaint the affected node
- if (docDirty && node->layoutObject()) {
+ if (docDirty && node->layoutObject())
node->layoutObject()->setShouldDoFullPaintInvalidation(
PaintInvalidationDocumentMarkerChange);
- }
+
return docDirty;
}
#ifndef NDEBUG
+static String showMarkerHelper(const DocumentMarkerVector& markers) {
+ StringBuilder builder;
+
+ for (const Member<DocumentMarker> marker : markers) {
+ builder.append(" ");
+ builder.appendNumber(marker->type());
+ builder.append(":[");
+ builder.appendNumber(marker->startOffset());
+ builder.append(":");
+ builder.appendNumber(marker->endOffset());
+ builder.append("](");
+ builder.appendNumber(marker->activeMatch());
+ builder.append(")");
+ }
+
+ return builder.toString();
+}
+
void DocumentMarkerController::showMarkers() const {
StringBuilder builder;
- MarkerMap::const_iterator end = m_markers.end();
- for (MarkerMap::const_iterator nodeIterator = m_markers.begin();
- nodeIterator != end; ++nodeIterator) {
- const Node* node = nodeIterator->key;
+
+ HeapHashSet<Member<Node>> nodes;
+ for (const auto& nodeMarkers : m_spelling)
+ nodes.insert(nodeMarkers.key);
+ for (const auto& nodeMarkers : m_grammar)
+ nodes.insert(nodeMarkers.key);
+ for (const auto& nodeMarkers : m_textMatches)
+ nodes.insert(nodeMarkers.key);
+ for (const auto& nodeMarkers : m_compositions)
+ nodes.insert(nodeMarkers.key);
+
+ HeapHashSet<Member<const Node>> nodesWithMarkers;
+ for (Node* node : nodes) {
builder.append(String::format("%p", node));
- MarkerLists* markers = m_markers.at(node);
- for (size_t markerListIndex = 0;
- markerListIndex < DocumentMarker::MarkerTypeIndexesCount;
- ++markerListIndex) {
- Member<MarkerList>& list = (*markers)[markerListIndex];
- for (unsigned markerIndex = 0; list.get() && markerIndex < list->size();
- ++markerIndex) {
- DocumentMarker* marker = list->at(markerIndex).get();
- builder.append(" ");
- builder.appendNumber(marker->type());
- builder.append(":[");
- builder.appendNumber(marker->startOffset());
- builder.append(":");
- builder.appendNumber(marker->endOffset());
- builder.append("](");
- builder.appendNumber(marker->activeMatch());
- builder.append(")");
+
+ if (m_spelling.contains(node)) {
+ DocumentMarkerVector markers;
+ m_spelling.at(node)->appendMarkersToInputList(&markers);
+ if (!markers.isEmpty()) {
+ builder.append(showMarkerHelper(markers));
+ nodesWithMarkers.insert(node);
+ }
+ }
+
+ if (m_grammar.contains(node)) {
+ DocumentMarkerVector markers;
+ m_grammar.at(node)->appendMarkersToInputList(&markers);
+ if (!markers.isEmpty()) {
+ builder.append(showMarkerHelper(markers));
+ nodesWithMarkers.insert(node);
+ }
+ }
+
+ if (m_textMatches.contains(node)) {
+ DocumentMarkerVector markers;
+ m_textMatches.at(node)->appendMarkersToInputList(&markers);
+ if (!markers.isEmpty()) {
+ builder.append(showMarkerHelper(markers));
+ nodesWithMarkers.insert(node);
}
}
+
+ if (m_compositions.contains(node)) {
+ DocumentMarkerVector markers;
+ m_compositions.at(node)->appendMarkersToInputList(&markers);
+ if (!markers.isEmpty()) {
+ builder.append(showMarkerHelper(markers));
+ nodesWithMarkers.insert(node);
+ }
+ }
+
builder.append("\n");
}
- LOG(INFO) << m_markers.size() << " nodes have markers:\n"
+ LOG(INFO) << nodesWithMarkers.size() << " nodes have markers:\n"
<< builder.toString().utf8().data();
}
#endif
-// SynchronousMutationObserver
-void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
- unsigned offset,
- unsigned oldLength,
- unsigned newLength) {
- // If we're doing a pure remove operation, remove the markers in the range
- // being removed (markers containing, but larger than, the range, will be
- // split)
- if (newLength == 0)
- removeMarkers(node, offset, oldLength);
+HeapVector<Member<DocumentMarkerList>>
+DocumentMarkerController::getMarkerListsForNode(
+ Node* node,
+ DocumentMarker::MarkerTypes markerTypes) {
+ HeapVector<Member<DocumentMarkerList>> markerLists;
- if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
- return;
- DCHECK(!m_markers.isEmpty());
+ if (markerTypes.contains(DocumentMarker::Spelling)) {
+ auto spellingIt = m_spelling.find(node);
+ if (spellingIt != m_spelling.end())
+ markerLists.push_back(spellingIt->value);
+ }
- MarkerLists* markers = m_markers.at(node);
- if (!markers)
- return;
+ if (markerTypes.contains(DocumentMarker::Grammar)) {
+ auto grammarIt = m_grammar.find(node);
+ if (grammarIt != m_grammar.end())
+ markerLists.push_back(grammarIt->value);
+ }
- bool didShiftMarker = false;
- for (MarkerList* list : *markers) {
- if (!list)
- continue;
+ if (markerTypes.contains(DocumentMarker::TextMatch)) {
+ auto textMatchesIt = m_textMatches.find(node);
+ if (textMatchesIt != m_textMatches.end())
+ markerLists.push_back(textMatchesIt->value);
+ }
- for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) {
- RenderedDocumentMarker& marker = **it;
- // algorithm inspired by https://dom.spec.whatwg.org/#concept-cd-replace
- // but with some changes
- if (marker.startOffset() > offset) {
- // Deviation from the concept-cd-replace algorithm: < instead of <= in
- // the next line
- if (marker.startOffset() < offset + oldLength) {
- // Marker start was in the replaced text. Move to end of new text
- // (Deviation from the concept-cd-replace algorithm: that algorithm
- // would move to the beginning of the new text here)
- marker.setStartOffset(offset + newLength);
- } else {
- // Marker start was after the replaced text. Shift by length
- // difference
- unsigned oldStartOffset = marker.startOffset();
- marker.setStartOffset(oldStartOffset + newLength - oldLength);
- }
- didShiftMarker = true;
- }
+ if (markerTypes.contains(DocumentMarker::Composition)) {
+ auto compositionsIt = m_compositions.find(node);
+ if (compositionsIt != m_compositions.end())
+ markerLists.push_back(compositionsIt->value);
+ }
- if (marker.endOffset() > offset) {
- // Deviation from the concept-cd-replace algorithm: < instead of <= in
- // the next line
- if (marker.endOffset() < offset + oldLength) {
- // Marker end was in the replaced text. Move to beginning of new text
- marker.setEndOffset(offset);
- } else {
- // Marker end was after the replaced text. Shift by length difference
- unsigned oldEndOffset = marker.endOffset();
- marker.setEndOffset(oldEndOffset + newLength - oldLength);
- }
- didShiftMarker = true;
- }
+ return markerLists;
+}
- if (marker.startOffset() < marker.endOffset())
- continue;
- list->remove(it - list->begin());
- --it;
- }
+void DocumentMarkerController::removeMarkers(
+ TextIterator& markedText,
+ DocumentMarker::MarkerTypes markerTypes,
+ RemovePartiallyOverlappingMarkerOrNot
+ shouldRemovePartiallyOverlappingMarker) {
+ for (; !markedText.atEnd(); markedText.advance()) {
+ int startOffset = markedText.startOffsetInCurrentContainer();
+ int endOffset = markedText.endOffsetInCurrentContainer();
+ removeMarkers(markedText.currentContainer(), startOffset,
+ endOffset - startOffset, markerTypes,
+ shouldRemovePartiallyOverlappingMarker);
}
+}
- if (!didShiftMarker)
- return;
- if (!node->layoutObject())
- return;
- invalidateRectsForMarkersInNode(*node);
- // repaint the affected node
- node->layoutObject()->setShouldDoFullPaintInvalidation();
+// SynchronousMutationObserver
+void DocumentMarkerController::didUpdateCharacterData(CharacterData* node,
+ unsigned offset,
+ unsigned oldLength,
+ unsigned newLength) {
+ bool didShiftMarker = false;
+ shiftMarkersInNode(&m_spelling, node, offset, oldLength, newLength,
+ &didShiftMarker);
+ shiftMarkersInNode(&m_grammar, node, offset, oldLength, newLength,
+ &didShiftMarker);
+ shiftMarkersInNode(&m_textMatches, node, offset, oldLength, newLength,
+ &didShiftMarker);
+ shiftMarkersInNode(&m_compositions, node, offset, oldLength, newLength,
+ &didShiftMarker);
+
+ if (didShiftMarker) {
+ invalidateRectsForMarkersInNode(*node);
+ // repaint the affected node
+ if (node->layoutObject()) {
+ node->layoutObject()->setShouldDoFullPaintInvalidation(
+ PaintInvalidationDocumentMarkerChange);
+ }
+ }
}
} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698