| 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 7c833994c93ed98299585562a2afc71afda45e92..e34bba5da6c36786ce4d1ba3d03e039e62164cfa 100644
|
| --- a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
|
| +++ b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
|
| @@ -25,6 +25,8 @@
|
|
|
| #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"
|
| @@ -32,20 +34,30 @@
|
|
|
| namespace blink {
|
|
|
| -SelectionEditor::SelectionEditor(LocalFrame& frame)
|
| - : m_frame(frame), m_observingVisibleSelection(false) {
|
| +SelectionEditor::SelectionEditor(LocalFrame& frame) : m_frame(frame) {
|
| clearVisibleSelection();
|
| }
|
|
|
| SelectionEditor::~SelectionEditor() {}
|
|
|
| +void SelectionEditor::assertSelectionValid() const {
|
| +#if DCHECK_IS_ON()
|
| + // Since We don't track dom tree version during attribute changes, we can't
|
| + // use it for validity of |m_selection|.
|
| + const_cast<SelectionEditor*>(this)->m_selection.m_domTreeVersion =
|
| + document().domTreeVersion();
|
| +#endif
|
| + m_selection.assertValidFor(document());
|
| +}
|
| +
|
| void SelectionEditor::clearVisibleSelection() {
|
| - m_selection = VisibleSelection();
|
| - m_selectionInFlatTree = VisibleSelectionInFlatTree();
|
| + m_selection = SelectionInDOMTree();
|
| + m_cachedVisibleSelectionInDOMTree = VisibleSelection();
|
| + m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
|
| + m_cacheIsDirty = false;
|
| if (!shouldAlwaysUseDirectionalSelection())
|
| return;
|
| - m_selection.setIsDirectional(true);
|
| - m_selectionInFlatTree.setIsDirectional(true);
|
| + m_selection.m_isDirectional = true;
|
| }
|
|
|
| void SelectionEditor::dispose() {
|
| @@ -54,89 +66,114 @@ void SelectionEditor::dispose() {
|
| clearVisibleSelection();
|
| }
|
|
|
| -const Document& SelectionEditor::document() const {
|
| - DCHECK(m_document);
|
| - return *m_document;
|
| +Document& SelectionEditor::document() const {
|
| + DCHECK(lifecycleContext());
|
| + return *lifecycleContext();
|
| }
|
|
|
| template <>
|
| const VisibleSelection& SelectionEditor::visibleSelection<EditingStrategy>()
|
| 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;
|
| + return computeVisibleSelectionInDOMTree();
|
| }
|
|
|
| template <>
|
| const VisibleSelectionInFlatTree&
|
| SelectionEditor::visibleSelection<EditingInFlatTreeStrategy>() const {
|
| + return computeVisibleSelectionInFlatTree();
|
| +}
|
| +
|
| +const VisibleSelection& SelectionEditor::computeVisibleSelectionInDOMTree()
|
| + 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;
|
| + updateCachedVisibleSelectionIfNeeded();
|
| + if (m_cachedVisibleSelectionInDOMTree.isNone())
|
| + return m_cachedVisibleSelectionInDOMTree;
|
| + DCHECK_EQ(m_cachedVisibleSelectionInDOMTree.base().document(), document());
|
| + return m_cachedVisibleSelectionInDOMTree;
|
| }
|
|
|
| -void SelectionEditor::setVisibleSelection(
|
| - const VisibleSelection& newSelection,
|
| - FrameSelection::SetSelectionOptions options) {
|
| - DCHECK(newSelection.isValidFor(document())) << newSelection;
|
| - resetLogicalRange();
|
| - clearDocumentCachedRange();
|
| +const VisibleSelectionInFlatTree&
|
| +SelectionEditor::computeVisibleSelectionInFlatTree() const {
|
| + DCHECK_EQ(frame()->document(), document());
|
| + DCHECK_EQ(frame(), document().frame());
|
| + updateCachedVisibleSelectionIfNeeded();
|
| + if (m_cachedVisibleSelectionInFlatTree.isNone())
|
| + return m_cachedVisibleSelectionInFlatTree;
|
| + DCHECK_EQ(m_cachedVisibleSelectionInFlatTree.base().document(), document());
|
| + return m_cachedVisibleSelectionInFlatTree;
|
| +}
|
|
|
| - m_selection = newSelection;
|
| - if (options & FrameSelection::DoNotAdjustInFlatTree) {
|
| - m_selectionInFlatTree.setWithoutValidation(
|
| - toPositionInFlatTree(m_selection.base()),
|
| - toPositionInFlatTree(m_selection.extent()));
|
| - return;
|
| - }
|
| +const SelectionInDOMTree& SelectionEditor::selectionInDOMTree() const {
|
| + assertSelectionValid();
|
| + return m_selection;
|
| +}
|
|
|
| - SelectionAdjuster::adjustSelectionInFlatTree(&m_selectionInFlatTree,
|
| - m_selection);
|
| +bool SelectionEditor::hasEditableStyle() const {
|
| + return computeVisibleSelectionInDOMTree().hasEditableStyle();
|
| }
|
|
|
| -void SelectionEditor::setVisibleSelection(
|
| - const VisibleSelectionInFlatTree& newSelection,
|
| - FrameSelection::SetSelectionOptions options) {
|
| - DCHECK(newSelection.isValidFor(document())) << newSelection;
|
| - DCHECK(!(options & FrameSelection::DoNotAdjustInFlatTree));
|
| - resetLogicalRange();
|
| - clearDocumentCachedRange();
|
| +bool SelectionEditor::isContentEditable() const {
|
| + return computeVisibleSelectionInDOMTree().isContentEditable();
|
| +}
|
|
|
| - m_selectionInFlatTree = newSelection;
|
| - SelectionAdjuster::adjustSelectionInDOMTree(&m_selection,
|
| - m_selectionInFlatTree);
|
| +bool SelectionEditor::isContentRichlyEditable() const {
|
| + return computeVisibleSelectionInDOMTree().isContentRichlyEditable();
|
| }
|
|
|
| -void SelectionEditor::setWithoutValidation(const Position& base,
|
| - const Position& extent) {
|
| +void SelectionEditor::markCacheDirty() {
|
| + m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
|
| + m_cachedVisibleSelectionInDOMTree = VisibleSelection();
|
| + m_cacheIsDirty = true;
|
| +}
|
| +
|
| +void SelectionEditor::setSelection(const SelectionInDOMTree& newSelection) {
|
| + newSelection.assertValidFor(document());
|
| + if (m_selection == newSelection)
|
| + return;
|
| resetLogicalRange();
|
| - if (base.isNotNull())
|
| - DCHECK_EQ(base.document(), document());
|
| - if (extent.isNotNull())
|
| - DCHECK_EQ(extent.document(), document());
|
| clearDocumentCachedRange();
|
| + markCacheDirty();
|
| + m_selection = newSelection;
|
| +}
|
| +
|
| +void SelectionEditor::didChangeChildren(const ContainerNode&) {
|
| + markCacheDirty();
|
| + didFinishDOMMutation();
|
| +}
|
| +
|
| +void SelectionEditor::didFinishTextChange(const Position& newBase,
|
| + const Position& newExtent) {
|
| + if (newBase == m_selection.m_base && newExtent == m_selection.m_extent) {
|
| + didFinishDOMMutation();
|
| + return;
|
| + }
|
| + m_selection.m_base = newBase;
|
| + m_selection.m_extent = newExtent;
|
| + markCacheDirty();
|
| + didFinishDOMMutation();
|
| +}
|
|
|
| - m_selection.setWithoutValidation(base, extent);
|
| - m_selectionInFlatTree.setWithoutValidation(toPositionInFlatTree(base),
|
| - toPositionInFlatTree(extent));
|
| +void SelectionEditor::didFinishDOMMutation() {
|
| + assertSelectionValid();
|
| }
|
|
|
| void SelectionEditor::documentAttached(Document* document) {
|
| DCHECK(document);
|
| - DCHECK(!m_document) << m_document;
|
| - m_document = document;
|
| + DCHECK(!lifecycleContext()) << lifecycleContext();
|
| + 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_styleVersion = static_cast<uint64_t>(-1);
|
| + m_selection = SelectionInDOMTree();
|
| + m_cachedVisibleSelectionInDOMTree = VisibleSelection();
|
| + m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
|
| + m_cacheIsDirty = false;
|
| }
|
|
|
| void SelectionEditor::resetLogicalRange() {
|
| @@ -157,7 +194,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 {
|
| @@ -165,10 +202,37 @@ 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();
|
| +}
|
| +
|
| +bool SelectionEditor::needsUpdateVisibleSelection() const {
|
| + return m_cacheIsDirty || m_styleVersion != document().styleVersion();
|
| +}
|
| +
|
| +void SelectionEditor::updateCachedVisibleSelectionIfNeeded() const {
|
| + // 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);
|
| + assertSelectionValid();
|
| + if (!needsUpdateVisibleSelection())
|
| + return;
|
| +
|
| + 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());
|
| + m_styleVersion = document().styleVersion();
|
| + m_cacheIsDirty = false;
|
| }
|
|
|
| void SelectionEditor::cacheRangeOfDocument(Range* range) {
|
| @@ -184,12 +248,13 @@ void SelectionEditor::clearDocumentCachedRange() {
|
| }
|
|
|
| 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);
|
| visitor->trace(m_cachedRange);
|
| + SynchronousMutationObserver::trace(visitor);
|
| }
|
|
|
| } // namespace blink
|
|
|