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 2a23e42732c35eea6bfa9e9388161fd933e740c6..a3bb48474967a6c8585d2371925405563c9d4c98 100644 |
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp |
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp |
@@ -71,6 +71,10 @@ DocumentMarker::MarkerTypeIndex MarkerTypeToMarkerIndex( |
return DocumentMarker::InvisibleSpellcheckMarkerIndex; |
case DocumentMarker::Composition: |
return DocumentMarker::CompositionMarkerIndex; |
+ case DocumentMarker::Suggestion: |
+ return DocumentMarker::SuggestionMarkerIndex; |
+ case DocumentMarker::SuggestionBackgroundHighlight: |
+ return DocumentMarker::SuggestionBackgroundHighlightMarkerIndex; |
} |
NOTREACHED(); |
@@ -85,11 +89,14 @@ inline bool DocumentMarkerController::possiblyHasMarkers( |
} |
DocumentMarkerController::DocumentMarkerController(const Document& document) |
- : m_possiblyExistingMarkerTypes(0), m_document(&document) {} |
+ : m_possiblyExistingMarkerTypes(0), |
+ m_document(&document), |
+ m_nextSuggestionMarkerID(0) {} |
void DocumentMarkerController::clear() { |
m_markers.clear(); |
m_possiblyExistingMarkerTypes = 0; |
+ m_nextSuggestionMarkerID = 0; |
} |
void DocumentMarkerController::addMarker(const Position& start, |
@@ -124,19 +131,40 @@ void DocumentMarkerController::addTextMatchMarker(const EphemeralRange& range, |
// throttling algorithm. crbug.com/6819. |
} |
-void DocumentMarkerController::addCompositionMarker(const Position& start, |
- const Position& end, |
- Color underlineColor, |
- bool thick, |
- Color backgroundColor) { |
+void DocumentMarkerController::addCompositionMarker( |
+ const Position& start, |
+ const Position& end, |
+ Color underlineColor, |
+ bool thick, |
+ Color backgroundColor, |
+ const std::vector<std::string>& suggestions) { |
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, |
+ suggestions, m_nextSuggestionMarkerID++)); |
+ } |
+} |
+ |
+void DocumentMarkerController::addSuggestionBackgroundHighlightMarker( |
+ const Position& start, |
+ const Position& end, |
+ Color underlineColor, |
+ bool thick, |
+ Color backgroundColor) { |
+ DCHECK(!m_document->needsLayoutTreeUpdate()); |
+ |
+ for (TextIterator markedText(start, end); !markedText.atEnd(); |
+ markedText.advance()) { |
+ addMarker(markedText.currentContainer(), |
+ DocumentMarker(DocumentMarker::SuggestionBackgroundHighlight, |
+ markedText.startOffsetInCurrentContainer(), |
+ markedText.endOffsetInCurrentContainer(), |
underlineColor, thick, backgroundColor)); |
+ } |
} |
void DocumentMarkerController::prepareForDestruction() { |
@@ -159,6 +187,7 @@ void DocumentMarkerController::removeMarkers( |
endOffset - startOffset, markerTypes, |
shouldRemovePartiallyOverlappingMarker); |
} |
+ showMarkers(); |
} |
void DocumentMarkerController::removeMarkers( |
@@ -171,6 +200,7 @@ void DocumentMarkerController::removeMarkers( |
TextIterator markedText(range.startPosition(), range.endPosition()); |
DocumentMarkerController::removeMarkers( |
markedText, markerTypes, shouldRemovePartiallyOverlappingMarker); |
+ showMarkers(); |
} |
static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, |
@@ -178,11 +208,6 @@ static bool startsFurther(const Member<RenderedDocumentMarker>& lhv, |
return lhv->startOffset() < rhv->startOffset(); |
} |
-static bool startsAfter(const Member<RenderedDocumentMarker>& marker, |
- size_t startOffset) { |
- return marker->startOffset() < startOffset; |
-} |
- |
static bool endsBefore(size_t startOffset, |
const Member<RenderedDocumentMarker>& rhv) { |
return startOffset < rhv->endOffset(); |
@@ -255,7 +280,8 @@ void DocumentMarkerController::addMarker(Node* node, |
list->push_back(newRenderedMarker); |
} else { |
if (newMarker.type() != DocumentMarker::TextMatch && |
- newMarker.type() != DocumentMarker::Composition) { |
+ newMarker.type() != DocumentMarker::Composition && |
+ newMarker.type() != DocumentMarker::Suggestion) { |
mergeOverlapping(list.get(), newRenderedMarker); |
} else { |
MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(), |
@@ -354,6 +380,7 @@ void DocumentMarkerController::removeMarkers( |
if (!possiblyHasMarkers(markerTypes)) |
return; |
+ |
DCHECK(!(m_markers.isEmpty())); |
MarkerLists* markers = m_markers.get(node); |
@@ -430,6 +457,8 @@ void DocumentMarkerController::removeMarkers( |
// repaint the affected node |
if (docDirty && node->layoutObject()) |
node->layoutObject()->setShouldDoFullPaintInvalidation(); |
+ |
+ showMarkers(); |
} |
DocumentMarkerVector DocumentMarkerController::markersFor( |
@@ -482,22 +511,38 @@ DocumentMarkerVector DocumentMarkerController::markersInRange( |
DocumentMarkerVector foundMarkers; |
Node* startContainer = range.startPosition().computeContainerNode(); |
- DCHECK(startContainer); |
+ if (!startContainer) |
+ return DocumentMarkerVector(); |
+ |
unsigned startOffset = static_cast<unsigned>( |
range.startPosition().computeOffsetInContainerNode()); |
+ |
Node* endContainer = range.endPosition().computeContainerNode(); |
- DCHECK(endContainer); |
+ if (!endContainer) |
+ return DocumentMarkerVector(); |
+ |
unsigned endOffset = |
static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode()); |
+ // For zero-length ranges, include spans whose endpoints touch the range |
aelias_OOO_until_Jul13
2017/01/25 03:34:27
That's not very principled. I'd prefer you introd
rlanday
2017/01/25 18:48:10
That's a good idea; I got the idea to do it the wa
|
+ // location |
+ bool isZeroLengthRange = |
+ (startContainer == endContainer) && (startOffset == endOffset); |
+ |
for (Node& node : range.nodes()) { |
for (DocumentMarker* marker : markersFor(&node)) { |
if (!markerTypes.contains(marker->type())) |
continue; |
- if (node == startContainer && marker->endOffset() <= startOffset) |
- continue; |
- if (node == endContainer && marker->startOffset() >= endOffset) |
- continue; |
+ if (node == startContainer) { |
+ if (marker->endOffset() < startOffset || |
+ (marker->endOffset() == startOffset && !isZeroLengthRange)) |
+ continue; |
+ } |
+ if (node == endContainer) { |
+ if (marker->startOffset() > endOffset || |
+ (marker->startOffset() == endOffset && !isZeroLengthRange)) |
+ continue; |
+ } |
foundMarkers.push_back(marker); |
} |
} |
@@ -600,6 +645,8 @@ void DocumentMarkerController::removeMarkers( |
MarkerMap::iterator iterator = m_markers.find(node); |
if (iterator != m_markers.end()) |
removeMarkersFromList(iterator, markerTypes); |
+ |
+ showMarkers(); |
} |
void DocumentMarkerController::removeMarkers( |
@@ -628,6 +675,8 @@ void DocumentMarkerController::removeMarkers( |
invalidatePaintForTickmarks(node); |
} |
} |
+ |
+ showMarkers(); |
} |
void DocumentMarkerController::removeMarkers( |
@@ -646,6 +695,27 @@ void DocumentMarkerController::removeMarkers( |
} |
m_possiblyExistingMarkerTypes.remove(markerTypes); |
+ |
+ showMarkers(); |
+} |
+ |
+void DocumentMarkerController::removeSuggestionMarkersByID( |
+ const Vector<int>& idsToRemove) { |
+ for (auto& nodeMarkers : m_markers) { |
+ MarkerLists& markers = *nodeMarkers.value; |
+ Member<MarkerList>& suggestionMarkerList = |
+ markers[DocumentMarker::SuggestionMarkerIndex]; |
+ if (!suggestionMarkerList) |
+ continue; |
+ bool removedMarkers = false; |
+ for (size_t j = suggestionMarkerList->size(); j > 0; --j) { |
+ if (idsToRemove.contains( |
+ suggestionMarkerList->at(j - 1)->suggestionMarkerID())) { |
+ suggestionMarkerList->remove(j - 1); |
+ removedMarkers = true; |
+ } |
+ } |
+ } |
} |
void DocumentMarkerController::removeMarkersFromList( |
@@ -695,6 +765,8 @@ void DocumentMarkerController::removeMarkersFromList( |
if (m_markers.isEmpty()) |
m_possiblyExistingMarkerTypes = 0; |
} |
+ |
+ showMarkers(); |
} |
void DocumentMarkerController::repaintMarkers( |
@@ -728,8 +800,13 @@ void DocumentMarkerController::repaintMarkers( |
} |
void DocumentMarkerController::shiftMarkers(Node* node, |
- unsigned startOffset, |
- int delta) { |
+ int startOffset, |
+ int prevLength, |
+ int newLength) { |
+ DCHECK_GE(startOffset, 0); |
+ DCHECK_GE(prevLength, 0); |
+ DCHECK_GE(newLength, 0); |
+ |
if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) |
return; |
DCHECK(!m_markers.isEmpty()); |
@@ -745,15 +822,34 @@ void DocumentMarkerController::shiftMarkers(Node* node, |
Member<MarkerList>& list = (*markers)[markerListIndex]; |
if (!list) |
continue; |
- MarkerList::iterator startPos = |
- std::lower_bound(list->begin(), list->end(), startOffset, startsAfter); |
- for (MarkerList::iterator marker = startPos; marker != list->end(); |
+ |
+ // algorithm from https://dom.spec.whatwg.org/#concept-cd-replace |
+ for (MarkerList::iterator marker = list->begin(); marker != list->end(); |
++marker) { |
-#if DCHECK_IS_ON() |
- int startOffset = (*marker)->startOffset(); |
- DCHECK_GE(startOffset + delta, 0); |
-#endif |
- (*marker)->shiftOffsets(delta); |
+ if ((*marker)->startOffset() > (unsigned)startOffset) { |
+ if ((*marker)->startOffset() <= (unsigned)(startOffset + prevLength)) { |
+ // Marker start was in the replaced text. Move to beginning of new |
+ // text |
+ (*marker)->setStartOffset(startOffset); |
+ } else { |
+ // Marker start was after the replaced text. Shift by length |
+ // difference |
+ unsigned oldStartOffset = (*marker)->startOffset(); |
+ (*marker)->setStartOffset(oldStartOffset + newLength - prevLength); |
+ } |
+ } |
+ |
+ if ((*marker)->endOffset() > (unsigned)startOffset) { |
+ if ((*marker)->endOffset() <= (unsigned)(startOffset + prevLength)) { |
+ // Marker end was in the replaced text. Move to beginning of new text |
+ (*marker)->setEndOffset(startOffset); |
+ } else { |
+ // Marker end was after the replaced text. Shift by length difference |
+ unsigned oldEndOffset = (*marker)->endOffset(); |
+ (*marker)->setEndOffset(oldEndOffset + newLength - prevLength); |
+ } |
+ } |
+ |
didShiftMarker = true; |
} |
} |