Index: third_party/WebKit/Source/core/editing/FrameSelection.cpp |
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp |
index 10a702562f5f21f4b2e96cf80b2d4582bd1f1942..a30f178610c8eede18e70b4fa4cfe6f76ee7b721 100644 |
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp |
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp |
@@ -110,16 +110,17 @@ const DisplayItemClient& FrameSelection::caretDisplayItemClientForTesting() |
return m_frameCaret->displayItemClient(); |
} |
-const Document& FrameSelection::document() const { |
+Document& FrameSelection::document() const { |
DCHECK(lifecycleContext()); |
return *lifecycleContext(); |
} |
-Document& FrameSelection::document() { |
- DCHECK(lifecycleContext()); |
- return *lifecycleContext(); |
+bool FrameSelection::isHandleVisible() const { |
+ return selectionInDOMTree().isHandleVisible(); |
} |
+// TODO(yosin): We should replace |visibleSelection<EditingStrategy>()| to |
+// |computeVisibleSelectionInDOMTree()|. |
// TODO(yosin): To avoid undefined symbols in clang, we explicitly |
// have specialized version of |FrameSelection::visibleSelection<Strategy>| |
// before |FrameSelection::selection()| which refers this. |
@@ -129,12 +130,29 @@ const VisibleSelection& FrameSelection::visibleSelection<EditingStrategy>() |
return m_selectionEditor->visibleSelection<EditingStrategy>(); |
} |
+// TODO(yosin): We should replace |
+// |visibleSelection<EditingInFlatTreeStrategy>()| with |
+// |computeVisibleSelectionInFlatTree()|. |
template <> |
const VisibleSelectionInFlatTree& |
FrameSelection::visibleSelection<EditingInFlatTreeStrategy>() const { |
return m_selectionEditor->visibleSelection<EditingInFlatTreeStrategy>(); |
} |
+const VisibleSelection& FrameSelection::computeVisibleSelectionInDOMTree() |
+ const { |
+ return m_selectionEditor->computeVisibleSelectionInDOMTree(); |
+} |
+ |
+const VisibleSelectionInFlatTree& |
+FrameSelection::computeVisibleSelectionInFlatTree() const { |
+ return m_selectionEditor->computeVisibleSelectionInFlatTree(); |
+} |
+ |
+const SelectionInDOMTree& FrameSelection::selectionInDOMTree() const { |
+ return m_selectionEditor->selectionInDOMTree(); |
+} |
+ |
Element* FrameSelection::rootEditableElementOrDocumentElement() const { |
Element* selectionRoot = selection().rootEditableElement(); |
return selectionRoot ? selectionRoot : document().documentElement(); |
@@ -149,8 +167,13 @@ ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const { |
return node ? &node->treeScope().rootNode() : 0; |
} |
+// TODO(yosin): We should rename |FrameSelection::selection()| to |
+// |selectionDeprecated()|. |
const VisibleSelection& FrameSelection::selection() const { |
- return visibleSelection<EditingStrategy>(); |
+ // TODO(yosin): We should hoist updateStyleAndLayoutIgnorePendingStylesheets |
+ // to caller. See http://crbug.com/590369 for more details. |
+ document().updateStyleAndLayoutIgnorePendingStylesheets(); |
+ return computeVisibleSelectionInDOMTree(); |
} |
const VisibleSelectionInFlatTree& FrameSelection::selectionInFlatTree() const { |
@@ -174,29 +197,22 @@ void FrameSelection::moveCaretSelection(const IntPoint& point) { |
setSelection(builder.build(), CloseTyping | ClearTypingStyle | UserTriggered); |
} |
-template <typename Strategy> |
-void FrameSelection::setSelectionAlgorithm( |
- const VisibleSelectionTemplate<Strategy>& newSelection, |
- HandleVisibility handleVisibility, |
- SetSelectionOptions options, |
- CursorAlignOnScroll align, |
- TextGranularity granularity) { |
+void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection, |
+ SetSelectionOptions options, |
+ CursorAlignOnScroll align, |
+ TextGranularity granularity) { |
DCHECK(isAvailable()); |
- DCHECK(newSelection.isValidFor(document())); |
- const Document& currentDocument = document(); |
+ passedSelection.assertValidFor(document()); |
+ |
+ SelectionInDOMTree::Builder builder(passedSelection); |
+ if (shouldAlwaysUseDirectionalSelection(m_frame)) |
+ builder.setIsDirectional(true); |
+ SelectionInDOMTree newSelection = builder.build(); |
if (m_granularityStrategy && |
(options & FrameSelection::DoNotClearStrategy) == 0) |
m_granularityStrategy->Clear(); |
bool closeTyping = options & CloseTyping; |
bool shouldClearTypingStyle = options & ClearTypingStyle; |
- EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); |
- |
- // TODO(editing-dev): We should rename variable |s| to another name to avoid |
- // using one letter variable name. |
- VisibleSelectionTemplate<Strategy> s = newSelection; |
- if (shouldAlwaysUseDirectionalSelection(m_frame)) |
- s.setIsDirectional(true); |
- |
m_granularity = granularity; |
// TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
@@ -207,23 +223,28 @@ void FrameSelection::setSelectionAlgorithm( |
if (shouldClearTypingStyle) |
m_frame->editor().clearTypingStyle(); |
- if (m_selectionEditor->visibleSelection<Strategy>() == s && |
- m_handleVisibility == handleVisibility) { |
- // Even if selection was not changed, selection offsets may have been |
- // changed. |
- notifyLayoutObjectOfSelectionChange(userTriggered); |
+ const SelectionInDOMTree oldSelectionInDOMTree = |
+ m_selectionEditor->selectionInDOMTree(); |
+ if (oldSelectionInDOMTree == newSelection) |
return; |
- } |
- |
- const VisibleSelectionTemplate<Strategy> oldSelection = |
- visibleSelection<Strategy>(); |
- const Position& oldSelectionStart = selection().start(); |
- |
- m_handleVisibility = handleVisibility; |
- m_selectionEditor->setVisibleSelection(s, options); |
+ m_selectionEditor->setSelection(newSelection); |
scheduleVisualUpdateForPaintInvalidationIfNeeded(); |
- if (!s.isNone() && !(options & DoNotSetFocus)) { |
+ // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets |
+ // needs to be audited. see http://crbug.com/590369 for more details. |
+ document().updateStyleAndLayoutIgnorePendingStylesheets(); |
+ |
+ const Document& currentDocument = document(); |
+ // TODO(yosin): We should get rid of unsued |options| for |
+ // |Editor::respondToChangedSelection()|. |
+ // Note: Since, setting focus can modify DOM tree, we should use |
+ // |oldSelection| before setting focus |
+ m_frame->editor().respondToChangedSelection( |
+ createVisibleSelection(oldSelectionInDOMTree).start(), options); |
+ DCHECK_EQ(currentDocument, document()); |
+ |
+ if (!computeVisibleSelectionInDOMTree().isNone() && |
+ !(options & DoNotSetFocus)) { |
setFocusedNodeIfNeeded(); |
// |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and |
// "FocusIn", |m_frame| may associate to another document. |
@@ -243,6 +264,7 @@ void FrameSelection::setSelectionAlgorithm( |
// Always clear the x position used for vertical arrow navigation. |
// It will be restored by the vertical arrow navigation code if necessary. |
m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); |
+ // TODO(yosin): Can we move this to at end of this function? |
// This may dispatch a synchronous focus-related events. |
selectFrameElementInParentIfFullySelected(); |
if (!isAvailable() || document() != currentDocument) { |
@@ -251,16 +273,8 @@ void FrameSelection::setSelectionAlgorithm( |
// reach here. |
return; |
} |
+ EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); |
notifyLayoutObjectOfSelectionChange(userTriggered); |
- // If the selections are same in the DOM tree but not in the flat tree, |
- // don't fire events. For example, if the selection crosses shadow tree |
- // boundary, selection for the DOM tree is shrunk while that for the |
- // flat tree is not. Additionally, this case occurs in some edge cases. |
- // See also: editing/pasteboard/4076267-3.html |
- if (oldSelection == m_selectionEditor->visibleSelection<Strategy>()) |
- return; |
- |
- m_frame->editor().respondToChangedSelection(oldSelectionStart, options); |
if (userTriggered == UserTriggered) { |
ScrollAlignment alignment; |
@@ -273,6 +287,11 @@ void FrameSelection::setSelectionAlgorithm( |
? ScrollAlignment::alignTopAlways |
: ScrollAlignment::alignToEdgeIfNeeded; |
+ // TODO(editing-dev): The use of |
+ // updateStyleAndLayoutIgnorePendingStylesheets |
+ // needs to be audited. See http://crbug.com/590369 for more details. |
+ document().updateStyleAndLayoutIgnorePendingStylesheets(); |
+ |
revealSelection(alignment, RevealExtent); |
} |
@@ -283,44 +302,20 @@ void FrameSelection::setSelectionAlgorithm( |
Event::create(EventTypeNames::selectionchange)); |
} |
-// TODO(yosin): We will make |selectionInDOMTree| version of |SetSelection()| |
-// as primary function instead of wrapper. |
-void FrameSelection::setSelection(const SelectionInDOMTree& newSelection, |
- SetSelectionOptions options, |
- CursorAlignOnScroll align, |
- TextGranularity granularity) { |
- if (!newSelection.isNone()) { |
- // TODO(editing-dev): The use of |
- // updateStyleAndLayoutIgnorePendingStylesheets |
- // needs to be audited. See http://crbug.com/590369 for more details. |
- newSelection.base() |
- .document() |
- ->updateStyleAndLayoutIgnorePendingStylesheets(); |
- } |
- setSelection(createVisibleSelection(newSelection), |
- newSelection.isHandleVisible() ? HandleVisibility::Visible |
- : HandleVisibility::NotVisible, |
- options, align, granularity); |
-} |
- |
-// TODO(yosin): We will make |selectionInFlatTree| version of |SetSelection()| |
-// as primary function instead of wrapper. |
void FrameSelection::setSelection(const SelectionInFlatTree& newSelection, |
SetSelectionOptions options, |
CursorAlignOnScroll align, |
TextGranularity granularity) { |
- if (!newSelection.isNone()) { |
- // TODO(editing-dev): The use of |
- // updateStyleAndLayoutIgnorePendingStylesheets |
- // needs to be audited. See http://crbug.com/590369 for more details. |
- newSelection.base() |
- .document() |
- ->updateStyleAndLayoutIgnorePendingStylesheets(); |
- } |
- setSelection(createVisibleSelection(newSelection), |
- newSelection.isHandleVisible() ? HandleVisibility::Visible |
- : HandleVisibility::NotVisible, |
- options, align, granularity); |
+ newSelection.assertValidFor(document()); |
+ SelectionInDOMTree::Builder builder; |
+ builder.setAffinity(newSelection.affinity()) |
+ .setBaseAndExtent(toPositionInDOMTree(newSelection.base()), |
+ toPositionInDOMTree(newSelection.extent())) |
+ .setGranularity(newSelection.granularity()) |
+ .setIsDirectional(newSelection.isDirectional()) |
+ .setIsHandleVisible(newSelection.isHandleVisible()) |
+ .setHasTrailingWhitespace(newSelection.hasTrailingWhitespace()); |
+ return setSelection(builder.build(), options, align, granularity); |
} |
void FrameSelection::setSelection(const VisibleSelection& newSelection, |
@@ -328,13 +323,16 @@ void FrameSelection::setSelection(const VisibleSelection& newSelection, |
SetSelectionOptions options, |
CursorAlignOnScroll align, |
TextGranularity granularity) { |
- setSelectionAlgorithm<EditingStrategy>(newSelection, handleVisibility, |
- options, align, granularity); |
+ setSelection( |
+ SelectionInDOMTree::Builder(newSelection.asSelection()) |
+ .setIsHandleVisible(handleVisibility == HandleVisibility::Visible) |
+ .build(), |
+ options, align, granularity); |
} |
void FrameSelection::setSelection(const VisibleSelection& newSelection, |
SetSelectionOptions options) { |
- setSelection(newSelection, HandleVisibility::NotVisible, options); |
+ setSelection(newSelection.asSelection(), options); |
} |
void FrameSelection::setSelection( |
@@ -343,30 +341,22 @@ void FrameSelection::setSelection( |
SetSelectionOptions options, |
CursorAlignOnScroll align, |
TextGranularity granularity) { |
- setSelectionAlgorithm<EditingInFlatTreeStrategy>( |
- newSelection, handleVisibility, options, align, granularity); |
+ setSelection( |
+ SelectionInFlatTree::Builder(newSelection.asSelection()) |
+ .setIsHandleVisible(handleVisibility == HandleVisibility::Visible) |
+ .build(), |
+ options, align, granularity); |
} |
void FrameSelection::setSelection( |
const VisibleSelectionInFlatTree& newSelection, |
SetSelectionOptions options) { |
- setSelection(newSelection, HandleVisibility::NotVisible, options); |
-} |
- |
-static bool removingNodeRemovesPosition(Node& node, const Position& position) { |
- if (!position.anchorNode()) |
- return false; |
- |
- if (position.anchorNode() == node) |
- return true; |
- |
- if (!node.isElementNode()) |
- return false; |
- |
- Element& element = toElement(node); |
- return element.isShadowIncludingInclusiveAncestorOf(position.anchorNode()); |
+ setSelection(newSelection.asSelection(), options); |
} |
+// TODO(yosin): We should move |computePositionForChildrenRemoval()| to |
+// "SelectionEditor.cpp" since it used only in |
+// |SelectionEditor::nodeChildrenWillBeRemoved()|. |
static Position computePositionForChildrenRemoval(const Position& position, |
ContainerNode& container) { |
Node* node = position.computeContainerNode(); |
@@ -376,122 +366,96 @@ static Position computePositionForChildrenRemoval(const Position& position, |
} |
void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) { |
- if (isNone() || !container.inActiveDocument()) |
+ if (!container.inActiveDocument()) |
return; |
- const Position& oldStart = selection().start(); |
- const Position& newStart = |
- computePositionForChildrenRemoval(oldStart, container); |
- const Position& oldEnd = selection().end(); |
- const Position& newEnd = computePositionForChildrenRemoval(oldEnd, container); |
- const Position& oldBase = selection().base(); |
+ // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
+ // |Editor| class. |
+ if (!document().isRunningExecCommand()) |
+ TypingCommand::closeTyping(m_frame); |
+} |
+ |
+// TODO(yosin): We should move |SelectionEditor::nodeChildrenWillBeRemoved()| |
+// to "SelectionEditor.cpp". |
+void SelectionEditor::nodeChildrenWillBeRemoved(ContainerNode& container) { |
+ if (m_selection.isNone()) |
+ return; |
+ const Position oldBase = m_selection.m_base; |
+ const Position oldExtent = m_selection.m_extent; |
const Position& newBase = |
computePositionForChildrenRemoval(oldBase, container); |
- const Position& oldExtent = selection().extent(); |
const Position& newExtent = |
computePositionForChildrenRemoval(oldExtent, container); |
- if (newStart == oldStart && newEnd == oldEnd && newBase == oldBase && |
- newExtent == oldExtent) |
+ if (newBase == oldBase && newExtent == oldExtent) |
return; |
- if (selection().isBaseFirst()) |
- m_selectionEditor->setWithoutValidation(newStart, newEnd); |
- else |
- m_selectionEditor->setWithoutValidation(newEnd, newStart); |
- if (document().isRunningExecCommand()) |
+ m_selection = SelectionInDOMTree::Builder() |
+ .setBaseAndExtent(newBase, newExtent) |
+ .build(); |
+ markCacheDirty(); |
+} |
+ |
+// TODO(yosin): We should move |computePositionForChildrenRemoval()| with |
+// |nodeWillBeRemoved()| to "SelectionEditor.cpp". |
+static Position computePositionForNodeRemoval(const Position& position, |
+ Node& nodeToBeRemoved) { |
+ Position result = position; |
+ // TODO(yosin): We should rename |updatePositionForNodeRemoval()| |
+ // to |computePositionForNodeRemoval()| to avoid using output parameter. |
+ updatePositionForNodeRemoval(result, nodeToBeRemoved); |
+ return result; |
+} |
+ |
+// TODO(yosin): We should move |nodeWillBeRemoved()| to |
+// "SelectionEditor.cpp". |
+void SelectionEditor::nodeWillBeRemoved(Node& nodeToBeRemoved) { |
+ if (m_selection.isNone()) |
return; |
- TypingCommand::closeTyping(m_frame); |
+ const Position oldBase = m_selection.m_base; |
+ const Position oldExtent = m_selection.m_extent; |
+ const Position& newBase = |
+ computePositionForNodeRemoval(oldBase, nodeToBeRemoved); |
+ const Position& newExtent = |
+ computePositionForNodeRemoval(oldExtent, nodeToBeRemoved); |
+ if (newBase == oldBase && newExtent == oldExtent) |
+ return; |
+ m_selection = SelectionInDOMTree::Builder() |
+ .setBaseAndExtent(newBase, newExtent) |
+ .build(); |
+ markCacheDirty(); |
} |
void FrameSelection::nodeWillBeRemoved(Node& node) { |
// There can't be a selection inside a fragment, so if a fragment's node is |
// being removed, the selection in the document that created the fragment |
// needs no adjustment. |
- if (isNone() || !node.inActiveDocument()) |
+ if (!node.inActiveDocument()) |
return; |
- |
- respondToNodeModification( |
- node, removingNodeRemovesPosition(node, selection().base()), |
- removingNodeRemovesPosition(node, selection().extent()), |
- removingNodeRemovesPosition(node, selection().start()), |
- removingNodeRemovesPosition(node, selection().end())); |
-} |
- |
-static SelectionState selectionStateOf(const Node& node) { |
- const LayoutObject* layoutObject = node.layoutObject(); |
- if (!layoutObject) |
- return SelectionNone; |
- return layoutObject->getSelectionState(); |
-} |
- |
-void FrameSelection::respondToNodeModification(Node& node, |
- bool baseRemoved, |
- bool extentRemoved, |
- bool startRemoved, |
- bool endRemoved) { |
- DCHECK(node.document().isActive()) << node; |
- |
- bool clearLayoutTreeSelection = false; |
- bool clearDOMTreeSelection = false; |
- |
- if (startRemoved || endRemoved) { |
- Position start = selection().start(); |
- Position end = selection().end(); |
- if (startRemoved) |
- updatePositionForNodeRemoval(start, node); |
- if (endRemoved) |
- updatePositionForNodeRemoval(end, node); |
- |
- if (Position::commonAncestorTreeScope(start, end) && start.isNotNull() && |
- end.isNotNull()) { |
- if (selection().isBaseFirst()) |
- m_selectionEditor->setWithoutValidation(start, end); |
- else |
- m_selectionEditor->setWithoutValidation(end, start); |
- } else { |
- clearDOMTreeSelection = true; |
- } |
- |
- clearLayoutTreeSelection = true; |
- } else if (baseRemoved || extentRemoved) { |
- // The base and/or extent are about to be removed, but the start and end |
- // aren't. Change the base and extent to the start and end, but don't |
- // re-validate the selection, since doing so could move the start and end |
- // into the node that is about to be removed. |
- if (selection().isBaseFirst()) |
- m_selectionEditor->setWithoutValidation(selection().start(), |
- selection().end()); |
- else |
- m_selectionEditor->setWithoutValidation(selection().end(), |
- selection().start()); |
- } else if (selectionStateOf(node) != SelectionNone) { |
- // When node to be removed is part of selection, we invalidate |
- // selection to paint again. |
- // TODO(yosin): We should paint changed area only rather than whole |
- // selected range. |
- clearLayoutTreeSelection = true; |
- } |
- |
- if (clearLayoutTreeSelection) |
- selection().start().document()->layoutViewItem().clearSelection(); |
- |
- if (clearDOMTreeSelection) |
- setSelection(SelectionInDOMTree(), DoNotSetFocus); |
- |
// TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
// |Editor| class. |
if (!document().isRunningExecCommand()) |
TypingCommand::closeTyping(m_frame); |
} |
+// TODO(yosin): We should move |updatePositionAfterAdoptingTextReplacement()| |
+// to "SelectionEditor.cpp" since it used only in |
+// |SelectionEditor::didUpdateCharacterData()|. |
static Position updatePositionAfterAdoptingTextReplacement( |
const Position& position, |
CharacterData* node, |
unsigned offset, |
unsigned oldLength, |
unsigned newLength) { |
- if (!position.anchorNode() || position.anchorNode() != node || |
- !position.isOffsetInAnchor()) |
+ if (position.anchorNode() != node) |
return position; |
+ if (position.isBeforeAnchor()) { |
+ return updatePositionAfterAdoptingTextReplacement( |
+ Position(node, 0), node, offset, oldLength, newLength); |
+ } |
+ if (position.isAfterAnchor()) { |
+ return updatePositionAfterAdoptingTextReplacement( |
+ Position(node, oldLength), node, offset, oldLength, newLength); |
+ } |
+ |
// See: |
// http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Mutation |
DCHECK_GE(position.offsetInContainerNode(), 0); |
@@ -514,69 +478,89 @@ static Position updatePositionAfterAdoptingTextReplacement( |
if (positionOffset > node->length()) |
positionOffset = node->length(); |
- // CharacterNode in VisibleSelection must be Text node, because Comment |
- // and ProcessingInstruction node aren't visible. |
- return Position(toText(node), positionOffset); |
+ return Position(node, positionOffset); |
} |
-void FrameSelection::didUpdateCharacterData(CharacterData* node, |
- unsigned offset, |
- unsigned oldLength, |
- unsigned newLength) { |
+// TODO(yosin): We should move |didUpdateCharacterData()| to |
+// "SelectionEditor.cpp". |
+void SelectionEditor::didUpdateCharacterData(CharacterData* node, |
+ unsigned offset, |
+ unsigned oldLength, |
+ unsigned newLength) { |
// The fragment check is a performance optimization. See |
// http://trac.webkit.org/changeset/30062. |
- if (isNone() || !node || !node->isConnected()) |
+ if (m_selection.isNone() || !node || !node->isConnected()) { |
+ didFinishDOMMutation(); |
return; |
- |
- Position base = updatePositionAfterAdoptingTextReplacement( |
- selection().base(), node, offset, oldLength, newLength); |
- Position extent = updatePositionAfterAdoptingTextReplacement( |
- selection().extent(), node, offset, oldLength, newLength); |
- Position start = updatePositionAfterAdoptingTextReplacement( |
- selection().start(), node, offset, oldLength, newLength); |
- Position end = updatePositionAfterAdoptingTextReplacement( |
- selection().end(), node, offset, oldLength, newLength); |
- updateSelectionIfNeeded(base, extent, start, end); |
-} |
- |
+ } |
+ const Position& newBase = updatePositionAfterAdoptingTextReplacement( |
+ m_selection.m_base, node, offset, oldLength, newLength); |
+ const Position& newExtent = updatePositionAfterAdoptingTextReplacement( |
+ m_selection.m_extent, node, offset, oldLength, newLength); |
+ didFinishTextChange(newBase, newExtent); |
+} |
+ |
+// TODO(yosin): We should move |updatePostionAfterAdoptingTextNodesMerged()| |
+// to "SelectionEditor.cpp" since it used only in |
+// |SelectionEditor::didMergeTextNodes()|. |
+// TODO(yosin): We should introduce |Position(const Text&, int)| to avoid |
+// |const_cast<Text*>|. |
static Position updatePostionAfterAdoptingTextNodesMerged( |
const Position& position, |
- const Text& oldNode, |
- unsigned offset) { |
- if (!position.anchorNode() || !position.isOffsetInAnchor()) |
- return position; |
- |
- DCHECK_GE(position.offsetInContainerNode(), 0); |
- unsigned positionOffset = |
- static_cast<unsigned>(position.offsetInContainerNode()); |
- |
- if (position.anchorNode() == &oldNode) |
- return Position(toText(oldNode.previousSibling()), positionOffset + offset); |
- |
- if (position.anchorNode() == oldNode.parentNode() && positionOffset == offset) |
- return Position(toText(oldNode.previousSibling()), offset); |
- |
+ const Text& mergedNode, |
+ const NodeWithIndex& nodeToBeRemovedWithIndex, |
+ unsigned oldLength) { |
+ Node* const anchorNode = position.anchorNode(); |
+ const Node& nodeToBeRemoved = nodeToBeRemovedWithIndex.node(); |
+ switch (position.anchorType()) { |
+ case PositionAnchorType::BeforeChildren: |
+ case PositionAnchorType::AfterChildren: |
+ return position; |
+ case PositionAnchorType::BeforeAnchor: |
+ if (anchorNode == nodeToBeRemoved) |
+ return Position(const_cast<Text*>(&mergedNode), mergedNode.length()); |
+ return position; |
+ case PositionAnchorType::AfterAnchor: |
+ if (anchorNode == nodeToBeRemoved) |
+ return Position(const_cast<Text*>(&mergedNode), mergedNode.length()); |
+ if (anchorNode == mergedNode) |
+ return Position(const_cast<Text*>(&mergedNode), oldLength); |
+ return position; |
+ case PositionAnchorType::OffsetInAnchor: { |
+ const int offset = position.offsetInContainerNode(); |
+ if (anchorNode == nodeToBeRemoved) |
+ return Position(const_cast<Text*>(&mergedNode), oldLength + offset); |
+ if (anchorNode == nodeToBeRemoved.parentNode() && |
+ offset == nodeToBeRemovedWithIndex.index()) { |
+ return Position(const_cast<Text*>(&mergedNode), oldLength); |
+ } |
+ return position; |
+ } |
+ } |
+ NOTREACHED() << position; |
return position; |
} |
-void FrameSelection::didMergeTextNodes( |
+// TODO(yosin): We should move |SelectionEditor::didMergeTextNodes()| to |
+// "SelectionEditor.cpp". |
+void SelectionEditor::didMergeTextNodes( |
const Text& mergedNode, |
const NodeWithIndex& nodeToBeRemovedWithIndex, |
- unsigned offset) { |
- const Text& oldNode = toText(nodeToBeRemovedWithIndex.node()); |
- if (isNone() || !oldNode.isConnected()) |
+ unsigned oldLength) { |
+ if (m_selection.isNone()) { |
+ didFinishDOMMutation(); |
return; |
- Position base = updatePostionAfterAdoptingTextNodesMerged(selection().base(), |
- oldNode, offset); |
- Position extent = updatePostionAfterAdoptingTextNodesMerged( |
- selection().extent(), oldNode, offset); |
- Position start = updatePostionAfterAdoptingTextNodesMerged( |
- selection().start(), oldNode, offset); |
- Position end = updatePostionAfterAdoptingTextNodesMerged(selection().end(), |
- oldNode, offset); |
- updateSelectionIfNeeded(base, extent, start, end); |
+ } |
+ const Position& newBase = updatePostionAfterAdoptingTextNodesMerged( |
+ m_selection.m_base, mergedNode, nodeToBeRemovedWithIndex, oldLength); |
+ const Position& newExtent = updatePostionAfterAdoptingTextNodesMerged( |
+ m_selection.m_extent, mergedNode, nodeToBeRemovedWithIndex, oldLength); |
+ didFinishTextChange(newBase, newExtent); |
} |
+// TODO(yosin): We should move |updatePostionAfterAdoptingTextNodeSplit()| |
+// to "SelectionEditor.cpp" since it used only in |
+// |SelectionEditor::didSplitTextNode()|. |
static Position updatePostionAfterAdoptingTextNodeSplit( |
const Position& position, |
const Text& oldNode) { |
@@ -594,37 +578,18 @@ static Position updatePostionAfterAdoptingTextNodeSplit( |
return Position(toText(oldNode.nextSibling()), positionOffset - oldLength); |
} |
-void FrameSelection::didSplitTextNode(const Text& oldNode) { |
- if (isNone() || !oldNode.isConnected()) |
+// TODO(yosin): We should move |SelectionEditor::didSplitTextNode()| to |
+// "SelectionEditor.cpp". |
+void SelectionEditor::didSplitTextNode(const Text& oldNode) { |
+ if (m_selection.isNone() || !oldNode.isConnected()) { |
+ didFinishDOMMutation(); |
return; |
- Position base = |
- updatePostionAfterAdoptingTextNodeSplit(selection().base(), oldNode); |
- Position extent = |
- updatePostionAfterAdoptingTextNodeSplit(selection().extent(), oldNode); |
- Position start = |
- updatePostionAfterAdoptingTextNodeSplit(selection().start(), oldNode); |
- Position end = |
- updatePostionAfterAdoptingTextNodeSplit(selection().end(), oldNode); |
- updateSelectionIfNeeded(base, extent, start, end); |
-} |
- |
-void FrameSelection::updateSelectionIfNeeded(const Position& base, |
- const Position& extent, |
- const Position& start, |
- const Position& end) { |
- if (base == selection().base() && extent == selection().extent() && |
- start == selection().start() && end == selection().end()) |
- return; |
- // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
- // |Editor| class. |
- if (!document().isRunningExecCommand()) |
- TypingCommand::closeTyping(m_frame); |
- VisibleSelection newSelection; |
- if (selection().isBaseFirst()) |
- newSelection.setWithoutValidation(start, end); |
- else |
- newSelection.setWithoutValidation(end, start); |
- setSelection(newSelection, DoNotSetFocus); |
+ } |
+ const Position& newBase = |
+ updatePostionAfterAdoptingTextNodeSplit(m_selection.m_base, oldNode); |
+ const Position& newExtent = |
+ updatePostionAfterAdoptingTextNodeSplit(m_selection.m_extent, oldNode); |
+ didFinishTextChange(newBase, newExtent); |
} |
void FrameSelection::didChangeFocus() { |
@@ -731,7 +696,6 @@ void FrameSelection::contextDestroyed(Document* document) { |
view.clearSelection(); |
m_frame->editor().clearTypingStyle(); |
- m_selectionEditor->documentDetached(*document); |
} |
void FrameSelection::clearPreviousCaretVisualRect(const LayoutBlock& block) { |
@@ -754,8 +718,7 @@ void FrameSelection::invalidatePaintIfNeeded( |
} |
bool FrameSelection::shouldPaintCaret(const LayoutBlock& block) const { |
- DCHECK(selection().isValidFor(document())); |
- |
+ DCHECK_GE(document().lifecycle().state(), DocumentLifecycle::LayoutClean); |
bool result = m_frameCaret->shouldPaintCaret(block); |
DCHECK(!result || (isCaret() && hasEditableStyle())); |
return result; |
@@ -1075,10 +1038,8 @@ void FrameSelection::didLayout() { |
} |
void FrameSelection::updateAppearance() { |
- m_frameCaret->updateAppearance(); |
- |
- if (m_frame->contentLayoutItem().isNull()) |
- return; |
+ DCHECK(!m_frame->contentLayoutItem().isNull()); |
+ m_frameCaret->scheduleVisualUpdateForPaintInvalidationIfNeeded(); |
m_pendingSelection->setHasPendingSelection(); |
} |
@@ -1281,10 +1242,6 @@ void FrameSelection::setSelectionFromNone() { |
return; |
if (HTMLBodyElement* body = |
Traversal<HTMLBodyElement>::firstChild(*documentElement)) { |
- // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
- // needs to be audited. See http://crbug.com/590369 for more details. |
- document->updateStyleAndLayoutIgnorePendingStylesheets(); |
- |
setSelection(SelectionInDOMTree::Builder() |
.collapse(firstPositionInOrBeforeNode(body)) |
.build()); |
@@ -1395,18 +1352,19 @@ void FrameSelection::moveRangeSelectionExtent(const IntPoint& contentsPoint) { |
void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, |
const VisiblePosition& extentPosition, |
TextGranularity granularity) { |
- VisibleSelection newSelection = createVisibleSelection( |
+ SelectionInDOMTree newSelection = |
SelectionInDOMTree::Builder() |
.setBaseAndExtentDeprecated(basePosition.deepEquivalent(), |
extentPosition.deepEquivalent()) |
.setAffinity(basePosition.affinity()) |
.setGranularity(granularity) |
- .build()); |
+ .setIsHandleVisible(isHandleVisible()) |
+ .build(); |
if (newSelection.isNone()) |
return; |
- setSelection(newSelection, m_handleVisibility, CloseTyping | ClearTypingStyle, |
+ setSelection(newSelection, CloseTyping | ClearTypingStyle, |
CursorAlignOnScroll::IfNeeded, granularity); |
} |