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

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

Issue 1958093002: CONTINUED Make FrameSelection to hold non-canonicalized positions Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 2017-01-16T20:04:35 Created 3 years, 11 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/SelectionEditor.cpp
diff --git a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
index 8206ecf15d3debae364272601af153a1bff8911d..42d97add4e8eeae89b1c5123b1f75228b9663e69 100644
--- a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
@@ -25,27 +25,56 @@
#include "core/editing/SelectionEditor.h"
+#include "core/dom/NodeWithIndex.h"
+#include "core/dom/Text.h"
#include "core/editing/EditingUtilities.h"
#include "core/editing/Editor.h"
#include "core/editing/SelectionAdjuster.h"
#include "core/frame/LocalFrame.h"
+#include <iterator>
+#include <ostream> // NOLINT
namespace blink {
+#define FOR_EACH_STATE(V) \
+ V(VisibleSelectionMayBeValid) \
+ V(DOMTreeIsChanged) \
+ V(DOMTreeIsChanging) \
+ V(SelectionInDOMTreeIsSource)
+
+enum class SelectionEditor::CacheState {
+#define V(name) name,
+ FOR_EACH_STATE(V)
+#undef V
+};
+
+std::ostream& operator<<(std::ostream& ostream,
+ SelectionEditor::CacheState state) {
+ static const char* names[] = {
+#define V(name) #name,
+ FOR_EACH_STATE(V)
+#undef V
+ };
+ const auto& it = std::begin(names) + static_cast<size_t>(state);
+ if (it < std::begin(names) || it >= std::end(names))
+ return ostream << "CacheState::Bad(" << static_cast<int>(state) << ')';
+ return ostream << *it;
+}
+
SelectionEditor::SelectionEditor(LocalFrame& frame)
- : m_frame(frame), m_observingVisibleSelection(false) {
+ : m_frame(frame), m_cacheState(CacheState::VisibleSelectionMayBeValid) {
clearVisibleSelection();
}
SelectionEditor::~SelectionEditor() {}
void SelectionEditor::clearVisibleSelection() {
- m_selection = VisibleSelection();
- m_selectionInFlatTree = VisibleSelectionInFlatTree();
+ m_selection = SelectionInDOMTree();
+ m_cachedVisibleSelectionInDOMTree = VisibleSelection();
+ m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
if (!shouldAlwaysUseDirectionalSelection())
return;
- m_selection.setIsDirectional(true);
- m_selectionInFlatTree.setIsDirectional(true);
+ m_selection.m_isDirectional = true;
}
void SelectionEditor::dispose() {
@@ -53,83 +82,356 @@ void SelectionEditor::dispose() {
clearVisibleSelection();
}
-const Document& SelectionEditor::document() const {
- DCHECK(m_document);
- return *m_document;
+Document& SelectionEditor::document() const {
+ DCHECK(lifecycleContext());
+ return *lifecycleContext();
+}
+
+const SelectionInDOMTree& SelectionEditor::selectionInDOMTree() const {
+ m_selection.assertValidFor(document());
+ return m_selection;
+}
+
+bool SelectionEditor::hasEditableStyle() const {
+ return computeVisibleSelectionInDOMTree().hasEditableStyle();
+}
+
+bool SelectionEditor::isContentEditable() const {
+ return computeVisibleSelectionInDOMTree().isContentEditable();
}
-template <>
-const VisibleSelection& SelectionEditor::visibleSelection<EditingStrategy>()
+bool SelectionEditor::isContentRichlyEditable() const {
+ return computeVisibleSelectionInDOMTree().isContentRichlyEditable();
+}
+
+const VisibleSelection& SelectionEditor::computeVisibleSelectionInDOMTree()
const {
DCHECK_EQ(frame()->document(), document());
DCHECK_EQ(frame(), document().frame());
- if (m_selection.isNone())
- return m_selection;
- DCHECK_EQ(m_selection.base().document(), document());
- return m_selection;
+ const_cast<SelectionEditor*>(this)->updateCachedVisibleSelectionIfNeeded();
+ if (m_cachedVisibleSelectionInDOMTree.isNone())
+ return m_cachedVisibleSelectionInDOMTree;
+ DCHECK_EQ(m_cachedVisibleSelectionInDOMTree.base().document(), document());
+ return m_cachedVisibleSelectionInDOMTree;
}
-template <>
const VisibleSelectionInFlatTree&
-SelectionEditor::visibleSelection<EditingInFlatTreeStrategy>() const {
+SelectionEditor::computeVisibleSelectionInFlatTree() const {
DCHECK_EQ(frame()->document(), document());
DCHECK_EQ(frame(), document().frame());
- if (m_selectionInFlatTree.isNone())
- return m_selectionInFlatTree;
- DCHECK_EQ(m_selectionInFlatTree.base().document(), document());
- return m_selectionInFlatTree;
+ const_cast<SelectionEditor*>(this)->updateCachedVisibleSelectionIfNeeded();
+ if (m_cachedVisibleSelectionInFlatTree.isNone())
+ return m_cachedVisibleSelectionInFlatTree;
+ DCHECK_EQ(m_cachedVisibleSelectionInFlatTree.base().document(), document());
+ return m_cachedVisibleSelectionInFlatTree;
}
-void SelectionEditor::setVisibleSelection(
- const VisibleSelection& newSelection,
- FrameSelection::SetSelectionOptions options) {
- DCHECK(newSelection.isValidFor(document())) << newSelection;
+void SelectionEditor::setSelection(const SelectionInDOMTree& newSelection) {
+ m_selection.assertValidFor(document());
+ newSelection.assertValidFor(document());
+ if (m_selection == newSelection)
+ return;
resetLogicalRange();
+ m_cacheState = CacheState::SelectionInDOMTreeIsSource;
+ m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
+ m_cachedVisibleSelectionInDOMTree = VisibleSelection();
+
m_selection = newSelection;
- if (options & FrameSelection::DoNotAdjustInFlatTree) {
- m_selectionInFlatTree.setWithoutValidation(
- toPositionInFlatTree(m_selection.base()),
- toPositionInFlatTree(m_selection.extent()));
+
+ m_domTreeVersion = document().domTreeVersion();
+ m_styleVersion = document().styleVersion();
+}
+
+void SelectionEditor::didChangeAttribute(const Element&) {
+ didFinishDOMMutation();
+}
+
+void SelectionEditor::didChangeChildren(const ContainerNode&) {
+ didFinishDOMMutation();
+}
+
+void SelectionEditor::didMoveTreeToNewDocument() {
+ didFinishDOMMutation();
+}
+
+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();
+ m_cachedVisibleSelectionInDOMTree = VisibleSelection();
+ m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
+}
+
+static Position positionAfterPreviousSiblingOf(const Node& node) {
+ Node* const previousSibling = NodeTraversal::previousSibling(node);
+ if (!previousSibling) {
+ // Returns |BeforeChildren| of a parent of |node| since |node| is the
+ // first child.
+ return Position::firstPositionInNode(NodeTraversal::parent(node));
+ }
+#if 0
+ // When enable this code fragment,
+ // "editing/selection/mouse/drag-user-select-all-textarea.html" is failed.
+ //
+ // When disable this code fragment,
+ // "editing/selection/selection-after-text-normalize.html" is failed.
+ if (previousSibling->isCharacterDataNode()) {
+ return Position(previousSibling,
+ toCharacterData(previousSibling)->length());
}
+#endif
+ return Position::afterNode(previousSibling);
+}
- SelectionAdjuster::adjustSelectionInFlatTree(&m_selectionInFlatTree,
- m_selection);
+static Position computePositionForNodeRemoval(const Position& position,
+ Node& nodeToBeRemoved) {
+ Node* const anchorNode = position.anchorNode();
+ if (anchorNode == nodeToBeRemoved)
+ return positionAfterPreviousSiblingOf(nodeToBeRemoved);
+ if (position.isOffsetInAnchor() &&
+ anchorNode == nodeToBeRemoved.parentNode()) {
+ const int positionOffset = position.offsetInContainerNode();
+ if (positionOffset == 0)
+ return position;
+ // |nodeToBeRemoved| is sibling or itself of |position|.
+ int offset = 0;
+ for (Node& child :
+ NodeTraversal::childrenOf(*nodeToBeRemoved.parentNode())) {
+ if (nodeToBeRemoved == child) {
+ // |position| is after |nodeToBeRemoved|.
+ return Position(anchorNode, positionOffset - 1);
+ }
+ if (positionOffset == offset) {
+ // |position| is before |nodeToBeRemoved|.
+ return position;
+ }
+ ++offset;
+ }
+ NOTREACHED() << position << " should be handled.";
+ }
+ if (!nodeToBeRemoved.isContainerNode())
+ return position;
+ if (toContainerNode(nodeToBeRemoved)
+ .containsIncludingHostElements(*anchorNode))
+ return positionAfterPreviousSiblingOf(nodeToBeRemoved);
+ return position;
}
-void SelectionEditor::setVisibleSelection(
- const VisibleSelectionInFlatTree& newSelection,
- FrameSelection::SetSelectionOptions options) {
- DCHECK(newSelection.isValidFor(document())) << newSelection;
- DCHECK(!(options & FrameSelection::DoNotAdjustInFlatTree));
- resetLogicalRange();
- m_selectionInFlatTree = newSelection;
- SelectionAdjuster::adjustSelectionInDOMTree(&m_selection,
- m_selectionInFlatTree);
+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::setWithoutValidation(const Position& base,
- const Position& extent) {
- resetLogicalRange();
- if (base.isNotNull())
- DCHECK_EQ(base.document(), document());
- if (extent.isNotNull())
- DCHECK_EQ(extent.document(), document());
- m_selection.setWithoutValidation(base, extent);
- m_selectionInFlatTree.setWithoutValidation(toPositionInFlatTree(base),
- toPositionInFlatTree(extent));
+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);
+}
+
+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(mergedNode, mergedNode.length());
+ return position;
+ case PositionAnchorType::AfterAnchor:
+ if (anchorNode == nodeToBeRemoved)
+ return Position(mergedNode, mergedNode.length());
+ if (anchorNode == mergedNode)
+ return Position(mergedNode, oldLength);
+ return position;
+ case PositionAnchorType::OffsetInAnchor: {
+ const int offset = position.offsetInContainerNode();
+ if (anchorNode == nodeToBeRemoved)
+ return Position(mergedNode, oldLength + offset);
+ if (anchorNode == nodeToBeRemoved.parentNode() &&
+ offset == nodeToBeRemovedWithIndex.index()) {
+ return Position(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() != &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::didFinishTextChange(const Position& newBase,
+ const Position& newExtent) {
+ if (newBase != m_selection.m_base || newExtent != m_selection.m_extent) {
+ m_selection.m_base = newBase;
+ m_selection.m_extent = newExtent;
+ m_cachedVisibleSelectionInDOMTree = VisibleSelection();
+ m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
+ }
+ didFinishDOMMutation();
+}
+
+void SelectionEditor::didFinishDOMMutation() {
+ m_domTreeVersion = document().domTreeVersion();
+#if ENABLE(ASSERT)
+ m_selection.m_domTreeVersion = m_domTreeVersion;
+#endif
+ m_cacheState = CacheState::DOMTreeIsChanged;
+ // TODO(yosin): Should we notify selection change?
+ m_selection.assertValidFor(document());
+}
+
+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_cacheState = CacheState::DOMTreeIsChanging;
+ m_selection = SelectionInDOMTree::Builder()
+ .setBaseAndExtent(newBase, newExtent)
+ .build();
+ m_cachedVisibleSelectionInDOMTree = VisibleSelection();
+ m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
}
void SelectionEditor::documentAttached(Document* document) {
DCHECK(document);
- DCHECK(!m_document) << m_document;
- m_document = document;
+ DCHECK(!lifecycleContext()) << lifecycleContext();
+ m_domTreeVersion = document->domTreeVersion();
+ m_styleVersion = static_cast<uint64_t>(-1);
+ clearVisibleSelection();
+ setContext(document);
}
-void SelectionEditor::documentDetached(const Document& document) {
- DCHECK_EQ(m_document, &document);
+void SelectionEditor::contextDestroyed(Document*) {
dispose();
- m_document = nullptr;
+ m_domTreeVersion = 0;
+ m_styleVersion = static_cast<uint64_t>(-1);
+ m_selection = SelectionInDOMTree();
+ m_cachedVisibleSelectionInDOMTree = VisibleSelection();
+ m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
}
void SelectionEditor::resetLogicalRange() {
@@ -150,7 +452,7 @@ void SelectionEditor::setLogicalRange(Range* range) {
Range* SelectionEditor::firstRange() const {
if (m_logicalRange)
return m_logicalRange->cloneRange();
- return firstRangeOf(m_selection);
+ return firstRangeOf(computeVisibleSelectionInDOMTree());
}
bool SelectionEditor::shouldAlwaysUseDirectionalSelection() const {
@@ -158,18 +460,107 @@ bool SelectionEditor::shouldAlwaysUseDirectionalSelection() const {
}
void SelectionEditor::updateIfNeeded() {
- DCHECK(m_selection.isValidFor(document())) << m_selection;
- DCHECK(m_selectionInFlatTree.isValidFor(document())) << m_selection;
- m_selection.updateIfNeeded();
- m_selectionInFlatTree.updateIfNeeded();
+ // TODO(yosin): We should unify |SelectionEditor::updateIfNeeded()| and
+ // |updateCachedVisibleSelectionIfNeeded()|
+ updateCachedVisibleSelectionIfNeeded();
+}
+
+class SelectionEditor::CacheUpdateScope {
+ STACK_ALLOCATED();
+
+ public:
+ CacheUpdateScope(SelectionEditor*);
+ ~CacheUpdateScope();
+
+ private:
+ DEFINE_INLINE_TRACE() { visitor->trace(m_editor); }
+
+ Member<SelectionEditor> m_editor;
+ DISALLOW_COPY_AND_ASSIGN(CacheUpdateScope);
+};
+
+SelectionEditor::CacheUpdateScope::CacheUpdateScope(SelectionEditor* editor)
+ : m_editor(editor) {
+ m_editor->m_isUpdatingCachedSelection = true;
+}
+
+SelectionEditor::CacheUpdateScope::~CacheUpdateScope() {
+ m_editor->m_styleVersion = m_editor->document().styleVersion();
+ m_editor->m_cacheState = CacheState::VisibleSelectionMayBeValid;
+ m_editor->m_isUpdatingCachedSelection = false;
+}
+
+bool SelectionEditor::needsUpdateVisibleSelection() const {
+ DCHECK_EQ(m_domTreeVersion, document().domTreeVersion());
+ if (m_cacheState != CacheState::VisibleSelectionMayBeValid)
+ return true;
+ return m_styleVersion != document().styleVersion();
+}
+
+void SelectionEditor::updateCachedVisibleSelectionIfNeeded() {
+ DCHECK(!m_isUpdatingCachedSelection)
+ << "Recursive update should not be happened.";
+ m_selection.assertValidFor(document());
+
+ // We should use |DCHECK(!document().needsLayoutTreeUpdate())| but following
+ // tests are failed:
+ // - media/track/css-cue-for-video-in-shadow-2.html
+ // - media/track/css-cue-for-video-in-shadow.html
+ // - media/track/cue-style-invalidation.html
+ // - media/track/opera/track/webvtt/parsing/001.html
+ // - media/track/text-track-selection-menu-add-track.html
+ // - media/track/track-css-all-cues.html
+ // - media/track/track-css-cue-lifetime.html [ Crash
+ // Note: Since we |FrameCaret::updateApperance()| is called from
+ // |FrameView::performPostLayoutTasks()|, we check lifecycle against
+ // |AfterPerformLayout| instead of |LayoutClean|.
+ DCHECK_GE(document().lifecycle().state(),
+ DocumentLifecycle::AfterPerformLayout);
+ if (!needsUpdateVisibleSelection())
+ return;
+
+ CacheUpdateScope updatingCache(this);
+ switch (m_cacheState) {
+ case CacheState::VisibleSelectionMayBeValid:
+ // TDOO(yosin): We should study why
+ // createVisibleSelection(m_cachedVisibleSelectionInDOMTree.asSelection())
+ // not
+ // work.
+ m_cachedVisibleSelectionInDOMTree.validate(
+ m_cachedVisibleSelectionInDOMTree.m_granularity);
+ m_cachedVisibleSelectionInFlatTree.validate(
+ m_cachedVisibleSelectionInFlatTree.m_granularity);
+ return;
+ case CacheState::DOMTreeIsChanged:
+ case CacheState::SelectionInDOMTreeIsSource: {
+ // TODO(yosin): We should get rid of |adjustSelectionInFlatTree| in
+ // |SelectionAdjuster|.
+ m_cachedVisibleSelectionInDOMTree = createVisibleSelection(m_selection);
+ m_cachedVisibleSelectionInFlatTree = createVisibleSelection(
+ SelectionInFlatTree::Builder()
+ .setBaseAndExtent(toPositionInFlatTree(m_selection.base()),
+ toPositionInFlatTree(m_selection.extent()))
+ .setAffinity(m_selection.affinity())
+ .setHasTrailingWhitespace(m_selection.hasTrailingWhitespace())
+ .setGranularity(m_selection.granularity())
+ .setIsDirectional(m_selection.isDirectional())
+ .build());
+ return;
+ }
+ case CacheState::DOMTreeIsChanging:
+ NOTREACHED() << "We should not update selection during DOM mutation";
+ return;
+ }
+ NOTREACHED() << "We should handle " << m_cacheState;
}
DEFINE_TRACE(SelectionEditor) {
- visitor->trace(m_document);
visitor->trace(m_frame);
visitor->trace(m_selection);
- visitor->trace(m_selectionInFlatTree);
+ visitor->trace(m_cachedVisibleSelectionInDOMTree);
+ visitor->trace(m_cachedVisibleSelectionInFlatTree);
visitor->trace(m_logicalRange);
+ SynchronousMutationObserver::trace(visitor);
}
} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/editing/SelectionEditor.h ('k') | third_party/WebKit/Source/core/editing/VisibleSelection.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698