summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/editing/FrameSelection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/editing/FrameSelection.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/editing/FrameSelection.cpp257
1 files changed, 141 insertions, 116 deletions
diff --git a/chromium/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/chromium/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index 05a32fb61b3..e8802b27504 100644
--- a/chromium/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/chromium/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -27,8 +27,8 @@
#include "core/editing/FrameSelection.h"
#include <stdio.h>
-#include "HTMLNames.h"
#include "bindings/v8/ExceptionState.h"
+#include "core/HTMLNames.h"
#include "core/accessibility/AXObjectCache.h"
#include "core/css/StylePropertySet.h"
#include "core/dom/CharacterData.h"
@@ -45,7 +45,9 @@
#include "core/editing/TypingCommand.h"
#include "core/editing/VisibleUnits.h"
#include "core/editing/htmlediting.h"
-#include "core/frame/DOMWindow.h"
+#include "core/frame/LocalDOMWindow.h"
+#include "core/frame/LocalFrame.h"
+#include "core/html/HTMLBodyElement.h"
#include "core/html/HTMLFormElement.h"
#include "core/html/HTMLFrameElementBase.h"
#include "core/html/HTMLInputElement.h"
@@ -53,7 +55,6 @@
#include "core/page/EditorClient.h"
#include "core/page/EventHandler.h"
#include "core/page/FocusController.h"
-#include "core/frame/Frame.h"
#include "core/page/FrameTree.h"
#include "core/frame/FrameView.h"
#include "core/page/Page.h"
@@ -62,6 +63,7 @@
#include "core/rendering/HitTestRequest.h"
#include "core/rendering/HitTestResult.h"
#include "core/rendering/InlineTextBox.h"
+#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderText.h"
#include "core/rendering/RenderTheme.h"
#include "core/rendering/RenderView.h"
@@ -82,14 +84,15 @@ static inline LayoutUnit NoXPosForVerticalArrowNavigation()
return LayoutUnit::min();
}
-static inline bool shouldAlwaysUseDirectionalSelection(Frame* frame)
+static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame)
{
return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirectional();
}
-FrameSelection::FrameSelection(Frame* frame)
+FrameSelection::FrameSelection(LocalFrame* frame)
: m_frame(frame)
, m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation())
+ , m_observingVisibleSelection(false)
, m_granularity(CharacterGranularity)
, m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired)
, m_absCaretBoundsDirty(true)
@@ -102,6 +105,15 @@ FrameSelection::FrameSelection(Frame* frame)
m_selection.setIsDirectional(true);
}
+FrameSelection::~FrameSelection()
+{
+#if !ENABLE(OILPAN)
+ // Oilpan: No need to clear out VisibleSelection observer;
+ // it is finalized as a part object of FrameSelection.
+ stopObservingVisibleSelectionChangeIfNecessary();
+#endif
+}
+
Element* FrameSelection::rootEditableElementOrDocumentElement() const
{
Element* selectionRoot = m_selection.rootEditableElement();
@@ -115,7 +127,7 @@ Node* FrameSelection::rootEditableElementOrTreeScopeRootNode() const
return selectionRoot;
Node* node = m_selection.base().containerNode();
- return node ? node->treeScope().rootNode() : 0;
+ return node ? &node->treeScope().rootNode() : 0;
}
void FrameSelection::moveTo(const VisiblePosition &pos, EUserTriggered userTriggered, CursorAlignOnScroll align)
@@ -137,20 +149,6 @@ void FrameSelection::moveTo(const Position &pos, EAffinity affinity, EUserTrigge
setSelection(VisibleSelection(pos, affinity, m_selection.isDirectional()), options);
}
-void FrameSelection::moveTo(const Range *r, EAffinity affinity, EUserTriggered userTriggered)
-{
- SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
- VisibleSelection selection = r ? VisibleSelection(r->startPosition(), r->endPosition(), affinity) : VisibleSelection(Position(), Position(), affinity);
- setSelection(selection, options);
-}
-
-void FrameSelection::moveTo(const Position &base, const Position &extent, EAffinity affinity, EUserTriggered userTriggered)
-{
- const bool selectionHasDirection = true;
- SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
- setSelection(VisibleSelection(base, extent, affinity, selectionHasDirection), options);
-}
-
static void adjustEndpointsAtBidiBoundary(VisiblePosition& visibleBase, VisiblePosition& visibleExtent)
{
RenderedPosition base(visibleBase);
@@ -162,7 +160,7 @@ static void adjustEndpointsAtBidiBoundary(VisiblePosition& visibleBase, VisibleP
if (base.atLeftBoundaryOfBidiRun()) {
if (!extent.atRightBoundaryOfBidiRun(base.bidiLevelOnRight())
&& base.isEquivalent(extent.leftBoundaryOfBidiRun(base.bidiLevelOnRight()))) {
- visibleBase = base.positionAtLeftBoundaryOfBiDiRun();
+ visibleBase = VisiblePosition(base.positionAtLeftBoundaryOfBiDiRun());
return;
}
return;
@@ -171,19 +169,19 @@ static void adjustEndpointsAtBidiBoundary(VisiblePosition& visibleBase, VisibleP
if (base.atRightBoundaryOfBidiRun()) {
if (!extent.atLeftBoundaryOfBidiRun(base.bidiLevelOnLeft())
&& base.isEquivalent(extent.rightBoundaryOfBidiRun(base.bidiLevelOnLeft()))) {
- visibleBase = base.positionAtRightBoundaryOfBiDiRun();
+ visibleBase = VisiblePosition(base.positionAtRightBoundaryOfBiDiRun());
return;
}
return;
}
if (extent.atLeftBoundaryOfBidiRun() && extent.isEquivalent(base.leftBoundaryOfBidiRun(extent.bidiLevelOnRight()))) {
- visibleExtent = extent.positionAtLeftBoundaryOfBiDiRun();
+ visibleExtent = VisiblePosition(extent.positionAtLeftBoundaryOfBiDiRun());
return;
}
if (extent.atRightBoundaryOfBidiRun() && extent.isEquivalent(base.rightBoundaryOfBidiRun(extent.bidiLevelOnLeft()))) {
- visibleExtent = extent.positionAtRightBoundaryOfBiDiRun();
+ visibleExtent = VisiblePosition(extent.positionAtRightBoundaryOfBiDiRun());
return;
}
}
@@ -238,7 +236,7 @@ void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec
if (s.base().anchorNode()) {
Document& document = *s.base().document();
if (document.frame() && document.frame() != m_frame && document != m_frame->document()) {
- RefPtr<Frame> guard = document.frame();
+ RefPtr<LocalFrame> guard = document.frame();
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
@@ -274,6 +272,9 @@ void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec
if (!(options & DoNotUpdateAppearance)) {
m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
+ // Hits in compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html
+ DisableCompositingQueryAsserts disabler;
updateAppearance();
}
@@ -335,9 +336,9 @@ void FrameSelection::respondToNodeModification(Node& node, bool baseRemoved, boo
Position start = m_selection.start();
Position end = m_selection.end();
if (startRemoved)
- updatePositionForNodeRemoval(start, &node);
+ updatePositionForNodeRemoval(start, node);
if (endRemoved)
- updatePositionForNodeRemoval(end, &node);
+ updatePositionForNodeRemoval(end, node);
if (start.isNotNull() && end.isNotNull()) {
if (m_selection.isBaseFirst())
@@ -357,7 +358,7 @@ void FrameSelection::respondToNodeModification(Node& node, bool baseRemoved, boo
m_selection.setWithoutValidation(m_selection.start(), m_selection.end());
else
m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
- } else if (RefPtr<Range> range = m_selection.firstRange()) {
+ } else if (RefPtrWillBeRawPtr<Range> range = m_selection.firstRange()) {
TrackExceptionState exceptionState;
Range::CompareResults compareResult = range->compareNode(&node, exceptionState);
if (!exceptionState.hadException() && (compareResult == Range::NODE_BEFORE_AND_AFTER || compareResult == Range::NODE_INSIDE)) {
@@ -393,7 +394,7 @@ static Position updatePositionAfterAdoptingTextReplacement(const Position& posit
if (positionOffset > offset + oldLength)
positionOffset = positionOffset - oldLength + newLength;
- ASSERT(positionOffset <= node->length());
+ ASSERT_WITH_SECURITY_IMPLICATION(positionOffset <= node->length());
// CharacterNode in VisibleSelection must be Text node, because Comment
// and ProcessingInstruction node aren't visible.
return Position(toText(node), positionOffset);
@@ -470,7 +471,6 @@ void FrameSelection::updateSelectionIfNeeded(const Position& base, const Positio
return;
VisibleSelection newSelection;
newSelection.setWithoutValidation(base, extent);
- m_frame->document()->updateLayout();
setSelection(newSelection, DoNotSetFocus);
}
@@ -500,6 +500,8 @@ TextDirection FrameSelection::directionOfSelection()
void FrameSelection::didChangeFocus()
{
+ // Hits in virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disabled.html
+ DisableCompositingQueryAsserts disabler;
updateAppearance();
}
@@ -598,7 +600,7 @@ VisiblePosition FrameSelection::nextWordPositionForPlatform(const VisiblePositio
static void adjustPositionForUserSelectAll(VisiblePosition& pos, bool isForward)
{
if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(pos.deepEquivalent().anchorNode()))
- pos = isForward ? positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary) : positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary);
+ pos = VisiblePosition(isForward ? positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary) : positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
}
VisiblePosition FrameSelection::modifyExtendingRight(TextGranularity granularity)
@@ -935,18 +937,18 @@ static bool isBoundary(TextGranularity granularity)
bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered)
{
if (userTriggered == UserTriggered) {
- FrameSelection trialFrameSelection;
- trialFrameSelection.setSelection(m_selection);
- trialFrameSelection.modify(alter, direction, granularity, NotUserTriggered);
+ OwnPtrWillBeRawPtr<FrameSelection> trialFrameSelection = FrameSelection::create();
+ trialFrameSelection->setSelection(m_selection);
+ trialFrameSelection->modify(alter, direction, granularity, NotUserTriggered);
- if (trialFrameSelection.selection().isRange() && m_selection.isCaret() && !dispatchSelectStart())
+ if (trialFrameSelection->selection().isRange() && m_selection.isCaret() && !dispatchSelectStart())
return false;
}
willBeModified(alter, direction);
bool wasRange = m_selection.isRange();
- Position originalStartPosition = m_selection.start();
+ VisiblePosition originalStartPosition = m_selection.visibleStart();
VisiblePosition position;
switch (direction) {
case DirectionRight:
@@ -1005,7 +1007,7 @@ bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, Tex
VisibleSelection newSelection = m_selection;
newSelection.setExtent(position);
if (m_selection.isBaseFirst() != newSelection.isBaseFirst())
- position = m_selection.base();
+ position = m_selection.visibleBase();
}
// Standard Mac behavior when extending to a boundary is grow the selection rather than leaving the
@@ -1049,9 +1051,9 @@ bool FrameSelection::modify(EAlteration alter, unsigned verticalDistance, Vertic
return false;
if (userTriggered == UserTriggered) {
- FrameSelection trialFrameSelection;
- trialFrameSelection.setSelection(m_selection);
- trialFrameSelection.modify(alter, verticalDistance, direction, NotUserTriggered);
+ OwnPtrWillBeRawPtr<FrameSelection> trialFrameSelection = FrameSelection::create();
+ trialFrameSelection->setSelection(m_selection);
+ trialFrameSelection->modify(alter, verticalDistance, direction, NotUserTriggered);
}
willBeModified(alter, direction == DirectionUp ? DirectionBackward : DirectionForward);
@@ -1144,7 +1146,7 @@ LayoutUnit FrameSelection::lineDirectionPointForBlockDirectionNavigation(EPositi
break;
}
- Frame* frame = pos.document()->frame();
+ LocalFrame* frame = pos.document()->frame();
if (!frame)
return x;
@@ -1208,18 +1210,6 @@ void FrameSelection::setExtent(const VisiblePosition &pos, EUserTriggered userTr
setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity(), selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
}
-void FrameSelection::setBase(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
-{
- const bool selectionHasDirection = true;
- setSelection(VisibleSelection(pos, m_selection.extent(), affinity, selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
-}
-
-void FrameSelection::setExtent(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
-{
- const bool selectionHasDirection = true;
- setSelection(VisibleSelection(m_selection.base(), pos, affinity, selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
-}
-
RenderObject* FrameSelection::caretRenderer() const
{
return CaretBase::caretRenderer(m_selection.start().deprecatedNode());
@@ -1253,11 +1243,7 @@ bool FrameSelection::recomputeCaretRect()
if (!shouldUpdateCaretRect())
return false;
- if (!m_frame)
- return false;
-
- FrameView* v = m_frame->document()->view();
- if (!v)
+ if (!m_frame || !m_frame->document()->view())
return false;
LayoutRect oldRect = localCaretRectWithoutUpdate();
@@ -1273,9 +1259,9 @@ bool FrameSelection::recomputeCaretRect()
return false;
if (RenderView* view = m_frame->document()->renderView()) {
- Node* node = m_selection.start().deprecatedNode();
- if (m_previousCaretNode)
+ if (m_previousCaretNode && shouldRepaintCaret(view, m_previousCaretNode->isContentEditable()))
repaintCaretForLocalRect(m_previousCaretNode.get(), oldRect);
+ Node* node = m_selection.start().deprecatedNode();
m_previousCaretNode = node;
if (shouldRepaintCaret(view, isContentEditable()))
repaintCaretForLocalRect(node, newRect);
@@ -1352,8 +1338,13 @@ void FrameSelection::selectFrameElementInParentIfFullySelected()
if (!isEndOfDocument(selection().visibleEnd()))
return;
+ // FIXME: This is not yet implemented for cross-process frame relationships.
+ if (!parent->isLocalFrame())
+ return;
+
// Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
- Element* ownerElement = m_frame->ownerElement();
+ // FIXME: Doesn't work for OOPI.
+ Element* ownerElement = m_frame->deprecatedLocalOwner();
if (!ownerElement)
return;
ContainerNode* ownerElementParent = ownerElement->parentNode();
@@ -1372,14 +1363,14 @@ void FrameSelection::selectFrameElementInParentIfFullySelected()
// Focus on the parent frame, and then select from before this element to after.
VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
page->focusController().setFocusedFrame(parent);
- parent->selection().setSelection(newSelection);
+ toLocalFrame(parent)->selection().setSelection(newSelection);
}
void FrameSelection::selectAll()
{
Document* document = m_frame->document();
- if (document->focusedElement() && document->focusedElement()->hasTagName(selectTag)) {
+ if (isHTMLSelectElement(document->focusedElement())) {
HTMLSelectElement* selectElement = toHTMLSelectElement(document->focusedElement());
if (selectElement->canSelectAll()) {
selectElement->selectAll();
@@ -1387,7 +1378,7 @@ void FrameSelection::selectAll()
}
}
- RefPtr<Node> root = 0;
+ RefPtrWillBeRawPtr<Node> root = nullptr;
Node* selectStartTarget = 0;
if (isContentEditable()) {
root = highestEditableRoot(m_selection.start());
@@ -1416,32 +1407,37 @@ void FrameSelection::selectAll()
notifyRendererOfSelectionChange(UserTriggered);
}
-bool FrameSelection::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
+bool FrameSelection::setSelectedRange(Range* range, EAffinity affinity, DirectoinalOption directional, SetSelectionOptions options)
{
if (!range || !range->startContainer() || !range->endContainer())
return false;
ASSERT(range->startContainer()->document() == range->endContainer()->document());
- m_frame->document()->updateLayoutIgnorePendingStylesheets();
-
// 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
- TrackExceptionState exceptionState;
- bool collapsed = range->collapsed(exceptionState);
- if (exceptionState.hadException())
- return false;
+ m_logicalRange = nullptr;
+ stopObservingVisibleSelectionChangeIfNecessary();
+
+ VisibleSelection newSelection(range, affinity, directional == Directional);
+ setSelection(newSelection, options);
+
+ m_logicalRange = range->cloneRange();
+ startObservingVisibleSelectionChange();
- // FIXME: Can we provide extentAffinity?
- VisiblePosition visibleStart(range->startPosition(), collapsed ? affinity : DOWNSTREAM);
- VisiblePosition visibleEnd(range->endPosition(), SEL_DEFAULT_AFFINITY);
- setSelection(VisibleSelection(visibleStart, visibleEnd), ClearTypingStyle | (closeTyping ? CloseTyping : 0));
return true;
}
+PassRefPtrWillBeRawPtr<Range> FrameSelection::firstRange() const
+{
+ if (m_logicalRange)
+ return m_logicalRange->cloneRange();
+ return m_selection.firstRange();
+}
+
bool FrameSelection::isInPasswordField() const
{
HTMLTextFormControlElement* textControl = enclosingTextFormControl(start());
- return textControl && textControl->hasTagName(inputTag) && toHTMLInputElement(textControl)->isPasswordField();
+ return isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->isPasswordField();
}
void FrameSelection::notifyAccessibilityForSelectionChange()
@@ -1456,8 +1452,8 @@ void FrameSelection::focusedOrActiveStateChanged()
{
bool activeAndFocused = isFocusedAndActive();
- RefPtr<Document> document = m_frame->document();
- document->updateStyleIfNeeded();
+ RefPtrWillBeRawPtr<Document> document = m_frame->document();
+ document->updateRenderTreeIfNeeded();
// Because RenderObject::selectionBackgroundColor() and
// RenderObject::selectionForegroundColor() check if the frame is active,
@@ -1518,7 +1514,7 @@ bool FrameSelection::isFocusedAndActive() const
return m_focused && m_frame->page() && m_frame->page()->focusController().isActive();
}
-inline static bool shouldStopBlinkingDueToTypingCommand(Frame* frame)
+inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame)
{
return frame->editor().lastEditCommand() && frame->editor().lastEditCommand()->shouldStopCaretBlinking();
}
@@ -1550,7 +1546,7 @@ void FrameSelection::updateAppearance()
// already blinking in the right location.
if (shouldBlink && !m_caretBlinkTimer.isActive()) {
if (double blinkInterval = RenderTheme::theme().caretBlinkInterval())
- m_caretBlinkTimer.startRepeating(blinkInterval);
+ m_caretBlinkTimer.startRepeating(blinkInterval, FROM_HERE);
if (!m_caretPaint) {
m_caretPaint = true;
@@ -1589,7 +1585,8 @@ void FrameSelection::updateAppearance()
if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
RenderObject* startRenderer = startPos.deprecatedNode()->renderer();
RenderObject* endRenderer = endPos.deprecatedNode()->renderer();
- view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
+ if (startRenderer->view() == view && endRenderer->view() == view)
+ view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
}
}
@@ -1640,14 +1637,14 @@ void FrameSelection::caretBlinkTimerFired(Timer<FrameSelection>*)
void FrameSelection::notifyRendererOfSelectionChange(EUserTriggered userTriggered)
{
- m_frame->document()->updateStyleIfNeeded();
+ m_frame->document()->updateRenderTreeIfNeeded();
if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(start()))
textControl->selectionChanged(userTriggered == UserTriggered);
}
// Helper function that tells whether a particular node is an element that has an entire
-// Frame and FrameView, a <frame>, <iframe>, or <object>.
+// LocalFrame and FrameView, a <frame>, <iframe>, or <object>.
static bool isFrameElement(const Node* n)
{
if (!n)
@@ -1684,20 +1681,13 @@ void FrameSelection::setFocusedNodeIfNeeded()
}
target = target->parentOrShadowHostElement();
}
- m_frame->document()->setFocusedElement(0);
+ m_frame->document()->setFocusedElement(nullptr);
}
if (caretBrowsing)
m_frame->page()->focusController().setFocusedElement(0, m_frame);
}
-PassRefPtr<MutableStylePropertySet> FrameSelection::copyTypingStyle() const
-{
- if (!m_typingStyle || !m_typingStyle->style())
- return 0;
- return m_typingStyle->style()->mutableCopy();
-}
-
static String extractSelectedText(const FrameSelection& selection, TextIteratorBehavior behavior)
{
// We remove '\0' characters because they are not visibly rendered to the user.
@@ -1718,7 +1708,7 @@ String FrameSelection::selectedTextForClipboard() const
FloatRect FrameSelection::bounds(bool clipToVisibleContent) const
{
- m_frame->document()->updateStyleIfNeeded();
+ m_frame->document()->updateRenderTreeIfNeeded();
FrameView* view = m_frame->view();
RenderView* renderView = m_frame->contentRenderer();
@@ -1730,22 +1720,26 @@ FloatRect FrameSelection::bounds(bool clipToVisibleContent) const
return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect;
}
+static inline HTMLFormElement* associatedFormElement(HTMLElement& element)
+{
+ if (isHTMLFormElement(element))
+ return &toHTMLFormElement(element);
+ return element.formOwner();
+}
+
// Scans logically forward from "start", including any child frames.
static HTMLFormElement* scanForForm(Node* start)
{
if (!start)
return 0;
- Element* element = start->isElementNode() ? toElement(start) : ElementTraversal::next(*start);
- for (; element; element = ElementTraversal::next(*element)) {
- if (element->hasTagName(formTag))
- return toHTMLFormElement(element);
- if (element->isHTMLElement()) {
- HTMLFormElement* owner = toHTMLElement(element)->formOwner();
- if (owner)
- return owner;
- }
- if (element->hasTagName(frameTag) || element->hasTagName(iframeTag)) {
- Node* childDocument = toHTMLFrameElementBase(element)->contentDocument();
+
+ HTMLElement* element = start->isHTMLElement() ? toHTMLElement(start) : Traversal<HTMLElement>::next(*start);
+ for (; element; element = Traversal<HTMLElement>::next(*element)) {
+ if (HTMLFormElement* form = associatedFormElement(*element))
+ return form;
+
+ if (isHTMLFrameElementBase(*element)) {
+ Node* childDocument = toHTMLFrameElementBase(*element).contentDocument();
if (HTMLFormElement* frameResult = scanForForm(childDocument))
return frameResult;
}
@@ -1760,17 +1754,13 @@ HTMLFormElement* FrameSelection::currentForm() const
Node* start = m_frame->document()->focusedElement();
if (!start)
start = this->start().deprecatedNode();
+ if (!start)
+ return 0;
// Try walking up the node tree to find a form element.
- Node* node;
- for (node = start; node; node = node->parentNode()) {
- if (node->hasTagName(formTag))
- return toHTMLFormElement(node);
- if (node->isHTMLElement()) {
- HTMLFormElement* owner = toHTMLElement(node)->formOwner();
- if (owner)
- return owner;
- }
+ for (HTMLElement* element = Traversal<HTMLElement>::firstAncestorOrSelf(*start); element; element = Traversal<HTMLElement>::firstAncestor(*element)) {
+ if (HTMLFormElement* form = associatedFormElement(*element))
+ return form;
}
// Try walking forward in the node tree to find a form element.
@@ -1814,10 +1804,11 @@ void FrameSelection::setSelectionFromNone()
return;
Node* node = document->documentElement();
- while (node && !node->hasTagName(bodyTag))
- node = NodeTraversal::next(*node);
- if (node)
- setSelection(VisibleSelection(firstPositionInOrBeforeNode(node), DOWNSTREAM));
+ if (!node)
+ return;
+ Node* body = isHTMLBodyElement(*node) ? node : Traversal<HTMLBodyElement>::next(*node);
+ if (body)
+ setSelection(VisibleSelection(firstPositionInOrBeforeNode(body), DOWNSTREAM));
}
bool FrameSelection::dispatchSelectStart()
@@ -1838,6 +1829,30 @@ void FrameSelection::setShouldShowBlockCursor(bool shouldShowBlockCursor)
updateAppearance();
}
+void FrameSelection::didChangeVisibleSelection()
+{
+ ASSERT(m_observingVisibleSelection);
+ // Invalidate the logical range when the underlying VisibleSelection has changed.
+ m_logicalRange = nullptr;
+ m_selection.clearChangeObserver();
+ m_observingVisibleSelection = false;
+}
+
+void FrameSelection::startObservingVisibleSelectionChange()
+{
+ ASSERT(!m_observingVisibleSelection);
+ m_selection.setChangeObserver(*this);
+ m_observingVisibleSelection = true;
+}
+
+void FrameSelection::stopObservingVisibleSelectionChangeIfNecessary()
+{
+ if (m_observingVisibleSelection) {
+ m_selection.clearChangeObserver();
+ m_observingVisibleSelection = false;
+ }
+}
+
#ifndef NDEBUG
void FrameSelection::formatForDebugger(char* buffer, unsigned length) const
@@ -1852,6 +1867,16 @@ void FrameSelection::showTreeForThis() const
#endif
+void FrameSelection::trace(Visitor* visitor)
+{
+ visitor->trace(m_selection);
+ visitor->trace(m_originalBase);
+ visitor->trace(m_logicalRange);
+ visitor->trace(m_previousCaretNode);
+ visitor->trace(m_typingStyle);
+ VisibleSelection::ChangeObserver::trace(visitor);
+}
+
}
#ifndef NDEBUG