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

Unified Diff: third_party/WebKit/Source/core/editing/FrameSelection.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/FrameSelection.cpp
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index 5cf2922249fa15ffd7d49687da53058e28b18ffc..96318698ec45a22f4467add9a25589e686dc38c5 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -92,6 +92,10 @@ static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame) {
return frame->editor().behavior().shouldConsiderSelectionAsDirectional();
}
+FrameSelection* FrameSelection::create(LocalFrame& frame) {
+ return new FrameSelection(frame);
+}
+
FrameSelection::FrameSelection(LocalFrame& frame)
: m_frame(frame),
m_pendingSelection(PendingSelection::create(*this)),
@@ -106,32 +110,26 @@ FrameSelection::~FrameSelection() {}
const DisplayItemClient& FrameSelection::caretDisplayItemClientForTesting()
const {
- return *m_frameCaret;
-}
-
-const Document& FrameSelection::document() const {
- DCHECK(m_document);
- return *m_document;
+ return m_frameCaret->displayItemClient();
}
-Document& FrameSelection::document() {
- DCHECK(m_document);
- return *m_document;
+Document& FrameSelection::document() const {
+ DCHECK(lifecycleContext());
+ return *lifecycleContext();
}
-// TODO(yosin): To avoid undefined symbols in clang, we explicitly
-// have specialized version of |FrameSelection::visibleSelection<Strategy>|
-// before |FrameSelection::selection()| which refers this.
-template <>
-const VisibleSelection& FrameSelection::visibleSelection<EditingStrategy>()
+const VisibleSelection& FrameSelection::computeVisibleSelectionInDOMTree()
const {
- return m_selectionEditor->visibleSelection<EditingStrategy>();
+ return m_selectionEditor->computeVisibleSelectionInDOMTree();
}
-template <>
const VisibleSelectionInFlatTree&
-FrameSelection::visibleSelection<EditingInFlatTreeStrategy>() const {
- return m_selectionEditor->visibleSelection<EditingInFlatTreeStrategy>();
+FrameSelection::computeVisibleSelectionInFlatTree() const {
+ return m_selectionEditor->computeVisibleSelectionInFlatTree();
+}
+
+const SelectionInDOMTree& FrameSelection::selectionInDOMTree() const {
+ return m_selectionEditor->selectionInDOMTree();
}
Element* FrameSelection::rootEditableElementOrDocumentElement() const {
@@ -148,12 +146,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>();
-}
-
-const VisibleSelectionInFlatTree& FrameSelection::selectionInFlatTree() const {
- return visibleSelection<EditingInFlatTreeStrategy>();
+ // TODO(yosin): We should hoist updateStyleAndLayoutIgnorePendingStylesheets
+ // to caller. See http://crbug.com/590369 for more details.
+ document().updateStyleAndLayoutIgnorePendingStylesheets();
+ return computeVisibleSelectionInDOMTree();
}
void FrameSelection::moveCaretSelection(const IntPoint& point) {
@@ -172,27 +171,22 @@ void FrameSelection::moveCaretSelection(const IntPoint& point) {
setSelection(builder.build(), CloseTyping | ClearTypingStyle | UserTriggered);
}
-template <typename Strategy>
-void FrameSelection::setSelectionAlgorithm(
- const VisibleSelectionTemplate<Strategy>& newSelection,
- 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;
@@ -204,22 +198,26 @@ void FrameSelection::setSelectionAlgorithm(
if (shouldClearTypingStyle)
clearTypingStyle();
- if (m_selectionEditor->visibleSelection<Strategy>() == s) {
- // Even if selection was not changed, selection offsets may have been
- // changed.
- m_frame->inputMethodController().cancelCompositionIfSelectionIsInvalid();
- notifyLayoutObjectOfSelectionChange(userTriggered);
+ const SelectionInDOMTree oldSelectionInDOMTree =
+ m_selectionEditor->selectionInDOMTree();
+ if (oldSelectionInDOMTree == newSelection)
return;
- }
-
- const VisibleSelectionTemplate<Strategy> oldSelection =
- visibleSelection<Strategy>();
- const Position& oldSelectionStart = selection().start();
+ m_selectionEditor->setSelection(newSelection);
- m_selectionEditor->setVisibleSelection(s, options);
- m_frameCaret->setCaretRectNeedsUpdate();
+ // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets
+ // needs to be audited. see http://crbug.com/590369 for more details.
+ document().updateStyleAndLayoutIgnorePendingStylesheets();
- if (!s.isNone() && !(options & DoNotSetFocus)) {
+ 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 (!selection().isNone() && !(options & DoNotSetFocus)) {
setFocusedNodeIfNeeded();
// |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and
// "FocusIn", |m_frame| may associate to another document.
@@ -230,18 +228,12 @@ void FrameSelection::setSelectionAlgorithm(
return;
}
}
-
- if (!(options & DoNotUpdateAppearance)) {
- // Hits in
- // compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html
- DisableCompositingQueryAsserts disabler;
- m_frameCaret->stopCaretBlinkTimer();
- updateAppearance();
- }
+ updateAppearance();
// 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) {
@@ -250,17 +242,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>()) {
- m_frame->inputMethodController().cancelCompositionIfSelectionIsInvalid();
- return;
- }
- m_frame->editor().respondToChangedSelection(oldSelectionStart, options);
if (userTriggered == UserTriggered) {
ScrollAlignment alignment;
@@ -273,6 +256,10 @@ void FrameSelection::setSelectionAlgorithm(
? ScrollAlignment::alignTopAlways
: ScrollAlignment::alignToEdgeIfNeeded;
+ // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
+ // needs to be audited. See http://crbug.com/590369 for more details.
+ document().updateStyleAndLayoutIgnorePendingStylesheets();
+
revealSelection(alignment, RevealExtent);
}
@@ -283,48 +270,26 @@ 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), 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), 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())
+ .setHasTrailingWhitespace(newSelection.hasTrailingWhitespace());
+ return setSelection(builder.build(), options, align, granularity);
}
void FrameSelection::setSelection(const VisibleSelection& newSelection,
SetSelectionOptions options,
CursorAlignOnScroll align,
TextGranularity granularity) {
- setSelectionAlgorithm<EditingStrategy>(newSelection, options, align,
- granularity);
+ setSelection(newSelection.asSelection(), options, align, granularity);
}
void FrameSelection::setSelection(
@@ -332,282 +297,29 @@ void FrameSelection::setSelection(
SetSelectionOptions options,
CursorAlignOnScroll align,
TextGranularity granularity) {
- setSelectionAlgorithm<EditingInFlatTreeStrategy>(newSelection, options, align,
- granularity);
-}
-
-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());
-}
-
-static Position computePositionForChildrenRemoval(const Position& position,
- ContainerNode& container) {
- Node* node = position.computeContainerNode();
- if (container.containsIncludingHostElements(*node))
- return Position::firstPositionInNode(&container);
- return position;
+ setSelection(newSelection.asSelection(), options, align, granularity);
}
void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) {
- if (isNone() || !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();
- 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 (!container.inActiveDocument())
return;
- if (selection().isBaseFirst())
- m_selectionEditor->setWithoutValidation(newStart, newEnd);
- else
- m_selectionEditor->setWithoutValidation(newEnd, newStart);
- m_frameCaret->setCaretRectNeedsUpdate();
- if (document().isRunningExecCommand())
- return;
- 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 (isNone() || !node.inActiveDocument())
- return;
-
- respondToNodeModification(
- node, removingNodeRemovesPosition(node, selection().base()),
- removingNodeRemovesPosition(node, selection().extent()),
- removingNodeRemovesPosition(node, selection().start()),
- removingNodeRemovesPosition(node, selection().end()));
-
- m_frameCaret->nodeWillBeRemoved(node);
-}
-
-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);
- m_frameCaret->setCaretRectNeedsUpdate();
-
// TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
// |Editor| class.
if (!document().isRunningExecCommand())
TypingCommand::closeTyping(m_frame);
}
-static Position updatePositionAfterAdoptingTextReplacement(
- const Position& position,
- CharacterData* node,
- unsigned offset,
- unsigned oldLength,
- unsigned newLength) {
- if (!position.anchorNode() || position.anchorNode() != node ||
- !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());
- // 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();
-
- // CharacterNode in VisibleSelection must be Text node, because Comment
- // and ProcessingInstruction node aren't visible.
- return Position(toText(node), positionOffset);
-}
-
-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 (isNone() || !node || !node->isConnected())
- 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);
-}
-
-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);
-
- return position;
-}
-
-void FrameSelection::didMergeTextNodes(const Text& oldNode, unsigned offset) {
- if (isNone() || !oldNode.isConnected())
- 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);
-}
-
-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 FrameSelection::didSplitTextNode(const Text& oldNode) {
- if (isNone() || !oldNode.isConnected())
- 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())
+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())
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,20 +408,17 @@ void FrameSelection::clear() {
m_granularity = CharacterGranularity;
if (m_granularityStrategy)
m_granularityStrategy->Clear();
- setSelection(SelectionInDOMTree());
+ setSelection(VisibleSelection());
}
void FrameSelection::documentAttached(Document* document) {
DCHECK(document);
- DCHECK(!m_document) << "FrameSelection is already attached to " << m_document;
- m_document = document;
- m_useSecureKeyboardEntryWhenActive = false;
+ m_frameCaret->documentAttached(document);
m_selectionEditor->documentAttached(document);
+ setContext(document);
}
-void FrameSelection::documentDetached(const Document& document) {
- DCHECK_EQ(m_document, document);
- m_document = nullptr;
+void FrameSelection::contextDestroyed(Document*) {
m_granularity = CharacterGranularity;
LayoutViewItem view = m_frame->contentLayoutItem();
@@ -717,19 +426,18 @@ void FrameSelection::documentDetached(const Document& document) {
view.clearSelection();
clearTypingStyle();
- m_selectionEditor->documentDetached(document);
- m_frameCaret->documentDetached();
}
LayoutBlock* FrameSelection::caretLayoutObject() const {
- DCHECK(selection().isValidFor(document()));
- if (!isCaret())
+ DCHECK(isAvailable());
+ const VisibleSelection& selection = computeVisibleSelectionInDOMTree();
+ if (!selection.isCaret())
return nullptr;
- return CaretBase::caretLayoutObject(selection().start().anchorNode());
+ return CaretBase::caretLayoutObject(selection.start().anchorNode());
}
IntRect FrameSelection::absoluteCaretBounds() {
- DCHECK(selection().isValidFor(*m_frame->document()));
+ DCHECK(isAvailable());
return m_frameCaret->absoluteCaretBounds();
}
@@ -737,22 +445,18 @@ void FrameSelection::invalidateCaretRect(bool forceInvalidation) {
m_frameCaret->invalidateCaretRect(forceInvalidation);
}
-void FrameSelection::dataWillChange(const CharacterData& node) {
- m_frameCaret->dataWillChange(node);
-}
-
void FrameSelection::paintCaret(GraphicsContext& context,
const LayoutPoint& paintOffset) {
m_frameCaret->paintCaret(context, paintOffset);
}
bool FrameSelection::contains(const LayoutPoint& point) {
- if (document().layoutViewItem().isNull())
+ if (!isAvailable())
return false;
// Treat a collapsed selection like no selection.
const VisibleSelectionInFlatTree& visibleSelection =
- this->visibleSelection<EditingInFlatTreeStrategy>();
+ computeVisibleSelectionInFlatTree();
if (!visibleSelection.isRange())
return false;
@@ -783,10 +487,12 @@ bool FrameSelection::contains(const LayoutPoint& point) {
// Workaround for the fact that it's hard to delete a frame.
// Call this after doing user-triggered selections to make it easy to delete the
-// frame you entirely selected. Can't do this implicitly as part of every
-// setSelection call because in some contexts it might not be good for the focus
-// to move to another frame. So instead we call it from places where we are
-// selecting with the mouse or the keyboard after setting the selection.
+// frame you entirely selected.
+// Can't do this implicitly as part of every setSelection call because in some
+// contexts it might not be good
+// for the focus to move to another frame. So instead we call it from places
+// where we are selecting with the
+// mouse or the keyboard after setting the selection.
void FrameSelection::selectFrameElementInParentIfFullySelected() {
// Find the parent frame; if there is none, then we have nothing to do.
Frame* parent = m_frame->tree().parent();
@@ -912,6 +618,18 @@ void FrameSelection::selectAll() {
notifyLayoutObjectOfSelectionChange(UserTriggered);
}
+bool FrameSelection::setSelectedRange(Range* range,
+ TextAffinity affinity,
+ SelectionDirectionalMode directional,
+ SetSelectionOptions options) {
+ if (!range || !range->isConnected())
+ return false;
+ DCHECK_EQ(range->startContainer()->document(),
+ range->endContainer()->document());
+ return setSelectedRange(EphemeralRange(range), affinity, directional,
+ options);
+}
+
bool FrameSelection::setSelectedRange(const EphemeralRange& range,
TextAffinity affinity,
SelectionDirectionalMode directional,
@@ -1001,9 +719,8 @@ void FrameSelection::pageActivationChanged() {
}
void FrameSelection::updateSecureKeyboardEntryIfActive() {
- if (!isFocusedAndActive())
- return;
- setUseSecureKeyboardEntry(m_useSecureKeyboardEntryWhenActive);
+ if (isFocusedAndActive())
+ setUseSecureKeyboardEntry(m_useSecureKeyboardEntryWhenActive);
}
void FrameSelection::setUseSecureKeyboardEntryWhenActive(
@@ -1042,11 +759,15 @@ void FrameSelection::commitAppearanceIfNeeded(LayoutView& layoutView) {
return m_pendingSelection->commit(layoutView);
}
-void FrameSelection::updateAppearance() {
- m_frameCaret->updateAppearance();
+void FrameSelection::didLayout() {
+ DCHECK_GE(document().lifecycle().state(),
+ DocumentLifecycle::AfterPerformLayout);
+ updateAppearance();
+}
- if (m_frame->contentLayoutItem().isNull())
- return;
+void FrameSelection::updateAppearance() {
+ DCHECK(!m_frame->contentLayoutItem().isNull());
+ m_frameCaret->setCaretRectNeedsUpdate();
m_pendingSelection->setHasPendingSelection();
}
@@ -1093,7 +814,7 @@ void FrameSelection::setFocusedNodeIfNeeded() {
static String extractSelectedText(const FrameSelection& selection,
TextIteratorBehavior behavior) {
const VisibleSelectionInFlatTree& visibleSelection =
- selection.visibleSelection<EditingInFlatTreeStrategy>();
+ selection.computeVisibleSelectionInFlatTree();
const EphemeralRangeInFlatTree& range =
visibleSelection.toNormalizedEphemeralRange();
// We remove '\0' characters because they are not visibly rendered to the
@@ -1103,7 +824,7 @@ static String extractSelectedText(const FrameSelection& selection,
String FrameSelection::selectedHTMLForClipboard() const {
const VisibleSelectionInFlatTree& visibleSelection =
- this->visibleSelection<EditingInFlatTreeStrategy>();
+ computeVisibleSelectionInFlatTree();
const EphemeralRangeInFlatTree& range =
visibleSelection.toNormalizedEphemeralRange();
return createMarkup(range.startPosition(), range.endPosition(),
@@ -1242,10 +963,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());
@@ -1270,6 +987,29 @@ void FrameSelection::setShouldShowBlockCursor(bool shouldShowBlockCursor) {
m_frameCaret->setShouldShowBlockCursor(shouldShowBlockCursor);
}
+template <typename Strategy>
+VisibleSelectionTemplate<Strategy> FrameSelection::validateSelection(
+ const VisibleSelectionTemplate<Strategy>& selection) {
+ if (selection.isNone())
+ return selection;
+
+ const PositionTemplate<Strategy> base = selection.base();
+ const PositionTemplate<Strategy> extent = selection.extent();
+ bool isBaseValid = base.document() == document();
+ bool isExtentValid = extent.document() == document();
+
+ if (isBaseValid && isExtentValid)
+ return selection;
+
+ VisibleSelectionTemplate<Strategy> newSelection;
+ if (isBaseValid) {
+ newSelection.setWithoutValidation(base, base);
+ } else if (isExtentValid) {
+ newSelection.setWithoutValidation(extent, extent);
+ }
+ return newSelection;
+}
+
#ifndef NDEBUG
void FrameSelection::showTreeForThis() const {
@@ -1279,12 +1019,12 @@ void FrameSelection::showTreeForThis() const {
#endif
DEFINE_TRACE(FrameSelection) {
- visitor->trace(m_document);
visitor->trace(m_frame);
visitor->trace(m_pendingSelection);
visitor->trace(m_selectionEditor);
visitor->trace(m_typingStyle);
visitor->trace(m_frameCaret);
+ SynchronousMutationObserver::trace(visitor);
}
void FrameSelection::scheduleVisualUpdate() const {
@@ -1305,8 +1045,7 @@ bool FrameSelection::selectWordAroundPosition(const VisiblePosition& position) {
.collapse(start.toPositionWithAffinity())
.extend(end.deepEquivalent())
.build(),
- CloseTyping | ClearTypingStyle,
- CursorAlignOnScroll::IfNeeded, WordGranularity);
+ WordGranularity);
return true;
}
}
@@ -1363,8 +1102,7 @@ void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition,
if (newSelection.isNone())
return;
- setSelection(newSelection, CloseTyping | ClearTypingStyle,
- CursorAlignOnScroll::IfNeeded, granularity);
+ setSelection(newSelection, granularity);
}
void FrameSelection::updateIfNeeded() {
« 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