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

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

Issue 2701363002: Move code for SelectionEditor in FrameSelection.cpp to SelectionEditor.cpp (Closed)
Patch Set: 2017-02-20T16:41:49 Rebase 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
« no previous file with comments | « third_party/WebKit/Source/core/editing/FrameSelection.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/editing/SelectionEditor.cpp
diff --git a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
index 3cbe4ecee2d19bcee6490b58cb16a34655a86a29..3835d0678c75ee6ef0417df6d5821adde52c828a 100644
--- a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
@@ -178,6 +178,199 @@ void SelectionEditor::contextDestroyed(Document*) {
m_cacheIsDirty = false;
}
+static Position computePositionForChildrenRemoval(const Position& position,
+ ContainerNode& container) {
+ Node* node = position.computeContainerNode();
+ if (container.containsIncludingHostElements(*node))
+ return Position::firstPositionInNode(&container);
+ return position;
+}
+
+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& newExtent =
+ computePositionForChildrenRemoval(oldExtent, container);
+ if (newBase == oldBase && newExtent == oldExtent)
+ return;
+ m_selection = SelectionInDOMTree::Builder()
+ .setBaseAndExtent(newBase, newExtent)
+ .build();
+ markCacheDirty();
+}
+
+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;
+}
+
+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)
+ return;
+ m_selection = SelectionInDOMTree::Builder()
+ .setBaseAndExtent(newBase, newExtent)
+ .build();
+ markCacheDirty();
+}
+
+static Position updatePositionAfterAdoptingTextReplacement(
+ const Position& position,
+ CharacterData* node,
+ unsigned offset,
+ unsigned oldLength,
+ unsigned newLength) {
+ 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);
+ unsigned positionOffset =
+ static_cast<unsigned>(position.offsetInContainerNode());
+ // Replacing text can be viewed as a deletion followed by insertion.
+ if (positionOffset >= offset && positionOffset <= offset + oldLength)
+ positionOffset = offset;
+
+ // Adjust the offset if the position is after the end of the deleted contents
+ // (positionOffset > offset + oldLength) to avoid having a stale offset.
+ if (positionOffset > offset + oldLength)
+ positionOffset = positionOffset - oldLength + newLength;
+
+ // Due to case folding
+ // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText
+ // length may be different from Text length. A correct implementation would
+ // translate the LayoutText offset to a Text offset; this is just a safety
+ // precaution to avoid offset values that run off the end of the Text.
+ if (positionOffset > node->length())
+ positionOffset = node->length();
+
+ return Position(node, positionOffset);
+}
+
+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 (m_selection.isNone() || !node || !node->isConnected()) {
+ didFinishDOMMutation();
+ 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 introduce |Position(const Text&, int)| to avoid
+// |const_cast<Text*>|.
+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;
+ return position;
+}
+
+void SelectionEditor::didMergeTextNodes(
+ const Text& mergedNode,
+ const NodeWithIndex& nodeToBeRemovedWithIndex,
+ unsigned oldLength) {
+ if (m_selection.isNone()) {
+ didFinishDOMMutation();
+ 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);
+}
+
+static Position updatePostionAfterAdoptingTextNodeSplit(
+ const Position& position,
+ const Text& oldNode) {
+ if (!position.anchorNode() || position.anchorNode() != &oldNode ||
+ !position.isOffsetInAnchor())
+ return position;
+ // See:
+ // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Mutation
+ DCHECK_GE(position.offsetInContainerNode(), 0);
+ unsigned positionOffset =
+ static_cast<unsigned>(position.offsetInContainerNode());
+ unsigned oldLength = oldNode.length();
+ if (positionOffset <= oldLength)
+ return position;
+ return Position(toText(oldNode.nextSibling()), positionOffset - oldLength);
+}
+
+void SelectionEditor::didSplitTextNode(const Text& oldNode) {
+ if (m_selection.isNone() || !oldNode.isConnected()) {
+ didFinishDOMMutation();
+ return;
+ }
+ const Position& newBase =
+ updatePostionAfterAdoptingTextNodeSplit(m_selection.m_base, oldNode);
+ const Position& newExtent =
+ updatePostionAfterAdoptingTextNodeSplit(m_selection.m_extent, oldNode);
+ didFinishTextChange(newBase, newExtent);
+}
+
void SelectionEditor::resetLogicalRange() {
// Non-collapsed ranges are not allowed to start at the end of a line that
// is wrapped, they start at the beginning of the next line instead
« no previous file with comments | « third_party/WebKit/Source/core/editing/FrameSelection.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698