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 5956a8b6601e1715e2faed739d94f128389642fc..6f1c25c92607a601ce32e8283e8436f1818ce3be 100644 |
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp |
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp |
@@ -101,14 +101,24 @@ FrameSelection::FrameSelection(LocalFrame* frame) |
, m_frameCaret(new FrameCaret(frame)) |
{ |
DCHECK(frame); |
- if (shouldAlwaysUseDirectionalSelection(m_frame)) |
tkent
2016/06/07 23:41:59
Why can we remove this code block?
yosin_UTC9
2016/06/08 04:06:10
Setting |VisibleSelection.isDirectional| done in |
|
- m_selectionEditor->setIsDirectional(true); |
} |
FrameSelection::~FrameSelection() |
{ |
} |
+const Document& FrameSelection::document() const |
+{ |
+ DCHECK(m_document); |
+ return *m_document; |
+} |
+ |
+Document& FrameSelection::document() |
+{ |
+ DCHECK(m_document); |
+ return *m_document; |
+} |
+ |
template <> |
VisiblePosition FrameSelection::originalBase<EditingStrategy>() const |
{ |
@@ -139,7 +149,7 @@ const VisibleSelectionInFlatTree& FrameSelection::visibleSelection<EditingInFlat |
Element* FrameSelection::rootEditableElementOrDocumentElement() const |
{ |
Element* selectionRoot = selection().rootEditableElement(); |
- return selectionRoot ? selectionRoot : m_frame->document()->documentElement(); |
+ return selectionRoot ? selectionRoot : document().documentElement(); |
} |
ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const |
@@ -274,6 +284,8 @@ void FrameSelection::setNonDirectionalSelectionIfNeeded(const VisibleSelectionIn |
template <typename Strategy> |
void FrameSelection::setSelectionAlgorithm(const VisibleSelectionTemplate<Strategy>& newSelection, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity) |
{ |
+ DCHECK(isAvailable()); |
+ const Document& currentDocument = document(); |
if (m_granularityStrategy && (options & FrameSelection::DoNotClearStrategy) == 0) |
m_granularityStrategy->Clear(); |
bool closeTyping = options & CloseTyping; |
@@ -284,26 +296,6 @@ void FrameSelection::setSelectionAlgorithm(const VisibleSelectionTemplate<Strate |
if (shouldAlwaysUseDirectionalSelection(m_frame)) |
s.setIsDirectional(true); |
- // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at |
tkent
2016/06/07 23:41:59
Why can we remove this code block?
yosin_UTC9
2016/06/08 04:06:10
This can't be happened any more as proofed by no l
|
- // |FrameSelection::setSelection| |
- // if |document->frame()| == |m_frame| we can get into an infinite loop |
- if (s.base().anchorNode()) { |
- Document& document = *s.base().document(); |
- // TODO(hajimehoshi): validateSelection already checks if the selection |
- // is valid, thus we don't need this 'if' clause any more. |
- if (document.frame() && document.frame() != m_frame && document != m_frame->document()) { |
- document.frame()->selection().setSelection(s, options, align, granularity); |
- // It's possible that during the above set selection, this |
- // |FrameSelection| has been modified by |
- // |selectFrameElementInParentIfFullySelected|, but that the |
- // selection is no longer valid since the frame is about to be |
- // destroyed. If this is the case, clear our selection. |
- if (!document.frame()->host() && !selection().isNonOrphanedCaretOrRange()) |
- clear(); |
- return; |
- } |
- } |
- |
m_granularity = granularity; |
// TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
@@ -331,8 +323,17 @@ void FrameSelection::setSelectionAlgorithm(const VisibleSelectionTemplate<Strate |
else |
m_frameCaret->clear(); |
- if (!s.isNone() && !(options & DoNotSetFocus)) |
+ if (!s.isNone() && !(options & DoNotSetFocus)) { |
setFocusedNodeIfNeeded(); |
+ // |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and |
+ // "FocusIn", |m_frame| may associate to another document. |
+ if (!isAvailable() || document() != currentDocument) { |
+ // Once we get test case to reach here, we should change this |
+ // if-statement to |DCHECK()|. |
+ NOTREACHED(); |
+ return; |
+ } |
+ } |
if (!(options & DoNotUpdateAppearance)) { |
// Hits in compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html |
@@ -346,6 +347,12 @@ void FrameSelection::setSelectionAlgorithm(const VisibleSelectionTemplate<Strate |
m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); |
// This may dispatch a synchronous focus-related events. |
selectFrameElementInParentIfFullySelected(); |
+ if (!isAvailable() || document() != currentDocument) { |
+ // editing/selection/selectallchildren-crash.html and |
+ // editing/selection/longpress-selection-in-iframe-removed-crash.html |
+ // reach here. |
+ return; |
+ } |
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 |
@@ -480,7 +487,7 @@ void FrameSelection::respondToNodeModification(Node& node, bool baseRemoved, boo |
// TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
// |Editor| class. |
- if (!m_frame->document()->isRunningExecCommand()) |
+ if (!document().isRunningExecCommand()) |
TypingCommand::closeTyping(m_frame); |
} |
@@ -584,7 +591,7 @@ void FrameSelection::updateSelectionIfNeeded(const Position& base, const Positio |
return; |
// TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
// |Editor| class. |
- if (!m_frame->document()->isRunningExecCommand()) |
+ if (!document().isRunningExecCommand()) |
TypingCommand::closeTyping(m_frame); |
VisibleSelection newSelection; |
if (selection().isBaseFirst()) |
@@ -663,8 +670,17 @@ void FrameSelection::clear() |
setSelection(VisibleSelection()); |
} |
-void FrameSelection::prepareForDestruction() |
+void FrameSelection::documentAttached(Document* document) |
+{ |
tkent
2016/06/07 23:41:59
We should have DCHECK(document).
yosin_UTC9
2016/06/08 04:06:10
Done.
|
+ DCHECK(!m_document) << "FrameSelection is already attached to " << m_document; |
+ m_document = document; |
+ m_selectionEditor->documentAttached(document); |
+} |
+ |
+void FrameSelection::documentDetached(const Document& document) |
{ |
+ DCHECK_EQ(m_document, document); |
+ m_document = nullptr; |
m_originalBase = VisiblePosition(); |
m_originalBaseInFlatTree = VisiblePositionInFlatTree(); |
m_granularity = CharacterGranularity; |
@@ -673,14 +689,14 @@ void FrameSelection::prepareForDestruction() |
if (!view.isNull()) |
view.clearSelection(); |
- setSelection(VisibleSelection(), CloseTyping | ClearTypingStyle | DoNotUpdateAppearance); |
- m_selectionEditor->dispose(); |
- m_frameCaret->prepareForDestruction(); |
+ clearTypingStyle(); |
+ m_selectionEditor->documentDetached(document); |
+ m_frameCaret->documentDetached(); |
} |
LayoutBlock* FrameSelection::caretLayoutObject() const |
{ |
- DCHECK(selection().isValidFor(*m_frame->document())); |
+ DCHECK(selection().isValidFor(document())); |
if (!isCaret()) |
return nullptr; |
return CaretBase::caretLayoutObject(selection().start().anchorNode()); |
@@ -709,8 +725,7 @@ void FrameSelection::paintCaret(GraphicsContext& context, const LayoutPoint& pai |
bool FrameSelection::contains(const LayoutPoint& point) |
{ |
- Document* document = m_frame->document(); |
- if (document->layoutViewItem().isNull()) |
+ if (document().layoutViewItem().isNull()) |
return false; |
// Treat a collapsed selection like no selection. |
@@ -720,7 +735,7 @@ bool FrameSelection::contains(const LayoutPoint& point) |
HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); |
HitTestResult result(request, point); |
- document->layoutViewItem().hitTest(result); |
+ document().layoutViewItem().hitTest(result); |
Node* innerNode = result.innerNode(); |
if (!innerNode || !innerNode->layoutObject()) |
return false; |
@@ -803,10 +818,8 @@ static Node* nonBoundaryShadowTreeRootNode(const Position& position) |
void FrameSelection::selectAll() |
{ |
- Document* document = m_frame->document(); |
- |
- if (isHTMLSelectElement(document->focusedElement())) { |
- HTMLSelectElement* selectElement = toHTMLSelectElement(document->focusedElement()); |
+ if (isHTMLSelectElement(document().focusedElement())) { |
+ HTMLSelectElement* selectElement = toHTMLSelectElement(document().focusedElement()); |
if (selectElement->canSelectAll()) { |
selectElement->selectAll(); |
return; |
@@ -826,18 +839,19 @@ void FrameSelection::selectAll() |
if (root) { |
selectStartTarget = root->shadowHost(); |
} else { |
- root = document->documentElement(); |
- selectStartTarget = document->body(); |
+ root = document().documentElement(); |
+ selectStartTarget = document().body(); |
} |
} |
if (!root || editingIgnoresContent(root)) |
return; |
if (selectStartTarget) { |
+ const Document& expectedDocument = document(); |
if (selectStartTarget->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart)) != DispatchEventResult::NotCanceled) |
return; |
// |root| may be detached due to selectstart event. |
- if (!root->inShadowIncludingDocument() || root->document() != document) |
+ if (!root->inShadowIncludingDocument() || expectedDocument != root->document()) |
return; |
} |
@@ -884,7 +898,7 @@ bool FrameSelection::isInPasswordField() const |
void FrameSelection::notifyAccessibilityForSelectionChange() |
{ |
if (selection().start().isNotNull() && selection().end().isNotNull()) { |
- if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) |
+ if (AXObjectCache* cache = document().existingAXObjectCache()) |
cache->selectionChanged(selection().start().computeContainerNode()); |
} |
} |
@@ -905,20 +919,19 @@ void FrameSelection::notifyEventHandlerForSelectionChange() |
void FrameSelection::focusedOrActiveStateChanged() |
{ |
bool activeAndFocused = isFocusedAndActive(); |
- Document* document = m_frame->document(); |
// Trigger style invalidation from the focused element. Even though |
// the focused element hasn't changed, the evaluation of focus pseudo |
// selectors are dependent on whether the frame is focused and active. |
- if (Element* element = document->focusedElement()) |
+ if (Element* element = document().focusedElement()) |
element->focusStateChanged(); |
- document->updateStyleAndLayoutTree(); |
+ document().updateStyleAndLayoutTree(); |
// Because LayoutObject::selectionBackgroundColor() and |
// LayoutObject::selectionForegroundColor() check if the frame is active, |
// we have to update places those colors were painted. |
- LayoutViewItem view = document->layoutViewItem(); |
+ LayoutViewItem view = document().layoutViewItem(); |
if (!view.isNull()) |
view.invalidatePaintForSelection(); |
@@ -933,7 +946,7 @@ void FrameSelection::focusedOrActiveStateChanged() |
m_frame->eventHandler().capsLockStateMayHaveChanged(); |
// Secure keyboard entry is set by the active frame. |
- if (document->useSecureKeyboardEntryWhenActive()) |
+ if (document().useSecureKeyboardEntryWhenActive()) |
setUseSecureKeyboardEntry(activeAndFocused); |
} |
@@ -944,8 +957,8 @@ void FrameSelection::pageActivationChanged() |
void FrameSelection::updateSecureKeyboardEntryIfActive() |
{ |
- if (m_frame->document() && isFocusedAndActive()) |
- setUseSecureKeyboardEntry(m_frame->document()->useSecureKeyboardEntryWhenActive()); |
+ if (isFocusedAndActive()) |
+ setUseSecureKeyboardEntry(document().useSecureKeyboardEntryWhenActive()); |
} |
void FrameSelection::setUseSecureKeyboardEntry(bool enable) |
@@ -1023,7 +1036,7 @@ void FrameSelection::setFocusedNodeIfNeeded() |
if (Element* target = rootEditableElement()) { |
// Walk up the DOM tree to search for a node to focus. |
- m_frame->document()->updateStyleAndLayoutTreeIgnorePendingStylesheets(); |
+ document().updateStyleAndLayoutTreeIgnorePendingStylesheets(); |
while (target) { |
// We don't want to set focus on a subframe when selecting in a parent frame, |
// so add the !isFrameElement check here. There's probably a better way to make this |
@@ -1034,7 +1047,7 @@ void FrameSelection::setFocusedNodeIfNeeded() |
} |
target = target->parentOrShadowHostElement(); |
} |
- m_frame->document()->clearFocusedElement(); |
+ document().clearFocusedElement(); |
} |
if (caretBrowsing) |
@@ -1119,7 +1132,7 @@ static HTMLFormElement* scanForForm(Node* start) |
HTMLFormElement* FrameSelection::currentForm() const |
{ |
// Start looking either at the active (first responder) node, or where the selection is. |
- Node* start = m_frame->document()->focusedElement(); |
+ Node* start = document().focusedElement(); |
if (!start) |
start = this->start().anchorNode(); |
if (!start) |
@@ -1238,6 +1251,7 @@ void FrameSelection::showTreeForThis() const |
DEFINE_TRACE(FrameSelection) |
{ |
+ visitor->trace(m_document); |
visitor->trace(m_frame); |
visitor->trace(m_pendingSelection); |
visitor->trace(m_selectionEditor); |