1/*
2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "core/editing/FrameSelection.h"
28
29#include "bindings/core/v8/ExceptionState.h"
30#include "core/HTMLNames.h"
31#include "core/InputTypeNames.h"
32#include "core/accessibility/AXObjectCache.h"
33#include "core/css/StylePropertySet.h"
34#include "core/dom/CharacterData.h"
35#include "core/dom/Document.h"
36#include "core/dom/Element.h"
37#include "core/dom/ElementTraversal.h"
38#include "core/dom/NodeTraversal.h"
39#include "core/dom/Text.h"
40#include "core/editing/Editor.h"
41#include "core/editing/InputMethodController.h"
42#include "core/editing/RenderedPosition.h"
43#include "core/editing/SpellChecker.h"
44#include "core/editing/TextIterator.h"
45#include "core/editing/TypingCommand.h"
46#include "core/editing/VisibleUnits.h"
47#include "core/editing/htmlediting.h"
48#include "core/events/Event.h"
49#include "core/frame/LocalDOMWindow.h"
50#include "core/frame/LocalFrame.h"
51#include "core/html/HTMLBodyElement.h"
52#include "core/html/HTMLFormElement.h"
53#include "core/html/HTMLFrameElementBase.h"
54#include "core/html/HTMLInputElement.h"
55#include "core/html/HTMLSelectElement.h"
56#include "core/page/EditorClient.h"
57#include "core/page/EventHandler.h"
58#include "core/page/FocusController.h"
59#include "core/page/FrameTree.h"
60#include "core/frame/FrameView.h"
61#include "core/page/Page.h"
62#include "core/frame/Settings.h"
63#include "core/page/SpatialNavigation.h"
64#include "core/rendering/HitTestRequest.h"
65#include "core/rendering/HitTestResult.h"
66#include "core/rendering/InlineTextBox.h"
67#include "core/rendering/RenderLayer.h"
68#include "core/rendering/RenderText.h"
69#include "core/rendering/RenderTheme.h"
70#include "core/rendering/RenderView.h"
71#include "core/rendering/RenderWidget.h"
72#include "platform/SecureTextInput.h"
73#include "platform/geometry/FloatQuad.h"
74#include "platform/graphics/GraphicsContext.h"
75#include "wtf/text/CString.h"
76#include <stdio.h>
77
78#define EDIT_DEBUG 0
79
80namespace blink {
81
82using namespace HTMLNames;
83
84static inline LayoutUnit NoXPosForVerticalArrowNavigation()
85{
86    return LayoutUnit::min();
87}
88
89static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame)
90{
91    return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirectional();
92}
93
94FrameSelection::FrameSelection(LocalFrame* frame)
95    : m_frame(frame)
96    , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation())
97    , m_observingVisibleSelection(false)
98    , m_granularity(CharacterGranularity)
99    , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired)
100    , m_caretRectDirty(true)
101    , m_shouldPaintCaret(true)
102    , m_isCaretBlinkingSuspended(false)
103    , m_focused(frame && frame->page() && frame->page()->focusController().focusedFrame() == frame)
104    , m_shouldShowBlockCursor(false)
105{
106    if (shouldAlwaysUseDirectionalSelection(m_frame))
107        m_selection.setIsDirectional(true);
108}
109
110FrameSelection::~FrameSelection()
111{
112#if !ENABLE(OILPAN)
113    // Oilpan: No need to clear out VisibleSelection observer;
114    // it is finalized as a part object of FrameSelection.
115    stopObservingVisibleSelectionChangeIfNecessary();
116#endif
117}
118
119Element* FrameSelection::rootEditableElementOrDocumentElement() const
120{
121    Element* selectionRoot = m_selection.rootEditableElement();
122    return selectionRoot ? selectionRoot : m_frame->document()->documentElement();
123}
124
125ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const
126{
127    Element* selectionRoot = m_selection.rootEditableElement();
128    if (selectionRoot)
129        return selectionRoot;
130
131    Node* node = m_selection.base().containerNode();
132    return node ? &node->treeScope().rootNode() : 0;
133}
134
135void FrameSelection::moveTo(const VisiblePosition &pos, EUserTriggered userTriggered, CursorAlignOnScroll align)
136{
137    SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
138    setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity(), m_selection.isDirectional()), options, align);
139}
140
141void FrameSelection::moveTo(const VisiblePosition &base, const VisiblePosition &extent, EUserTriggered userTriggered)
142{
143    const bool selectionHasDirection = true;
144    SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
145    setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity(), selectionHasDirection), options);
146}
147
148void FrameSelection::moveTo(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
149{
150    SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
151    setSelection(VisibleSelection(pos, affinity, m_selection.isDirectional()), options);
152}
153
154static void adjustEndpointsAtBidiBoundary(VisiblePosition& visibleBase, VisiblePosition& visibleExtent)
155{
156    RenderedPosition base(visibleBase);
157    RenderedPosition extent(visibleExtent);
158
159    if (base.isNull() || extent.isNull() || base.isEquivalent(extent))
160        return;
161
162    if (base.atLeftBoundaryOfBidiRun()) {
163        if (!extent.atRightBoundaryOfBidiRun(base.bidiLevelOnRight())
164            && base.isEquivalent(extent.leftBoundaryOfBidiRun(base.bidiLevelOnRight()))) {
165            visibleBase = VisiblePosition(base.positionAtLeftBoundaryOfBiDiRun());
166            return;
167        }
168        return;
169    }
170
171    if (base.atRightBoundaryOfBidiRun()) {
172        if (!extent.atLeftBoundaryOfBidiRun(base.bidiLevelOnLeft())
173            && base.isEquivalent(extent.rightBoundaryOfBidiRun(base.bidiLevelOnLeft()))) {
174            visibleBase = VisiblePosition(base.positionAtRightBoundaryOfBiDiRun());
175            return;
176        }
177        return;
178    }
179
180    if (extent.atLeftBoundaryOfBidiRun() && extent.isEquivalent(base.leftBoundaryOfBidiRun(extent.bidiLevelOnRight()))) {
181        visibleExtent = VisiblePosition(extent.positionAtLeftBoundaryOfBiDiRun());
182        return;
183    }
184
185    if (extent.atRightBoundaryOfBidiRun() && extent.isEquivalent(base.rightBoundaryOfBidiRun(extent.bidiLevelOnLeft()))) {
186        visibleExtent = VisiblePosition(extent.positionAtRightBoundaryOfBiDiRun());
187        return;
188    }
189}
190
191void FrameSelection::setNonDirectionalSelectionIfNeeded(const VisibleSelection& passedNewSelection, TextGranularity granularity,
192    EndPointsAdjustmentMode endpointsAdjustmentMode)
193{
194    VisibleSelection newSelection = passedNewSelection;
195    bool isDirectional = shouldAlwaysUseDirectionalSelection(m_frame) || newSelection.isDirectional();
196
197    VisiblePosition base = m_originalBase.isNotNull() ? m_originalBase : newSelection.visibleBase();
198    VisiblePosition newBase = base;
199    VisiblePosition extent = newSelection.visibleExtent();
200    VisiblePosition newExtent = extent;
201    if (endpointsAdjustmentMode == AdjustEndpointsAtBidiBoundary)
202        adjustEndpointsAtBidiBoundary(newBase, newExtent);
203
204    if (newBase != base || newExtent != extent) {
205        m_originalBase = base;
206        newSelection.setBase(newBase);
207        newSelection.setExtent(newExtent);
208    } else if (m_originalBase.isNotNull()) {
209        if (m_selection.base() == newSelection.base())
210            newSelection.setBase(m_originalBase);
211        m_originalBase.clear();
212    }
213
214    newSelection.setIsDirectional(isDirectional); // Adjusting base and extent will make newSelection always directional
215    if (m_selection == newSelection)
216        return;
217
218    setSelection(newSelection, granularity);
219}
220
221void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity)
222{
223    bool closeTyping = options & CloseTyping;
224    bool shouldClearTypingStyle = options & ClearTypingStyle;
225    EUserTriggered userTriggered = selectionOptionsToUserTriggered(options);
226
227    VisibleSelection s = validateSelection(newSelection);
228    if (shouldAlwaysUseDirectionalSelection(m_frame))
229        s.setIsDirectional(true);
230
231    if (!m_frame) {
232        m_selection = s;
233        return;
234    }
235
236    // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at FrameSelection::setSelection
237    // if document->frame() == m_frame we can get into an infinite loop
238    if (s.base().anchorNode()) {
239        Document& document = *s.base().document();
240        if (document.frame() && document.frame() != m_frame && document != m_frame->document()) {
241            RefPtrWillBeRawPtr<LocalFrame> guard(document.frame());
242            document.frame()->selection().setSelection(s, options, align, granularity);
243            // It's possible that during the above set selection, this FrameSelection has been modified by
244            // selectFrameElementInParentIfFullySelected, but that the selection is no longer valid since
245            // the frame is about to be destroyed. If this is the case, clear our selection.
246            if (!guard->host() && !m_selection.isNonOrphanedCaretOrRange())
247                clear();
248            return;
249        }
250    }
251
252    m_granularity = granularity;
253
254    if (closeTyping)
255        TypingCommand::closeTyping(m_frame);
256
257    if (shouldClearTypingStyle)
258        clearTypingStyle();
259
260    if (m_selection == s) {
261        // Even if selection was not changed, selection offsets may have been changed.
262        m_frame->inputMethodController().cancelCompositionIfSelectionIsInvalid();
263        notifyRendererOfSelectionChange(userTriggered);
264        return;
265    }
266
267    VisibleSelection oldSelection = m_selection;
268
269    m_selection = s;
270    setCaretRectNeedsUpdate();
271
272    if (!s.isNone() && !(options & DoNotSetFocus))
273        setFocusedNodeIfNeeded();
274
275    if (!(options & DoNotUpdateAppearance)) {
276        // Hits in compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html
277        DisableCompositingQueryAsserts disabler;
278        updateAppearance(ResetCaretBlink);
279    }
280
281    // Always clear the x position used for vertical arrow navigation.
282    // It will be restored by the vertical arrow navigation code if necessary.
283    m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation();
284    selectFrameElementInParentIfFullySelected();
285    notifyRendererOfSelectionChange(userTriggered);
286    m_frame->editor().respondToChangedSelection(oldSelection, options);
287    if (userTriggered == UserTriggered) {
288        ScrollAlignment alignment;
289
290        if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed())
291            alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
292        else
293            alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
294
295        revealSelection(alignment, RevealExtent);
296    }
297
298    notifyAccessibilityForSelectionChange();
299    notifyCompositorForSelectionChange();
300    notifyEventHandlerForSelectionChange();
301    m_frame->domWindow()->enqueueDocumentEvent(Event::create(EventTypeNames::selectionchange));
302}
303
304static bool removingNodeRemovesPosition(Node& node, const Position& position)
305{
306    if (!position.anchorNode())
307        return false;
308
309    if (position.anchorNode() == node)
310        return true;
311
312    if (!node.isElementNode())
313        return false;
314
315    Element& element = toElement(node);
316    return element.containsIncludingShadowDOM(position.anchorNode());
317}
318
319void FrameSelection::nodeWillBeRemoved(Node& node)
320{
321    // There can't be a selection inside a fragment, so if a fragment's node is being removed,
322    // the selection in the document that created the fragment needs no adjustment.
323    if (isNone() || !node.inActiveDocument())
324        return;
325
326    respondToNodeModification(node, removingNodeRemovesPosition(node, m_selection.base()), removingNodeRemovesPosition(node, m_selection.extent()),
327        removingNodeRemovesPosition(node, m_selection.start()), removingNodeRemovesPosition(node, m_selection.end()));
328}
329
330void FrameSelection::respondToNodeModification(Node& node, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved)
331{
332    ASSERT(node.document().isActive());
333
334    bool clearRenderTreeSelection = false;
335    bool clearDOMTreeSelection = false;
336
337    if (startRemoved || endRemoved) {
338        Position start = m_selection.start();
339        Position end = m_selection.end();
340        if (startRemoved)
341            updatePositionForNodeRemoval(start, node);
342        if (endRemoved)
343            updatePositionForNodeRemoval(end, node);
344
345        if (start.isNotNull() && end.isNotNull()) {
346            if (m_selection.isBaseFirst())
347                m_selection.setWithoutValidation(start, end);
348            else
349                m_selection.setWithoutValidation(end, start);
350        } else
351            clearDOMTreeSelection = true;
352
353        clearRenderTreeSelection = true;
354    } else if (baseRemoved || extentRemoved) {
355        // The base and/or extent are about to be removed, but the start and end aren't.
356        // Change the base and extent to the start and end, but don't re-validate the
357        // selection, since doing so could move the start and end into the node
358        // that is about to be removed.
359        if (m_selection.isBaseFirst())
360            m_selection.setWithoutValidation(m_selection.start(), m_selection.end());
361        else
362            m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
363    } else if (m_selection.intersectsNode(&node)) {
364        // If we did nothing here, when this node's renderer was destroyed, the rect that it
365        // occupied would be invalidated, but, selection gaps that change as a result of
366        // the removal wouldn't be invalidated.
367        // FIXME: Don't do so much unnecessary invalidation.
368        clearRenderTreeSelection = true;
369    }
370
371    if (clearRenderTreeSelection)
372        m_selection.start().document()->renderView()->clearSelection();
373
374    if (clearDOMTreeSelection)
375        setSelection(VisibleSelection(), DoNotSetFocus);
376}
377
378static Position updatePositionAfterAdoptingTextReplacement(const Position& position, CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
379{
380    if (!position.anchorNode() || position.anchorNode() != node || position.anchorType() != Position::PositionIsOffsetInAnchor)
381        return position;
382
383    // See: http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Mutation
384    ASSERT(position.offsetInContainerNode() >= 0);
385    unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
386    // Replacing text can be viewed as a deletion followed by insertion.
387    if (positionOffset >= offset && positionOffset <= offset + oldLength)
388        positionOffset = offset;
389
390    // Adjust the offset if the position is after the end of the deleted contents
391    // (positionOffset > offset + oldLength) to avoid having a stale offset.
392    if (positionOffset > offset + oldLength)
393        positionOffset = positionOffset - oldLength + newLength;
394
395    ASSERT_WITH_SECURITY_IMPLICATION(positionOffset <= node->length());
396    // CharacterNode in VisibleSelection must be Text node, because Comment
397    // and ProcessingInstruction node aren't visible.
398    return Position(toText(node), positionOffset);
399}
400
401void FrameSelection::didUpdateCharacterData(CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
402{
403    // The fragment check is a performance optimization. See http://trac.webkit.org/changeset/30062.
404    if (isNone() || !node || !node->inDocument())
405        return;
406
407    Position base = updatePositionAfterAdoptingTextReplacement(m_selection.base(), node, offset, oldLength, newLength);
408    Position extent = updatePositionAfterAdoptingTextReplacement(m_selection.extent(), node, offset, oldLength, newLength);
409    Position start = updatePositionAfterAdoptingTextReplacement(m_selection.start(), node, offset, oldLength, newLength);
410    Position end = updatePositionAfterAdoptingTextReplacement(m_selection.end(), node, offset, oldLength, newLength);
411    updateSelectionIfNeeded(base, extent, start, end);
412}
413
414static Position updatePostionAfterAdoptingTextNodesMerged(const Position& position, const Text& oldNode, unsigned offset)
415{
416    if (!position.anchorNode() || position.anchorType() != Position::PositionIsOffsetInAnchor)
417        return position;
418
419    ASSERT(position.offsetInContainerNode() >= 0);
420    unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
421
422    if (position.anchorNode() == &oldNode)
423        return Position(toText(oldNode.previousSibling()), positionOffset + offset);
424
425    if (position.anchorNode() == oldNode.parentNode() && positionOffset == offset)
426        return Position(toText(oldNode.previousSibling()), offset);
427
428    return position;
429}
430
431void FrameSelection::didMergeTextNodes(const Text& oldNode, unsigned offset)
432{
433    if (isNone() || !oldNode.inDocument())
434        return;
435    Position base = updatePostionAfterAdoptingTextNodesMerged(m_selection.base(), oldNode, offset);
436    Position extent = updatePostionAfterAdoptingTextNodesMerged(m_selection.extent(), oldNode, offset);
437    Position start = updatePostionAfterAdoptingTextNodesMerged(m_selection.start(), oldNode, offset);
438    Position end = updatePostionAfterAdoptingTextNodesMerged(m_selection.end(), oldNode, offset);
439    updateSelectionIfNeeded(base, extent, start, end);
440}
441
442static Position updatePostionAfterAdoptingTextNodeSplit(const Position& position, const Text& oldNode)
443{
444    if (!position.anchorNode() || position.anchorNode() != &oldNode || position.anchorType() != Position::PositionIsOffsetInAnchor)
445        return position;
446    // See: http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Mutation
447    ASSERT(position.offsetInContainerNode() >= 0);
448    unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
449    unsigned oldLength = oldNode.length();
450    if (positionOffset <= oldLength)
451        return position;
452    return Position(toText(oldNode.nextSibling()), positionOffset - oldLength);
453}
454
455void FrameSelection::didSplitTextNode(const Text& oldNode)
456{
457    if (isNone() || !oldNode.inDocument())
458        return;
459    Position base = updatePostionAfterAdoptingTextNodeSplit(m_selection.base(), oldNode);
460    Position extent = updatePostionAfterAdoptingTextNodeSplit(m_selection.extent(), oldNode);
461    Position start = updatePostionAfterAdoptingTextNodeSplit(m_selection.start(), oldNode);
462    Position end = updatePostionAfterAdoptingTextNodeSplit(m_selection.end(), oldNode);
463    updateSelectionIfNeeded(base, extent, start, end);
464}
465
466void FrameSelection::updateSelectionIfNeeded(const Position& base, const Position& extent, const Position& start, const Position& end)
467{
468    if (base == m_selection.base() && extent == m_selection.extent() && start == m_selection.start() && end == m_selection.end())
469        return;
470    VisibleSelection newSelection;
471    if (m_selection.isBaseFirst())
472        newSelection.setWithoutValidation(start, end);
473    else
474        newSelection.setWithoutValidation(end, start);
475    setSelection(newSelection, DoNotSetFocus);
476}
477
478TextDirection FrameSelection::directionOfEnclosingBlock()
479{
480    return blink::directionOfEnclosingBlock(m_selection.extent());
481}
482
483TextDirection FrameSelection::directionOfSelection()
484{
485    InlineBox* startBox = 0;
486    InlineBox* endBox = 0;
487    int unusedOffset;
488    // Cache the VisiblePositions because visibleStart() and visibleEnd()
489    // can cause layout, which has the potential to invalidate lineboxes.
490    VisiblePosition startPosition = m_selection.visibleStart();
491    VisiblePosition endPosition = m_selection.visibleEnd();
492    if (startPosition.isNotNull())
493        startPosition.getInlineBoxAndOffset(startBox, unusedOffset);
494    if (endPosition.isNotNull())
495        endPosition.getInlineBoxAndOffset(endBox, unusedOffset);
496    if (startBox && endBox && startBox->direction() == endBox->direction())
497        return startBox->direction();
498
499    return directionOfEnclosingBlock();
500}
501
502void FrameSelection::didChangeFocus()
503{
504    // Hits in virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disabled.html
505    DisableCompositingQueryAsserts disabler;
506    updateAppearance();
507}
508
509void FrameSelection::willBeModified(EAlteration alter, SelectionDirection direction)
510{
511    if (alter != AlterationExtend)
512        return;
513
514    Position start = m_selection.start();
515    Position end = m_selection.end();
516
517    bool baseIsStart = true;
518
519    if (m_selection.isDirectional()) {
520        // Make base and extent match start and end so we extend the user-visible selection.
521        // This only matters for cases where base and extend point to different positions than
522        // start and end (e.g. after a double-click to select a word).
523        if (m_selection.isBaseFirst())
524            baseIsStart = true;
525        else
526            baseIsStart = false;
527    } else {
528        switch (direction) {
529        case DirectionRight:
530            if (directionOfSelection() == LTR)
531                baseIsStart = true;
532            else
533                baseIsStart = false;
534            break;
535        case DirectionForward:
536            baseIsStart = true;
537            break;
538        case DirectionLeft:
539            if (directionOfSelection() == LTR)
540                baseIsStart = false;
541            else
542                baseIsStart = true;
543            break;
544        case DirectionBackward:
545            baseIsStart = false;
546            break;
547        }
548    }
549    if (baseIsStart) {
550        m_selection.setBase(start);
551        m_selection.setExtent(end);
552    } else {
553        m_selection.setBase(end);
554        m_selection.setExtent(start);
555    }
556}
557
558VisiblePosition FrameSelection::positionForPlatform(bool isGetStart) const
559{
560    Settings* settings = m_frame ? m_frame->settings() : 0;
561    if (settings && settings->editingBehaviorType() == EditingMacBehavior)
562        return isGetStart ? m_selection.visibleStart() : m_selection.visibleEnd();
563    // Linux and Windows always extend selections from the extent endpoint.
564    // FIXME: VisibleSelection should be fixed to ensure as an invariant that
565    // base/extent always point to the same nodes as start/end, but which points
566    // to which depends on the value of isBaseFirst. Then this can be changed
567    // to just return m_sel.extent().
568    return m_selection.isBaseFirst() ? m_selection.visibleEnd() : m_selection.visibleStart();
569}
570
571VisiblePosition FrameSelection::startForPlatform() const
572{
573    return positionForPlatform(true);
574}
575
576VisiblePosition FrameSelection::endForPlatform() const
577{
578    return positionForPlatform(false);
579}
580
581VisiblePosition FrameSelection::nextWordPositionForPlatform(const VisiblePosition &originalPosition)
582{
583    VisiblePosition positionAfterCurrentWord = nextWordPosition(originalPosition);
584
585    if (m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight()) {
586        // In order to skip spaces when moving right, we advance one
587        // word further and then move one word back. Given the
588        // semantics of previousWordPosition() this will put us at the
589        // beginning of the word following.
590        VisiblePosition positionAfterSpacingAndFollowingWord = nextWordPosition(positionAfterCurrentWord);
591        if (positionAfterSpacingAndFollowingWord.isNotNull() && positionAfterSpacingAndFollowingWord != positionAfterCurrentWord)
592            positionAfterCurrentWord = previousWordPosition(positionAfterSpacingAndFollowingWord);
593
594        bool movingBackwardsMovedPositionToStartOfCurrentWord = positionAfterCurrentWord == previousWordPosition(nextWordPosition(originalPosition));
595        if (movingBackwardsMovedPositionToStartOfCurrentWord)
596            positionAfterCurrentWord = positionAfterSpacingAndFollowingWord;
597    }
598    return positionAfterCurrentWord;
599}
600
601static void adjustPositionForUserSelectAll(VisiblePosition& pos, bool isForward)
602{
603    if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(pos.deepEquivalent().anchorNode()))
604        pos = VisiblePosition(isForward ? positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary) : positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
605}
606
607VisiblePosition FrameSelection::modifyExtendingRight(TextGranularity granularity)
608{
609    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
610
611    // The difference between modifyExtendingRight and modifyExtendingForward is:
612    // modifyExtendingForward always extends forward logically.
613    // modifyExtendingRight behaves the same as modifyExtendingForward except for extending character or word,
614    // it extends forward logically if the enclosing block is LTR direction,
615    // but it extends backward logically if the enclosing block is RTL direction.
616    switch (granularity) {
617    case CharacterGranularity:
618        if (directionOfEnclosingBlock() == LTR)
619            pos = pos.next(CanSkipOverEditingBoundary);
620        else
621            pos = pos.previous(CanSkipOverEditingBoundary);
622        break;
623    case WordGranularity:
624        if (directionOfEnclosingBlock() == LTR)
625            pos = nextWordPositionForPlatform(pos);
626        else
627            pos = previousWordPosition(pos);
628        break;
629    case LineBoundary:
630        if (directionOfEnclosingBlock() == LTR)
631            pos = modifyExtendingForward(granularity);
632        else
633            pos = modifyExtendingBackward(granularity);
634        break;
635    case SentenceGranularity:
636    case LineGranularity:
637    case ParagraphGranularity:
638    case SentenceBoundary:
639    case ParagraphBoundary:
640    case DocumentBoundary:
641        // FIXME: implement all of the above?
642        pos = modifyExtendingForward(granularity);
643        break;
644    }
645    adjustPositionForUserSelectAll(pos, directionOfEnclosingBlock() == LTR);
646    return pos;
647}
648
649VisiblePosition FrameSelection::modifyExtendingForward(TextGranularity granularity)
650{
651    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
652    switch (granularity) {
653    case CharacterGranularity:
654        pos = pos.next(CanSkipOverEditingBoundary);
655        break;
656    case WordGranularity:
657        pos = nextWordPositionForPlatform(pos);
658        break;
659    case SentenceGranularity:
660        pos = nextSentencePosition(pos);
661        break;
662    case LineGranularity:
663        pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
664        break;
665    case ParagraphGranularity:
666        pos = nextParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
667        break;
668    case SentenceBoundary:
669        pos = endOfSentence(endForPlatform());
670        break;
671    case LineBoundary:
672        pos = logicalEndOfLine(endForPlatform());
673        break;
674    case ParagraphBoundary:
675        pos = endOfParagraph(endForPlatform());
676        break;
677    case DocumentBoundary:
678        pos = endForPlatform();
679        if (isEditablePosition(pos.deepEquivalent()))
680            pos = endOfEditableContent(pos);
681        else
682            pos = endOfDocument(pos);
683        break;
684    }
685    adjustPositionForUserSelectAll(pos, directionOfEnclosingBlock() == LTR);
686    return pos;
687}
688
689VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity)
690{
691    VisiblePosition pos;
692    switch (granularity) {
693    case CharacterGranularity:
694        if (isRange()) {
695            if (directionOfSelection() == LTR)
696                pos = VisiblePosition(m_selection.end(), m_selection.affinity());
697            else
698                pos = VisiblePosition(m_selection.start(), m_selection.affinity());
699        } else
700            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
701        break;
702    case WordGranularity: {
703        bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight();
704        pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
705        break;
706    }
707    case SentenceGranularity:
708    case LineGranularity:
709    case ParagraphGranularity:
710    case SentenceBoundary:
711    case ParagraphBoundary:
712    case DocumentBoundary:
713        // FIXME: Implement all of the above.
714        pos = modifyMovingForward(granularity);
715        break;
716    case LineBoundary:
717        pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
718        break;
719    }
720    return pos;
721}
722
723VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity)
724{
725    VisiblePosition pos;
726    // FIXME: Stay in editable content for the less common granularities.
727    switch (granularity) {
728    case CharacterGranularity:
729        if (isRange())
730            pos = VisiblePosition(m_selection.end(), m_selection.affinity());
731        else
732            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CanSkipOverEditingBoundary);
733        break;
734    case WordGranularity:
735        pos = nextWordPositionForPlatform(VisiblePosition(m_selection.extent(), m_selection.affinity()));
736        break;
737    case SentenceGranularity:
738        pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
739        break;
740    case LineGranularity: {
741        // down-arrowing from a range selection that ends at the start of a line needs
742        // to leave the selection at that line start (no need to call nextLinePosition!)
743        pos = endForPlatform();
744        if (!isRange() || !isStartOfLine(pos))
745            pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(START));
746        break;
747    }
748    case ParagraphGranularity:
749        pos = nextParagraphPosition(endForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
750        break;
751    case SentenceBoundary:
752        pos = endOfSentence(endForPlatform());
753        break;
754    case LineBoundary:
755        pos = logicalEndOfLine(endForPlatform());
756        break;
757    case ParagraphBoundary:
758        pos = endOfParagraph(endForPlatform());
759        break;
760    case DocumentBoundary:
761        pos = endForPlatform();
762        if (isEditablePosition(pos.deepEquivalent()))
763            pos = endOfEditableContent(pos);
764        else
765            pos = endOfDocument(pos);
766        break;
767    }
768    return pos;
769}
770
771VisiblePosition FrameSelection::modifyExtendingLeft(TextGranularity granularity)
772{
773    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
774
775    // The difference between modifyExtendingLeft and modifyExtendingBackward is:
776    // modifyExtendingBackward always extends backward logically.
777    // modifyExtendingLeft behaves the same as modifyExtendingBackward except for extending character or word,
778    // it extends backward logically if the enclosing block is LTR direction,
779    // but it extends forward logically if the enclosing block is RTL direction.
780    switch (granularity) {
781    case CharacterGranularity:
782        if (directionOfEnclosingBlock() == LTR)
783            pos = pos.previous(CanSkipOverEditingBoundary);
784        else
785            pos = pos.next(CanSkipOverEditingBoundary);
786        break;
787    case WordGranularity:
788        if (directionOfEnclosingBlock() == LTR)
789            pos = previousWordPosition(pos);
790        else
791            pos = nextWordPositionForPlatform(pos);
792        break;
793    case LineBoundary:
794        if (directionOfEnclosingBlock() == LTR)
795            pos = modifyExtendingBackward(granularity);
796        else
797            pos = modifyExtendingForward(granularity);
798        break;
799    case SentenceGranularity:
800    case LineGranularity:
801    case ParagraphGranularity:
802    case SentenceBoundary:
803    case ParagraphBoundary:
804    case DocumentBoundary:
805        pos = modifyExtendingBackward(granularity);
806        break;
807    }
808    adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
809    return pos;
810}
811
812VisiblePosition FrameSelection::modifyExtendingBackward(TextGranularity granularity)
813{
814    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
815
816    // Extending a selection backward by word or character from just after a table selects
817    // the table.  This "makes sense" from the user perspective, esp. when deleting.
818    // It was done here instead of in VisiblePosition because we want VPs to iterate
819    // over everything.
820    switch (granularity) {
821    case CharacterGranularity:
822        pos = pos.previous(CanSkipOverEditingBoundary);
823        break;
824    case WordGranularity:
825        pos = previousWordPosition(pos);
826        break;
827    case SentenceGranularity:
828        pos = previousSentencePosition(pos);
829        break;
830    case LineGranularity:
831        pos = previousLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
832        break;
833    case ParagraphGranularity:
834        pos = previousParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
835        break;
836    case SentenceBoundary:
837        pos = startOfSentence(startForPlatform());
838        break;
839    case LineBoundary:
840        pos = logicalStartOfLine(startForPlatform());
841        break;
842    case ParagraphBoundary:
843        pos = startOfParagraph(startForPlatform());
844        break;
845    case DocumentBoundary:
846        pos = startForPlatform();
847        if (isEditablePosition(pos.deepEquivalent()))
848            pos = startOfEditableContent(pos);
849        else
850            pos = startOfDocument(pos);
851        break;
852    }
853    adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
854    return pos;
855}
856
857VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity)
858{
859    VisiblePosition pos;
860    switch (granularity) {
861    case CharacterGranularity:
862        if (isRange())
863            if (directionOfSelection() == LTR)
864                pos = VisiblePosition(m_selection.start(), m_selection.affinity());
865            else
866                pos = VisiblePosition(m_selection.end(), m_selection.affinity());
867        else
868            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
869        break;
870    case WordGranularity: {
871        bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight();
872        pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
873        break;
874    }
875    case SentenceGranularity:
876    case LineGranularity:
877    case ParagraphGranularity:
878    case SentenceBoundary:
879    case ParagraphBoundary:
880    case DocumentBoundary:
881        // FIXME: Implement all of the above.
882        pos = modifyMovingBackward(granularity);
883        break;
884    case LineBoundary:
885        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
886        break;
887    }
888    return pos;
889}
890
891VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity)
892{
893    VisiblePosition pos;
894    switch (granularity) {
895    case CharacterGranularity:
896        if (isRange())
897            pos = VisiblePosition(m_selection.start(), m_selection.affinity());
898        else
899            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CanSkipOverEditingBoundary);
900        break;
901    case WordGranularity:
902        pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
903        break;
904    case SentenceGranularity:
905        pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
906        break;
907    case LineGranularity:
908        pos = previousLinePosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
909        break;
910    case ParagraphGranularity:
911        pos = previousParagraphPosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
912        break;
913    case SentenceBoundary:
914        pos = startOfSentence(startForPlatform());
915        break;
916    case LineBoundary:
917        pos = logicalStartOfLine(startForPlatform());
918        break;
919    case ParagraphBoundary:
920        pos = startOfParagraph(startForPlatform());
921        break;
922    case DocumentBoundary:
923        pos = startForPlatform();
924        if (isEditablePosition(pos.deepEquivalent()))
925            pos = startOfEditableContent(pos);
926        else
927            pos = startOfDocument(pos);
928        break;
929    }
930    return pos;
931}
932
933static bool isBoundary(TextGranularity granularity)
934{
935    return granularity == LineBoundary || granularity == ParagraphBoundary || granularity == DocumentBoundary;
936}
937
938bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered)
939{
940    if (userTriggered == UserTriggered) {
941        OwnPtrWillBeRawPtr<FrameSelection> trialFrameSelection = FrameSelection::create();
942        trialFrameSelection->setSelection(m_selection);
943        trialFrameSelection->modify(alter, direction, granularity, NotUserTriggered);
944
945        if (trialFrameSelection->selection().isRange() && m_selection.isCaret() && !dispatchSelectStart())
946            return false;
947    }
948
949    willBeModified(alter, direction);
950
951    bool wasRange = m_selection.isRange();
952    VisiblePosition originalStartPosition = m_selection.visibleStart();
953    VisiblePosition position;
954    switch (direction) {
955    case DirectionRight:
956        if (alter == AlterationMove)
957            position = modifyMovingRight(granularity);
958        else
959            position = modifyExtendingRight(granularity);
960        break;
961    case DirectionForward:
962        if (alter == AlterationExtend)
963            position = modifyExtendingForward(granularity);
964        else
965            position = modifyMovingForward(granularity);
966        break;
967    case DirectionLeft:
968        if (alter == AlterationMove)
969            position = modifyMovingLeft(granularity);
970        else
971            position = modifyExtendingLeft(granularity);
972        break;
973    case DirectionBackward:
974        if (alter == AlterationExtend)
975            position = modifyExtendingBackward(granularity);
976        else
977            position = modifyMovingBackward(granularity);
978        break;
979    }
980
981    if (position.isNull())
982        return false;
983
984    if (isSpatialNavigationEnabled(m_frame))
985        if (!wasRange && alter == AlterationMove && position == originalStartPosition)
986            return false;
987
988    // Some of the above operations set an xPosForVerticalArrowNavigation.
989    // Setting a selection will clear it, so save it to possibly restore later.
990    // Note: the START position type is arbitrary because it is unused, it would be
991    // the requested position type if there were no xPosForVerticalArrowNavigation set.
992    LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(START);
993    m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_frame) || alter == AlterationExtend);
994
995    switch (alter) {
996    case AlterationMove:
997        moveTo(position, userTriggered);
998        break;
999    case AlterationExtend:
1000
1001        if (!m_selection.isCaret()
1002            && (granularity == WordGranularity || granularity == ParagraphGranularity || granularity == LineGranularity)
1003            && m_frame && !m_frame->editor().behavior().shouldExtendSelectionByWordOrLineAcrossCaret()) {
1004            // Don't let the selection go across the base position directly. Needed to match mac
1005            // behavior when, for instance, word-selecting backwards starting with the caret in
1006            // the middle of a word and then word-selecting forward, leaving the caret in the
1007            // same place where it was, instead of directly selecting to the end of the word.
1008            VisibleSelection newSelection = m_selection;
1009            newSelection.setExtent(position);
1010            if (m_selection.isBaseFirst() != newSelection.isBaseFirst())
1011                position = m_selection.visibleBase();
1012        }
1013
1014        // Standard Mac behavior when extending to a boundary is grow the selection rather than leaving the
1015        // base in place and moving the extent. Matches NSTextView.
1016        if (!m_frame || !m_frame->editor().behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity))
1017            setExtent(position, userTriggered);
1018        else {
1019            TextDirection textDirection = directionOfEnclosingBlock();
1020            if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft))
1021                setEnd(position, userTriggered);
1022            else
1023                setStart(position, userTriggered);
1024        }
1025        break;
1026    }
1027
1028    if (granularity == LineGranularity || granularity == ParagraphGranularity)
1029        m_xPosForVerticalArrowNavigation = x;
1030
1031    if (userTriggered == UserTriggered)
1032        m_granularity = CharacterGranularity;
1033
1034    setCaretRectNeedsUpdate();
1035
1036    return true;
1037}
1038
1039// FIXME: Maybe baseline would be better?
1040static bool absoluteCaretY(const VisiblePosition &c, int &y)
1041{
1042    IntRect rect = c.absoluteCaretBounds();
1043    if (rect.isEmpty())
1044        return false;
1045    y = rect.y() + rect.height() / 2;
1046    return true;
1047}
1048
1049bool FrameSelection::modify(EAlteration alter, unsigned verticalDistance, VerticalDirection direction, EUserTriggered userTriggered, CursorAlignOnScroll align)
1050{
1051    if (!verticalDistance)
1052        return false;
1053
1054    if (userTriggered == UserTriggered) {
1055        OwnPtrWillBeRawPtr<FrameSelection> trialFrameSelection = FrameSelection::create();
1056        trialFrameSelection->setSelection(m_selection);
1057        trialFrameSelection->modify(alter, verticalDistance, direction, NotUserTriggered);
1058    }
1059
1060    willBeModified(alter, direction == DirectionUp ? DirectionBackward : DirectionForward);
1061
1062    VisiblePosition pos;
1063    LayoutUnit xPos = 0;
1064    switch (alter) {
1065    case AlterationMove:
1066        pos = VisiblePosition(direction == DirectionUp ? m_selection.start() : m_selection.end(), m_selection.affinity());
1067        xPos = lineDirectionPointForBlockDirectionNavigation(direction == DirectionUp ? START : END);
1068        m_selection.setAffinity(direction == DirectionUp ? UPSTREAM : DOWNSTREAM);
1069        break;
1070    case AlterationExtend:
1071        pos = VisiblePosition(m_selection.extent(), m_selection.affinity());
1072        xPos = lineDirectionPointForBlockDirectionNavigation(EXTENT);
1073        m_selection.setAffinity(DOWNSTREAM);
1074        break;
1075    }
1076
1077    int startY;
1078    if (!absoluteCaretY(pos, startY))
1079        return false;
1080    if (direction == DirectionUp)
1081        startY = -startY;
1082    int lastY = startY;
1083
1084    VisiblePosition result;
1085    VisiblePosition next;
1086    for (VisiblePosition p = pos; ; p = next) {
1087        if (direction == DirectionUp)
1088            next = previousLinePosition(p, xPos);
1089        else
1090            next = nextLinePosition(p, xPos);
1091
1092        if (next.isNull() || next == p)
1093            break;
1094        int nextY;
1095        if (!absoluteCaretY(next, nextY))
1096            break;
1097        if (direction == DirectionUp)
1098            nextY = -nextY;
1099        if (nextY - startY > static_cast<int>(verticalDistance))
1100            break;
1101        if (nextY >= lastY) {
1102            lastY = nextY;
1103            result = next;
1104        }
1105    }
1106
1107    if (result.isNull())
1108        return false;
1109
1110    switch (alter) {
1111    case AlterationMove:
1112        moveTo(result, userTriggered, align);
1113        break;
1114    case AlterationExtend:
1115        setExtent(result, userTriggered);
1116        break;
1117    }
1118
1119    if (userTriggered == UserTriggered)
1120        m_granularity = CharacterGranularity;
1121
1122    m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_frame) || alter == AlterationExtend);
1123
1124    return true;
1125}
1126
1127LayoutUnit FrameSelection::lineDirectionPointForBlockDirectionNavigation(EPositionType type)
1128{
1129    LayoutUnit x = 0;
1130
1131    if (isNone())
1132        return x;
1133
1134    Position pos;
1135    switch (type) {
1136    case START:
1137        pos = m_selection.start();
1138        break;
1139    case END:
1140        pos = m_selection.end();
1141        break;
1142    case BASE:
1143        pos = m_selection.base();
1144        break;
1145    case EXTENT:
1146        pos = m_selection.extent();
1147        break;
1148    }
1149
1150    LocalFrame* frame = pos.document()->frame();
1151    if (!frame)
1152        return x;
1153
1154    if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation()) {
1155        VisiblePosition visiblePosition(pos, m_selection.affinity());
1156        // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
1157        // after the selection is created and before this function is called.
1158        x = visiblePosition.isNotNull() ? visiblePosition.lineDirectionPointForBlockDirectionNavigation() : 0;
1159        m_xPosForVerticalArrowNavigation = x;
1160    } else
1161        x = m_xPosForVerticalArrowNavigation;
1162
1163    return x;
1164}
1165
1166void FrameSelection::clear()
1167{
1168    m_granularity = CharacterGranularity;
1169    setSelection(VisibleSelection());
1170}
1171
1172void FrameSelection::prepareForDestruction()
1173{
1174    m_granularity = CharacterGranularity;
1175
1176    m_caretBlinkTimer.stop();
1177
1178    RenderView* view = m_frame->contentRenderer();
1179    if (view)
1180        view->clearSelection();
1181
1182    setSelection(VisibleSelection(), CloseTyping | ClearTypingStyle | DoNotUpdateAppearance);
1183    m_previousCaretNode.clear();
1184}
1185
1186void FrameSelection::setStart(const VisiblePosition &pos, EUserTriggered trigger)
1187{
1188    if (m_selection.isBaseFirst())
1189        setBase(pos, trigger);
1190    else
1191        setExtent(pos, trigger);
1192}
1193
1194void FrameSelection::setEnd(const VisiblePosition &pos, EUserTriggered trigger)
1195{
1196    if (m_selection.isBaseFirst())
1197        setExtent(pos, trigger);
1198    else
1199        setBase(pos, trigger);
1200}
1201
1202void FrameSelection::setBase(const VisiblePosition &pos, EUserTriggered userTriggered)
1203{
1204    const bool selectionHasDirection = true;
1205    setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity(), selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
1206}
1207
1208void FrameSelection::setExtent(const VisiblePosition &pos, EUserTriggered userTriggered)
1209{
1210    const bool selectionHasDirection = true;
1211    setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity(), selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
1212}
1213
1214RenderBlock* FrameSelection::caretRenderer() const
1215{
1216    return CaretBase::caretRenderer(m_selection.start().deprecatedNode());
1217}
1218
1219static bool isNonOrphanedCaret(const VisibleSelection& selection)
1220{
1221    return selection.isCaret() && !selection.start().isOrphan() && !selection.end().isOrphan();
1222}
1223
1224static bool isTextFormControl(const VisibleSelection& selection)
1225{
1226    return enclosingTextFormControl(selection.start());
1227}
1228
1229IntRect FrameSelection::absoluteCaretBounds()
1230{
1231    ASSERT(m_frame->document()->lifecycle().state() != DocumentLifecycle::InPaintInvalidation);
1232    m_frame->document()->updateLayoutIgnorePendingStylesheets();
1233    if (!isNonOrphanedCaret(m_selection)) {
1234        clearCaretRect();
1235    } else {
1236        if (isTextFormControl(m_selection))
1237            updateCaretRect(m_frame->document(), PositionWithAffinity(m_selection.start().isCandidate() ? m_selection.start() : Position(), m_selection.affinity()));
1238        else
1239            updateCaretRect(m_frame->document(), VisiblePosition(m_selection.start(), m_selection.affinity()));
1240    }
1241    return absoluteBoundsForLocalRect(m_selection.start().deprecatedNode(), localCaretRectWithoutUpdate());
1242}
1243
1244static LayoutRect localCaretRect(const VisibleSelection& m_selection, const PositionWithAffinity& caretPosition, RenderObject*& renderer)
1245{
1246    renderer = nullptr;
1247    if (!isNonOrphanedCaret(m_selection))
1248        return LayoutRect();
1249
1250    return localCaretRectOfPosition(caretPosition, renderer);
1251}
1252
1253void FrameSelection::invalidateCaretRect()
1254{
1255    if (!m_caretRectDirty)
1256        return;
1257    m_caretRectDirty = false;
1258
1259    RenderObject* renderer = nullptr;
1260    LayoutRect newRect = localCaretRect(m_selection, PositionWithAffinity(m_selection.start(), m_selection.affinity()), renderer);
1261    Node* newNode = renderer ? renderer->node() : nullptr;
1262
1263    if (!m_caretBlinkTimer.isActive() && newNode == m_previousCaretNode && newRect == m_previousCaretRect)
1264        return;
1265
1266    RenderView* view = m_frame->document()->renderView();
1267    if (m_previousCaretNode && shouldRepaintCaret(view, m_previousCaretNode->isContentEditable()))
1268        invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect);
1269    if (newNode && shouldRepaintCaret(view, newNode->isContentEditable()))
1270        invalidateLocalCaretRect(newNode, newRect);
1271
1272    m_previousCaretNode = newNode;
1273    m_previousCaretRect = newRect;
1274}
1275
1276void FrameSelection::paintCaret(GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect)
1277{
1278    if (m_selection.isCaret() && m_shouldPaintCaret) {
1279        updateCaretRect(m_frame->document(), PositionWithAffinity(m_selection.start(), m_selection.affinity()));
1280        CaretBase::paintCaret(m_selection.start().deprecatedNode(), context, paintOffset, clipRect);
1281    }
1282}
1283
1284bool FrameSelection::contains(const LayoutPoint& point)
1285{
1286    Document* document = m_frame->document();
1287
1288    // Treat a collapsed selection like no selection.
1289    if (!isRange())
1290        return false;
1291    if (!document->renderView())
1292        return false;
1293
1294    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1295    HitTestResult result(point);
1296    document->renderView()->hitTest(request, result);
1297    Node* innerNode = result.innerNode();
1298    if (!innerNode || !innerNode->renderer())
1299        return false;
1300
1301    VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint()));
1302    if (visiblePos.isNull())
1303        return false;
1304
1305    if (m_selection.visibleStart().isNull() || m_selection.visibleEnd().isNull())
1306        return false;
1307
1308    Position start(m_selection.visibleStart().deepEquivalent());
1309    Position end(m_selection.visibleEnd().deepEquivalent());
1310    Position p(visiblePos.deepEquivalent());
1311
1312    return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;
1313}
1314
1315// Workaround for the fact that it's hard to delete a frame.
1316// Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
1317// Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
1318// for the focus to move to another frame. So instead we call it from places where we are selecting with the
1319// mouse or the keyboard after setting the selection.
1320void FrameSelection::selectFrameElementInParentIfFullySelected()
1321{
1322    // Find the parent frame; if there is none, then we have nothing to do.
1323    Frame* parent = m_frame->tree().parent();
1324    if (!parent)
1325        return;
1326    Page* page = m_frame->page();
1327    if (!page)
1328        return;
1329
1330    // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
1331    if (!isRange())
1332        return;
1333    if (!isStartOfDocument(selection().visibleStart()))
1334        return;
1335    if (!isEndOfDocument(selection().visibleEnd()))
1336        return;
1337
1338    // FIXME: This is not yet implemented for cross-process frame relationships.
1339    if (!parent->isLocalFrame())
1340        return;
1341
1342    // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
1343    // FIXME: Doesn't work for OOPI.
1344    HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
1345    if (!ownerElement)
1346        return;
1347    ContainerNode* ownerElementParent = ownerElement->parentNode();
1348    if (!ownerElementParent)
1349        return;
1350
1351    // This method's purpose is it to make it easier to select iframes (in order to delete them).  Don't do anything if the iframe isn't deletable.
1352    if (!ownerElementParent->hasEditableStyle())
1353        return;
1354
1355    // Create compute positions before and after the element.
1356    unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
1357    VisiblePosition beforeOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex, Position::PositionIsOffsetInAnchor)));
1358    VisiblePosition afterOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex + 1, Position::PositionIsOffsetInAnchor), VP_UPSTREAM_IF_POSSIBLE));
1359
1360    // Focus on the parent frame, and then select from before this element to after.
1361    VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
1362    page->focusController().setFocusedFrame(parent);
1363    toLocalFrame(parent)->selection().setSelection(newSelection);
1364}
1365
1366void FrameSelection::selectAll()
1367{
1368    Document* document = m_frame->document();
1369
1370    if (isHTMLSelectElement(document->focusedElement())) {
1371        HTMLSelectElement* selectElement = toHTMLSelectElement(document->focusedElement());
1372        if (selectElement->canSelectAll()) {
1373            selectElement->selectAll();
1374            return;
1375        }
1376    }
1377
1378    RefPtrWillBeRawPtr<Node> root = nullptr;
1379    Node* selectStartTarget = 0;
1380    if (isContentEditable()) {
1381        root = highestEditableRoot(m_selection.start());
1382        if (Node* shadowRoot = m_selection.nonBoundaryShadowTreeRootNode())
1383            selectStartTarget = shadowRoot->shadowHost();
1384        else
1385            selectStartTarget = root.get();
1386    } else {
1387        root = m_selection.nonBoundaryShadowTreeRootNode();
1388        if (root)
1389            selectStartTarget = root->shadowHost();
1390        else {
1391            root = document->documentElement();
1392            selectStartTarget = document->body();
1393        }
1394    }
1395    if (!root)
1396        return;
1397
1398    if (selectStartTarget && !selectStartTarget->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart)))
1399        return;
1400
1401    VisibleSelection newSelection(VisibleSelection::selectionFromContentsOfNode(root.get()));
1402    setSelection(newSelection);
1403    selectFrameElementInParentIfFullySelected();
1404    notifyRendererOfSelectionChange(UserTriggered);
1405}
1406
1407bool FrameSelection::setSelectedRange(Range* range, EAffinity affinity, DirectoinalOption directional, SetSelectionOptions options)
1408{
1409    if (!range || !range->startContainer() || !range->endContainer())
1410        return false;
1411    ASSERT(range->startContainer()->document() == range->endContainer()->document());
1412
1413    // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
1414    // they start at the beginning of the next line instead
1415    m_logicalRange = nullptr;
1416    stopObservingVisibleSelectionChangeIfNecessary();
1417
1418    VisibleSelection newSelection(range, affinity, directional == Directional);
1419    setSelection(newSelection, options);
1420
1421    m_logicalRange = range->cloneRange();
1422    startObservingVisibleSelectionChange();
1423
1424    return true;
1425}
1426
1427PassRefPtrWillBeRawPtr<Range> FrameSelection::firstRange() const
1428{
1429    if (m_logicalRange)
1430        return m_logicalRange->cloneRange();
1431    return m_selection.firstRange();
1432}
1433
1434bool FrameSelection::isInPasswordField() const
1435{
1436    HTMLTextFormControlElement* textControl = enclosingTextFormControl(start());
1437    return isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->type() == InputTypeNames::password;
1438}
1439
1440void FrameSelection::notifyAccessibilityForSelectionChange()
1441{
1442    if (m_selection.start().isNotNull() && m_selection.end().isNotNull()) {
1443        if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1444            cache->selectionChanged(m_selection.start().containerNode());
1445    }
1446}
1447
1448void FrameSelection::notifyCompositorForSelectionChange()
1449{
1450    if (!RuntimeEnabledFeatures::compositedSelectionUpdateEnabled())
1451        return;
1452
1453    scheduleVisualUpdate();
1454}
1455
1456void FrameSelection::notifyEventHandlerForSelectionChange()
1457{
1458    m_frame->eventHandler().notifySelectionChanged();
1459}
1460
1461void FrameSelection::focusedOrActiveStateChanged()
1462{
1463    bool activeAndFocused = isFocusedAndActive();
1464
1465    RefPtrWillBeRawPtr<Document> document = m_frame->document();
1466    document->updateRenderTreeIfNeeded();
1467
1468    // Because RenderObject::selectionBackgroundColor() and
1469    // RenderObject::selectionForegroundColor() check if the frame is active,
1470    // we have to update places those colors were painted.
1471    if (RenderView* view = document->renderView())
1472        view->invalidatePaintForSelection();
1473
1474    // Caret appears in the active frame.
1475    if (activeAndFocused)
1476        setSelectionFromNone();
1477    else
1478        m_frame->spellChecker().spellCheckAfterBlur();
1479    setCaretVisibility(activeAndFocused ? Visible : Hidden);
1480
1481    // Update for caps lock state
1482    m_frame->eventHandler().capsLockStateMayHaveChanged();
1483
1484    // We may have lost active status even though the focusElement hasn't changed
1485    // give the element a chance to recalc style if its affected by focus.
1486    if (Element* element = document->focusedElement())
1487        element->focusStateChanged();
1488
1489    // Secure keyboard entry is set by the active frame.
1490    if (document->useSecureKeyboardEntryWhenActive())
1491        setUseSecureKeyboardEntry(activeAndFocused);
1492}
1493
1494void FrameSelection::pageActivationChanged()
1495{
1496    focusedOrActiveStateChanged();
1497}
1498
1499void FrameSelection::updateSecureKeyboardEntryIfActive()
1500{
1501    if (m_frame->document() && isFocusedAndActive())
1502        setUseSecureKeyboardEntry(m_frame->document()->useSecureKeyboardEntryWhenActive());
1503}
1504
1505void FrameSelection::setUseSecureKeyboardEntry(bool enable)
1506{
1507    if (enable)
1508        enableSecureTextInput();
1509    else
1510        disableSecureTextInput();
1511}
1512
1513void FrameSelection::setFocused(bool flag)
1514{
1515    if (m_focused == flag)
1516        return;
1517    m_focused = flag;
1518
1519    focusedOrActiveStateChanged();
1520}
1521
1522bool FrameSelection::isFocusedAndActive() const
1523{
1524    return m_focused && m_frame->page() && m_frame->page()->focusController().isActive();
1525}
1526
1527inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame)
1528{
1529    return frame->editor().lastEditCommand() && frame->editor().lastEditCommand()->shouldStopCaretBlinking();
1530}
1531
1532void FrameSelection::updateAppearance(ResetCaretBlinkOption option)
1533{
1534    // Paint a block cursor instead of a caret in overtype mode unless the caret is at the end of a line (in this case
1535    // the FrameSelection will paint a blinking caret as usual).
1536    bool paintBlockCursor = m_shouldShowBlockCursor && m_selection.isCaret() && !isLogicalEndOfLine(m_selection.visibleEnd());
1537
1538    bool shouldBlink = !paintBlockCursor && shouldBlinkCaret();
1539
1540    bool willNeedCaretRectUpdate = false;
1541
1542    // If the caret moved, stop the blink timer so we can restart with a
1543    // black caret in the new location.
1544    if (option == ResetCaretBlink || !shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame)) {
1545        m_caretBlinkTimer.stop();
1546
1547        m_shouldPaintCaret = false;
1548        willNeedCaretRectUpdate = true;
1549    }
1550
1551    // Start blinking with a black caret. Be sure not to restart if we're
1552    // already blinking in the right location.
1553    if (shouldBlink && !m_caretBlinkTimer.isActive()) {
1554        if (double blinkInterval = RenderTheme::theme().caretBlinkInterval())
1555            m_caretBlinkTimer.startRepeating(blinkInterval, FROM_HERE);
1556
1557        m_shouldPaintCaret = true;
1558        willNeedCaretRectUpdate = true;
1559    }
1560
1561    if (willNeedCaretRectUpdate)
1562        setCaretRectNeedsUpdate();
1563
1564    RenderView* view = m_frame->contentRenderer();
1565    if (!view)
1566        return;
1567
1568    // Construct a new VisibleSolution, since m_selection is not necessarily valid, and the following steps
1569    // assume a valid selection. See <https://bugs.webkit.org/show_bug.cgi?id=69563> and <rdar://problem/10232866>.
1570
1571    VisibleSelection selection;
1572    if (isTextFormControl(m_selection)) {
1573        Position endPosition = paintBlockCursor ? m_selection.extent().next() : m_selection.end();
1574        selection.setWithoutValidation(m_selection.start(), endPosition);
1575    } else {
1576        VisiblePosition endVisiblePosition = paintBlockCursor ? modifyExtendingForward(CharacterGranularity) : m_selection.visibleEnd();
1577        selection = VisibleSelection(m_selection.visibleStart(), endVisiblePosition);
1578    }
1579
1580    if (!selection.isRange()) {
1581        view->clearSelection();
1582        return;
1583    }
1584
1585    m_frame->document()->updateLayoutIgnorePendingStylesheets();
1586
1587    // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
1588    // Example: foo <a>bar</a>.  Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.   If we pass [foo, 3]
1589    // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
1590    // and will fill the gap before 'bar'.
1591    Position startPos = selection.start();
1592    Position candidate = startPos.downstream();
1593    if (candidate.isCandidate())
1594        startPos = candidate;
1595    Position endPos = selection.end();
1596    candidate = endPos.upstream();
1597    if (candidate.isCandidate())
1598        endPos = candidate;
1599
1600    // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
1601    // because we don't yet notify the FrameSelection of text removal.
1602    if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
1603        RenderObject* startRenderer = startPos.deprecatedNode()->renderer();
1604        RenderObject* endRenderer = endPos.deprecatedNode()->renderer();
1605        if (startRenderer && endRenderer && startRenderer->view() == view && endRenderer->view() == view)
1606            view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
1607    }
1608}
1609
1610void FrameSelection::setCaretVisibility(CaretVisibility visibility)
1611{
1612    if (caretVisibility() == visibility)
1613        return;
1614
1615    CaretBase::setCaretVisibility(visibility);
1616
1617    updateAppearance();
1618}
1619
1620bool FrameSelection::shouldBlinkCaret() const
1621{
1622    if (!caretIsVisible() || !isCaret())
1623        return false;
1624
1625    if (m_frame->settings() && m_frame->settings()->caretBrowsingEnabled())
1626        return false;
1627
1628    Element* root = rootEditableElement();
1629    if (!root)
1630        return false;
1631
1632    Element* focusedElement = root->document().focusedElement();
1633    if (!focusedElement)
1634        return false;
1635
1636    return focusedElement->containsIncludingShadowDOM(m_selection.start().anchorNode());
1637}
1638
1639void FrameSelection::caretBlinkTimerFired(Timer<FrameSelection>*)
1640{
1641    ASSERT(caretIsVisible());
1642    ASSERT(isCaret());
1643    if (isCaretBlinkingSuspended() && m_shouldPaintCaret)
1644        return;
1645    m_shouldPaintCaret = !m_shouldPaintCaret;
1646    setCaretRectNeedsUpdate();
1647}
1648
1649void FrameSelection::notifyRendererOfSelectionChange(EUserTriggered userTriggered)
1650{
1651    if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(start()))
1652        textControl->selectionChanged(userTriggered == UserTriggered);
1653}
1654
1655// Helper function that tells whether a particular node is an element that has an entire
1656// LocalFrame and FrameView, a <frame>, <iframe>, or <object>.
1657static bool isFrameElement(const Node* n)
1658{
1659    if (!n)
1660        return false;
1661    RenderObject* renderer = n->renderer();
1662    if (!renderer || !renderer->isWidget())
1663        return false;
1664    Widget* widget = toRenderWidget(renderer)->widget();
1665    return widget && widget->isFrameView();
1666}
1667
1668void FrameSelection::setFocusedNodeIfNeeded()
1669{
1670    if (isNone() || !isFocused())
1671        return;
1672
1673    bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
1674    if (caretBrowsing) {
1675        if (Element* anchor = enclosingAnchorElement(base())) {
1676            m_frame->page()->focusController().setFocusedElement(anchor, m_frame);
1677            return;
1678        }
1679    }
1680
1681    if (Element* target = rootEditableElement()) {
1682        // Walk up the DOM tree to search for a node to focus.
1683        while (target) {
1684            // We don't want to set focus on a subframe when selecting in a parent frame,
1685            // so add the !isFrameElement check here. There's probably a better way to make this
1686            // work in the long term, but this is the safest fix at this time.
1687            if (target->isMouseFocusable() && !isFrameElement(target)) {
1688                m_frame->page()->focusController().setFocusedElement(target, m_frame);
1689                return;
1690            }
1691            target = target->parentOrShadowHostElement();
1692        }
1693        m_frame->document()->setFocusedElement(nullptr);
1694    }
1695
1696    if (caretBrowsing)
1697        m_frame->page()->focusController().setFocusedElement(0, m_frame);
1698}
1699
1700static String extractSelectedText(const FrameSelection& selection, TextIteratorBehavior behavior)
1701{
1702    // We remove '\0' characters because they are not visibly rendered to the user.
1703    return plainText(selection.toNormalizedRange().get(), behavior).replace(0, "");
1704}
1705
1706String FrameSelection::selectedText() const
1707{
1708    return extractSelectedText(*this, TextIteratorDefaultBehavior);
1709}
1710
1711String FrameSelection::selectedTextForClipboard() const
1712{
1713    if (m_frame->settings() && m_frame->settings()->selectionIncludesAltImageText())
1714        return extractSelectedText(*this, TextIteratorEmitsImageAltText);
1715    return selectedText();
1716}
1717
1718FloatRect FrameSelection::bounds() const
1719{
1720    m_frame->document()->updateRenderTreeIfNeeded();
1721
1722    FrameView* view = m_frame->view();
1723    RenderView* renderView = m_frame->contentRenderer();
1724
1725    if (!view || !renderView)
1726        return FloatRect();
1727
1728    LayoutRect selectionRect = renderView->selectionBounds();
1729    return selectionRect;
1730}
1731
1732static inline HTMLFormElement* associatedFormElement(HTMLElement& element)
1733{
1734    if (isHTMLFormElement(element))
1735        return &toHTMLFormElement(element);
1736    return element.formOwner();
1737}
1738
1739// Scans logically forward from "start", including any child frames.
1740static HTMLFormElement* scanForForm(Node* start)
1741{
1742    if (!start)
1743        return 0;
1744
1745    HTMLElement* element = start->isHTMLElement() ? toHTMLElement(start) : Traversal<HTMLElement>::next(*start);
1746    for (; element; element = Traversal<HTMLElement>::next(*element)) {
1747        if (HTMLFormElement* form = associatedFormElement(*element))
1748            return form;
1749
1750        if (isHTMLFrameElementBase(*element)) {
1751            Node* childDocument = toHTMLFrameElementBase(*element).contentDocument();
1752            if (HTMLFormElement* frameResult = scanForForm(childDocument))
1753                return frameResult;
1754        }
1755    }
1756    return 0;
1757}
1758
1759// We look for either the form containing the current focus, or for one immediately after it
1760HTMLFormElement* FrameSelection::currentForm() const
1761{
1762    // Start looking either at the active (first responder) node, or where the selection is.
1763    Node* start = m_frame->document()->focusedElement();
1764    if (!start)
1765        start = this->start().deprecatedNode();
1766    if (!start)
1767        return 0;
1768
1769    // Try walking up the node tree to find a form element.
1770    for (HTMLElement* element = Traversal<HTMLElement>::firstAncestorOrSelf(*start); element; element = Traversal<HTMLElement>::firstAncestor(*element)) {
1771        if (HTMLFormElement* form = associatedFormElement(*element))
1772            return form;
1773    }
1774
1775    // Try walking forward in the node tree to find a form element.
1776    return scanForForm(start);
1777}
1778
1779void FrameSelection::revealSelection(const ScrollAlignment& alignment, RevealExtentOption revealExtentOption)
1780{
1781    LayoutRect rect;
1782
1783    switch (selectionType()) {
1784    case NoSelection:
1785        return;
1786    case CaretSelection:
1787        rect = absoluteCaretBounds();
1788        break;
1789    case RangeSelection:
1790        rect = revealExtentOption == RevealExtent ? VisiblePosition(extent()).absoluteCaretBounds() : enclosingIntRect(bounds());
1791        break;
1792    }
1793
1794    Position start = this->start();
1795    ASSERT(start.deprecatedNode());
1796    if (start.deprecatedNode() && start.deprecatedNode()->renderer()) {
1797        // FIXME: This code only handles scrolling the startContainer's layer, but
1798        // the selection rect could intersect more than just that.
1799        // See <rdar://problem/4799899>.
1800        if (start.deprecatedNode()->renderer()->scrollRectToVisible(rect, alignment, alignment))
1801            updateAppearance();
1802    }
1803}
1804
1805void FrameSelection::setSelectionFromNone()
1806{
1807    // Put a caret inside the body if the entire frame is editable (either the
1808    // entire WebView is editable or designMode is on for this document).
1809
1810    Document* document = m_frame->document();
1811    bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
1812    if (!isNone() || !(document->hasEditableStyle() || caretBrowsing))
1813        return;
1814
1815    Element* documentElement = document->documentElement();
1816    if (!documentElement)
1817        return;
1818    if (HTMLBodyElement* body = Traversal<HTMLBodyElement>::firstChild(*documentElement))
1819        setSelection(VisibleSelection(firstPositionInOrBeforeNode(body), DOWNSTREAM));
1820}
1821
1822bool FrameSelection::dispatchSelectStart()
1823{
1824    Node* selectStartTarget = m_selection.extent().containerNode();
1825    if (!selectStartTarget)
1826        return true;
1827
1828    return selectStartTarget->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart));
1829}
1830
1831void FrameSelection::setShouldShowBlockCursor(bool shouldShowBlockCursor)
1832{
1833    m_shouldShowBlockCursor = shouldShowBlockCursor;
1834
1835    m_frame->document()->updateLayoutIgnorePendingStylesheets();
1836
1837    updateAppearance();
1838}
1839
1840void FrameSelection::didChangeVisibleSelection()
1841{
1842    ASSERT(m_observingVisibleSelection);
1843    // Invalidate the logical range when the underlying VisibleSelection has changed.
1844    m_logicalRange = nullptr;
1845    m_selection.clearChangeObserver();
1846    m_observingVisibleSelection = false;
1847}
1848
1849VisibleSelection FrameSelection::validateSelection(const VisibleSelection& selection)
1850{
1851    if (!m_frame || selection.isNone())
1852        return selection;
1853
1854    Position base = selection.base();
1855    Position extent = selection.extent();
1856    bool isBaseValid = base.document() == m_frame->document();
1857    bool isExtentValid = extent.document() == m_frame->document();
1858
1859    if (isBaseValid && isExtentValid)
1860        return selection;
1861
1862    VisibleSelection newSelection;
1863    if (isBaseValid) {
1864        newSelection.setWithoutValidation(base, base);
1865    } else if (isExtentValid) {
1866        newSelection.setWithoutValidation(extent, extent);
1867    }
1868    return newSelection;
1869}
1870
1871void FrameSelection::startObservingVisibleSelectionChange()
1872{
1873    ASSERT(!m_observingVisibleSelection);
1874    m_selection.setChangeObserver(*this);
1875    m_observingVisibleSelection = true;
1876}
1877
1878void FrameSelection::stopObservingVisibleSelectionChangeIfNecessary()
1879{
1880    if (m_observingVisibleSelection) {
1881        m_selection.clearChangeObserver();
1882        m_observingVisibleSelection = false;
1883    }
1884}
1885
1886#ifndef NDEBUG
1887
1888void FrameSelection::formatForDebugger(char* buffer, unsigned length) const
1889{
1890    m_selection.formatForDebugger(buffer, length);
1891}
1892
1893void FrameSelection::showTreeForThis() const
1894{
1895    m_selection.showTreeForThis();
1896}
1897
1898#endif
1899
1900void FrameSelection::trace(Visitor* visitor)
1901{
1902    visitor->trace(m_frame);
1903    visitor->trace(m_selection);
1904    visitor->trace(m_originalBase);
1905    visitor->trace(m_logicalRange);
1906    visitor->trace(m_previousCaretNode);
1907    visitor->trace(m_typingStyle);
1908    VisibleSelection::ChangeObserver::trace(visitor);
1909}
1910
1911void FrameSelection::setCaretRectNeedsUpdate()
1912{
1913    m_caretRectDirty = true;
1914
1915    scheduleVisualUpdate();
1916}
1917
1918void FrameSelection::scheduleVisualUpdate() const
1919{
1920    if (!m_frame)
1921        return;
1922    if (Page* page = m_frame->page())
1923        page->animator().scheduleVisualUpdate();
1924}
1925
1926}
1927
1928#ifndef NDEBUG
1929
1930void showTree(const blink::FrameSelection& sel)
1931{
1932    sel.showTreeForThis();
1933}
1934
1935void showTree(const blink::FrameSelection* sel)
1936{
1937    if (sel)
1938        sel->showTreeForThis();
1939}
1940
1941#endif
1942