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

Unified Diff: third_party/WebKit/Source/core/editing/FrameSelection.cpp

Issue 2694823002: Revert of Make FrameSelection to hold non-canonicalized positions (Closed)
Patch Set: Merge branch 'master' of https://chromium.googlesource.com/chromium/src into patch_revert Created 3 years, 10 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/FrameSelection.cpp
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index a30f178610c8eede18e70b4fa4cfe6f76ee7b721..10a702562f5f21f4b2e96cf80b2d4582bd1f1942 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -110,17 +110,16 @@ const DisplayItemClient& FrameSelection::caretDisplayItemClientForTesting()
return m_frameCaret->displayItemClient();
}
-Document& FrameSelection::document() const {
+const Document& FrameSelection::document() const {
DCHECK(lifecycleContext());
return *lifecycleContext();
}
-bool FrameSelection::isHandleVisible() const {
- return selectionInDOMTree().isHandleVisible();
+Document& FrameSelection::document() {
+ DCHECK(lifecycleContext());
+ return *lifecycleContext();
}
-// 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.
@@ -130,29 +129,12 @@ 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();
@@ -167,13 +149,8 @@ ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const {
return node ? &node->treeScope().rootNode() : 0;
}
-// TODO(yosin): We should rename |FrameSelection::selection()| to
-// |selectionDeprecated()|.
const VisibleSelection& FrameSelection::selection() const {
- // TODO(yosin): We should hoist updateStyleAndLayoutIgnorePendingStylesheets
- // to caller. See http://crbug.com/590369 for more details.
- document().updateStyleAndLayoutIgnorePendingStylesheets();
- return computeVisibleSelectionInDOMTree();
+ return visibleSelection<EditingStrategy>();
}
const VisibleSelectionInFlatTree& FrameSelection::selectionInFlatTree() const {
@@ -197,22 +174,29 @@ void FrameSelection::moveCaretSelection(const IntPoint& point) {
setSelection(builder.build(), CloseTyping | ClearTypingStyle | UserTriggered);
}
-void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection,
- SetSelectionOptions options,
- CursorAlignOnScroll align,
- TextGranularity granularity) {
+template <typename Strategy>
+void FrameSelection::setSelectionAlgorithm(
+ const VisibleSelectionTemplate<Strategy>& newSelection,
+ HandleVisibility handleVisibility,
+ SetSelectionOptions options,
+ CursorAlignOnScroll align,
+ TextGranularity granularity) {
DCHECK(isAvailable());
- passedSelection.assertValidFor(document());
-
- SelectionInDOMTree::Builder builder(passedSelection);
- if (shouldAlwaysUseDirectionalSelection(m_frame))
- builder.setIsDirectional(true);
- SelectionInDOMTree newSelection = builder.build();
+ DCHECK(newSelection.isValidFor(document()));
+ const Document& currentDocument = document();
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
@@ -223,28 +207,23 @@ void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection,
if (shouldClearTypingStyle)
m_frame->editor().clearTypingStyle();
- const SelectionInDOMTree oldSelectionInDOMTree =
- m_selectionEditor->selectionInDOMTree();
- if (oldSelectionInDOMTree == newSelection)
+ if (m_selectionEditor->visibleSelection<Strategy>() == s &&
+ m_handleVisibility == handleVisibility) {
+ // Even if selection was not changed, selection offsets may have been
+ // changed.
+ notifyLayoutObjectOfSelectionChange(userTriggered);
return;
- m_selectionEditor->setSelection(newSelection);
- scheduleVisualUpdateForPaintInvalidationIfNeeded();
+ }
- // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets
- // needs to be audited. see http://crbug.com/590369 for more details.
- document().updateStyleAndLayoutIgnorePendingStylesheets();
+ const VisibleSelectionTemplate<Strategy> oldSelection =
+ visibleSelection<Strategy>();
+ const Position& oldSelectionStart = selection().start();
- 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)) {
+ m_handleVisibility = handleVisibility;
+ m_selectionEditor->setVisibleSelection(s, options);
+ scheduleVisualUpdateForPaintInvalidationIfNeeded();
+
+ if (!s.isNone() && !(options & DoNotSetFocus)) {
setFocusedNodeIfNeeded();
// |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and
// "FocusIn", |m_frame| may associate to another document.
@@ -264,7 +243,6 @@ void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection,
// 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) {
@@ -273,8 +251,16 @@ void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection,
// 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;
@@ -287,11 +273,6 @@ void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection,
? 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);
}
@@ -302,20 +283,44 @@ void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection,
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) {
- 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);
+ 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);
}
void FrameSelection::setSelection(const VisibleSelection& newSelection,
@@ -323,16 +328,13 @@ void FrameSelection::setSelection(const VisibleSelection& newSelection,
SetSelectionOptions options,
CursorAlignOnScroll align,
TextGranularity granularity) {
- setSelection(
- SelectionInDOMTree::Builder(newSelection.asSelection())
- .setIsHandleVisible(handleVisibility == HandleVisibility::Visible)
- .build(),
- options, align, granularity);
+ setSelectionAlgorithm<EditingStrategy>(newSelection, handleVisibility,
+ options, align, granularity);
}
void FrameSelection::setSelection(const VisibleSelection& newSelection,
SetSelectionOptions options) {
- setSelection(newSelection.asSelection(), options);
+ setSelection(newSelection, HandleVisibility::NotVisible, options);
}
void FrameSelection::setSelection(
@@ -341,22 +343,30 @@ void FrameSelection::setSelection(
SetSelectionOptions options,
CursorAlignOnScroll align,
TextGranularity granularity) {
- setSelection(
- SelectionInFlatTree::Builder(newSelection.asSelection())
- .setIsHandleVisible(handleVisibility == HandleVisibility::Visible)
- .build(),
- options, align, granularity);
+ setSelectionAlgorithm<EditingInFlatTreeStrategy>(
+ newSelection, handleVisibility, options, align, granularity);
}
void FrameSelection::setSelection(
const VisibleSelectionInFlatTree& newSelection,
SetSelectionOptions options) {
- setSelection(newSelection.asSelection(), 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());
}
-// 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();
@@ -366,96 +376,122 @@ static Position computePositionForChildrenRemoval(const Position& position,
}
void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) {
- if (!container.inActiveDocument())
+ if (isNone() || !container.inActiveDocument())
return;
- // 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& 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();
const Position& newBase =
computePositionForChildrenRemoval(oldBase, container);
+ const Position& oldExtent = selection().extent();
const Position& newExtent =
computePositionForChildrenRemoval(oldExtent, container);
- if (newBase == oldBase && newExtent == oldExtent)
+ if (newStart == oldStart && newEnd == oldEnd && newBase == oldBase &&
+ newExtent == oldExtent)
return;
- 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;
- 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)
+ if (selection().isBaseFirst())
+ m_selectionEditor->setWithoutValidation(newStart, newEnd);
+ else
+ m_selectionEditor->setWithoutValidation(newEnd, newStart);
+ if (document().isRunningExecCommand())
return;
- m_selection = SelectionInDOMTree::Builder()
- .setBaseAndExtent(newBase, newExtent)
- .build();
- markCacheDirty();
+ TypingCommand::closeTyping(m_frame);
}
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 (!node.inActiveDocument())
+ if (isNone() || !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() != node)
+ if (!position.anchorNode() || position.anchorNode() != node ||
+ !position.isOffsetInAnchor())
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);
@@ -478,89 +514,69 @@ static Position updatePositionAfterAdoptingTextReplacement(
if (positionOffset > node->length())
positionOffset = node->length();
- return Position(node, positionOffset);
+ // CharacterNode in VisibleSelection must be Text node, because Comment
+ // and ProcessingInstruction node aren't visible.
+ return Position(toText(node), positionOffset);
}
-// TODO(yosin): We should move |didUpdateCharacterData()| to
-// "SelectionEditor.cpp".
-void SelectionEditor::didUpdateCharacterData(CharacterData* node,
- unsigned offset,
- unsigned oldLength,
- unsigned newLength) {
+void FrameSelection::didUpdateCharacterData(CharacterData* node,
+ unsigned offset,
+ unsigned oldLength,
+ unsigned newLength) {
// The fragment check is a performance optimization. See
// http://trac.webkit.org/changeset/30062.
- if (m_selection.isNone() || !node || !node->isConnected()) {
- didFinishDOMMutation();
+ if (isNone() || !node || !node->isConnected())
return;
- }
- 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*>|.
+
+ 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);
+}
+
static Position updatePostionAfterAdoptingTextNodesMerged(
const Position& position,
- 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;
+ 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);
+
return position;
}
-// TODO(yosin): We should move |SelectionEditor::didMergeTextNodes()| to
-// "SelectionEditor.cpp".
-void SelectionEditor::didMergeTextNodes(
+void FrameSelection::didMergeTextNodes(
const Text& mergedNode,
const NodeWithIndex& nodeToBeRemovedWithIndex,
- unsigned oldLength) {
- if (m_selection.isNone()) {
- didFinishDOMMutation();
+ unsigned offset) {
+ const Text& oldNode = toText(nodeToBeRemovedWithIndex.node());
+ if (isNone() || !oldNode.isConnected())
return;
- }
- 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);
+ 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);
}
-// 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) {
@@ -578,18 +594,37 @@ static Position updatePostionAfterAdoptingTextNodeSplit(
return Position(toText(oldNode.nextSibling()), positionOffset - oldLength);
}
-// TODO(yosin): We should move |SelectionEditor::didSplitTextNode()| to
-// "SelectionEditor.cpp".
-void SelectionEditor::didSplitTextNode(const Text& oldNode) {
- if (m_selection.isNone() || !oldNode.isConnected()) {
- didFinishDOMMutation();
+void FrameSelection::didSplitTextNode(const Text& oldNode) {
+ if (isNone() || !oldNode.isConnected())
return;
- }
- const Position& newBase =
- updatePostionAfterAdoptingTextNodeSplit(m_selection.m_base, oldNode);
- const Position& newExtent =
- updatePostionAfterAdoptingTextNodeSplit(m_selection.m_extent, oldNode);
- didFinishTextChange(newBase, newExtent);
+ 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);
}
void FrameSelection::didChangeFocus() {
@@ -696,6 +731,7 @@ void FrameSelection::contextDestroyed(Document* document) {
view.clearSelection();
m_frame->editor().clearTypingStyle();
+ m_selectionEditor->documentDetached(*document);
}
void FrameSelection::clearPreviousCaretVisualRect(const LayoutBlock& block) {
@@ -718,7 +754,8 @@ void FrameSelection::invalidatePaintIfNeeded(
}
bool FrameSelection::shouldPaintCaret(const LayoutBlock& block) const {
- DCHECK_GE(document().lifecycle().state(), DocumentLifecycle::LayoutClean);
+ DCHECK(selection().isValidFor(document()));
+
bool result = m_frameCaret->shouldPaintCaret(block);
DCHECK(!result || (isCaret() && hasEditableStyle()));
return result;
@@ -1038,8 +1075,10 @@ void FrameSelection::didLayout() {
}
void FrameSelection::updateAppearance() {
- DCHECK(!m_frame->contentLayoutItem().isNull());
- m_frameCaret->scheduleVisualUpdateForPaintInvalidationIfNeeded();
+ m_frameCaret->updateAppearance();
+
+ if (m_frame->contentLayoutItem().isNull())
+ return;
m_pendingSelection->setHasPendingSelection();
}
@@ -1242,6 +1281,10 @@ 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());
@@ -1352,19 +1395,18 @@ void FrameSelection::moveRangeSelectionExtent(const IntPoint& contentsPoint) {
void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition,
const VisiblePosition& extentPosition,
TextGranularity granularity) {
- SelectionInDOMTree newSelection =
+ VisibleSelection newSelection = createVisibleSelection(
SelectionInDOMTree::Builder()
.setBaseAndExtentDeprecated(basePosition.deepEquivalent(),
extentPosition.deepEquivalent())
.setAffinity(basePosition.affinity())
.setGranularity(granularity)
- .setIsHandleVisible(isHandleVisible())
- .build();
+ .build());
if (newSelection.isNone())
return;
- setSelection(newSelection, CloseTyping | ClearTypingStyle,
+ setSelection(newSelection, m_handleVisibility, CloseTyping | ClearTypingStyle,
CursorAlignOnScroll::IfNeeded, granularity);
}
« no previous file with comments | « third_party/WebKit/Source/core/editing/FrameSelection.h ('k') | third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698