1/*
2 * Copyright (C) 2004, 2008, 2009, 2010, 2014 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 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 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 "FrameSelection.h"
28
29#include "CharacterData.h"
30#include "DeleteSelectionCommand.h"
31#include "Document.h"
32#include "Editor.h"
33#include "EditorClient.h"
34#include "Element.h"
35#include "ElementIterator.h"
36#include "EventHandler.h"
37#include "ExceptionCode.h"
38#include "FloatQuad.h"
39#include "FocusController.h"
40#include "Frame.h"
41#include "FrameTree.h"
42#include "FrameView.h"
43#include "GraphicsContext.h"
44#include "HTMLFormElement.h"
45#include "HTMLFrameElementBase.h"
46#include "HTMLInputElement.h"
47#include "HTMLSelectElement.h"
48#include "HTMLNames.h"
49#include "HitTestRequest.h"
50#include "HitTestResult.h"
51#include "InlineTextBox.h"
52#include "Page.h"
53#include "RenderText.h"
54#include "RenderTextControl.h"
55#include "RenderTheme.h"
56#include "RenderView.h"
57#include "RenderWidget.h"
58#include "RenderedPosition.h"
59#include "Settings.h"
60#include "SpatialNavigation.h"
61#include "StyleProperties.h"
62#include "TypingCommand.h"
63#include "VisibleUnits.h"
64#include "htmlediting.h"
65#include <stdio.h>
66#include <wtf/text/CString.h>
67
68#if PLATFORM(IOS)
69#include "Chrome.h"
70#include "ChromeClient.h"
71#include "Color.h"
72#include "RenderLayer.h"
73#include "RenderObject.h"
74#include "RenderStyle.h"
75#endif
76
77#define EDIT_DEBUG 0
78
79namespace WebCore {
80
81using namespace HTMLNames;
82
83static inline LayoutUnit NoXPosForVerticalArrowNavigation()
84{
85    return LayoutUnit::min();
86}
87
88CaretBase::CaretBase(CaretVisibility visibility)
89    : m_caretRectNeedsUpdate(true)
90    , m_caretVisibility(visibility)
91{
92}
93
94DragCaretController::DragCaretController()
95    : CaretBase(Visible)
96{
97}
98
99bool DragCaretController::isContentRichlyEditable() const
100{
101    return isRichlyEditablePosition(m_position.deepEquivalent());
102}
103
104static inline bool shouldAlwaysUseDirectionalSelection(Frame* frame)
105{
106    return !frame || frame->editor().behavior().shouldConsiderSelectionAsDirectional();
107}
108
109FrameSelection::FrameSelection(Frame* frame)
110    : m_frame(frame)
111    , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation())
112    , m_granularity(CharacterGranularity)
113    , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired)
114    , m_absCaretBoundsDirty(true)
115    , m_caretPaint(true)
116    , m_isCaretBlinkingSuspended(false)
117    , m_focused(frame && frame->page() && frame->page()->focusController().focusedFrame() == frame)
118    , m_shouldShowBlockCursor(false)
119    , m_pendingSelectionUpdate(false)
120    , m_shouldRevealSelection(false)
121    , m_alwaysAlignCursorOnScrollWhenRevealingSelection(false)
122#if PLATFORM(IOS)
123    , m_updateAppearanceEnabled(false)
124    , m_caretBlinks(true)
125    , m_scrollingSuppressCount(0)
126#endif
127{
128    if (shouldAlwaysUseDirectionalSelection(m_frame))
129        m_selection.setIsDirectional(true);
130}
131
132Element* FrameSelection::rootEditableElementOrDocumentElement() const
133{
134    Element* selectionRoot = m_selection.rootEditableElement();
135    return selectionRoot ? selectionRoot : m_frame->document()->documentElement();
136}
137
138void FrameSelection::moveTo(const VisiblePosition &pos, EUserTriggered userTriggered, CursorAlignOnScroll align)
139{
140    setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity(), m_selection.isDirectional()),
141        defaultSetSelectionOptions(userTriggered), align);
142}
143
144void FrameSelection::moveTo(const VisiblePosition &base, const VisiblePosition &extent, EUserTriggered userTriggered)
145{
146    const bool selectionHasDirection = true;
147    setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity(), selectionHasDirection), defaultSetSelectionOptions(userTriggered));
148}
149
150void FrameSelection::moveTo(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
151{
152    setSelection(VisibleSelection(pos, affinity, m_selection.isDirectional()), defaultSetSelectionOptions(userTriggered));
153}
154
155void FrameSelection::moveTo(const Range* range)
156{
157    VisibleSelection selection = range ? VisibleSelection(range->startPosition(), range->endPosition()) : VisibleSelection();
158    setSelection(selection);
159}
160
161void FrameSelection::moveTo(const Position &base, const Position &extent, EAffinity affinity, EUserTriggered userTriggered)
162{
163    const bool selectionHasDirection = true;
164    setSelection(VisibleSelection(base, extent, affinity, selectionHasDirection), defaultSetSelectionOptions(userTriggered));
165}
166
167void FrameSelection::moveWithoutValidationTo(const Position& base, const Position& extent, bool selectionHasDirection, bool shouldSetFocus)
168{
169    VisibleSelection newSelection;
170    newSelection.setWithoutValidation(base, extent);
171    newSelection.setIsDirectional(selectionHasDirection);
172    setSelection(newSelection, defaultSetSelectionOptions() | (shouldSetFocus ? 0 : DoNotSetFocus));
173}
174
175void DragCaretController::setCaretPosition(const VisiblePosition& position)
176{
177    if (Node* node = m_position.deepEquivalent().deprecatedNode())
178        invalidateCaretRect(node);
179    m_position = position;
180    setCaretRectNeedsUpdate();
181    Document* document = 0;
182    if (Node* node = m_position.deepEquivalent().deprecatedNode()) {
183        invalidateCaretRect(node);
184        document = &node->document();
185    }
186    if (m_position.isNull() || m_position.isOrphan())
187        clearCaretRect();
188    else
189        updateCaretRect(document, m_position);
190}
191
192static void adjustEndpointsAtBidiBoundary(VisiblePosition& visibleBase, VisiblePosition& visibleExtent)
193{
194    RenderedPosition base(visibleBase);
195    RenderedPosition extent(visibleExtent);
196
197    if (base.isNull() || extent.isNull() || base.isEquivalent(extent))
198        return;
199
200    if (base.atLeftBoundaryOfBidiRun()) {
201        if (!extent.atRightBoundaryOfBidiRun(base.bidiLevelOnRight())
202            && base.isEquivalent(extent.leftBoundaryOfBidiRun(base.bidiLevelOnRight()))) {
203            visibleBase = base.positionAtLeftBoundaryOfBiDiRun();
204            return;
205        }
206        return;
207    }
208
209    if (base.atRightBoundaryOfBidiRun()) {
210        if (!extent.atLeftBoundaryOfBidiRun(base.bidiLevelOnLeft())
211            && base.isEquivalent(extent.rightBoundaryOfBidiRun(base.bidiLevelOnLeft()))) {
212            visibleBase = base.positionAtRightBoundaryOfBiDiRun();
213            return;
214        }
215        return;
216    }
217
218    if (extent.atLeftBoundaryOfBidiRun() && extent.isEquivalent(base.leftBoundaryOfBidiRun(extent.bidiLevelOnRight()))) {
219        visibleExtent = extent.positionAtLeftBoundaryOfBiDiRun();
220        return;
221    }
222
223    if (extent.atRightBoundaryOfBidiRun() && extent.isEquivalent(base.rightBoundaryOfBidiRun(extent.bidiLevelOnLeft()))) {
224        visibleExtent = extent.positionAtRightBoundaryOfBiDiRun();
225        return;
226    }
227}
228
229void FrameSelection::setSelectionByMouseIfDifferent(const VisibleSelection& passedNewSelection, TextGranularity granularity,
230    EndPointsAdjustmentMode endpointsAdjustmentMode)
231{
232    VisibleSelection newSelection = passedNewSelection;
233    bool isDirectional = shouldAlwaysUseDirectionalSelection(m_frame) || newSelection.isDirectional();
234
235    VisiblePosition base = m_originalBase.isNotNull() ? m_originalBase : newSelection.visibleBase();
236    VisiblePosition newBase = base;
237    VisiblePosition extent = newSelection.visibleExtent();
238    VisiblePosition newExtent = extent;
239    if (endpointsAdjustmentMode == AdjustEndpointsAtBidiBoundary)
240        adjustEndpointsAtBidiBoundary(newBase, newExtent);
241
242    if (newBase != base || newExtent != extent) {
243        m_originalBase = base;
244        newSelection.setBase(newBase);
245        newSelection.setExtent(newExtent);
246    } else if (m_originalBase.isNotNull()) {
247        if (m_selection.base() == newSelection.base())
248            newSelection.setBase(m_originalBase);
249        m_originalBase.clear();
250    }
251
252    newSelection.setIsDirectional(isDirectional); // Adjusting base and extent will make newSelection always directional
253    if (m_selection == newSelection || !shouldChangeSelection(newSelection))
254        return;
255
256    setSelection(newSelection, defaultSetSelectionOptions() | FireSelectEvent, AlignCursorOnScrollIfNeeded, granularity);
257}
258
259bool FrameSelection::setSelectionWithoutUpdatingAppearance(const VisibleSelection& newSelectionPossiblyWithoutDirection, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity)
260{
261    bool closeTyping = options & CloseTyping;
262    bool shouldClearTypingStyle = options & ClearTypingStyle;
263
264    VisibleSelection newSelection = newSelectionPossiblyWithoutDirection;
265    if (shouldAlwaysUseDirectionalSelection(m_frame))
266        newSelection.setIsDirectional(true);
267
268    if (!m_frame) {
269        m_selection = newSelection;
270        return false;
271    }
272
273    // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at FrameSelection::setSelection
274    // if document->frame() == m_frame we can get into an infinite loop
275    if (Document* newSelectionDocument = newSelection.base().document()) {
276        if (RefPtr<Frame> newSelectionFrame = newSelectionDocument->frame()) {
277            if (newSelectionFrame != m_frame && newSelectionDocument != m_frame->document()) {
278                newSelectionFrame->selection().setSelection(newSelection, options, align, granularity);
279                // It's possible that during the above set selection, this FrameSelection has been modified by
280                // selectFrameElementInParentIfFullySelected, but that the selection is no longer valid since
281                // the frame is about to be destroyed. If this is the case, clear our selection.
282                if (newSelectionFrame->hasOneRef() && !m_selection.isNonOrphanedCaretOrRange())
283                    clear();
284                return false;
285            }
286        }
287    }
288
289    m_granularity = granularity;
290
291    if (closeTyping)
292        TypingCommand::closeTyping(m_frame);
293
294    if (shouldClearTypingStyle)
295        clearTypingStyle();
296
297    VisibleSelection oldSelection = m_selection;
298    m_selection = newSelection;
299
300    // Selection offsets should increase when LF is inserted before the caret in InsertLineBreakCommand. See <https://webkit.org/b/56061>.
301    if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(newSelection.start()))
302        textControl->selectionChanged(options & FireSelectEvent);
303
304    if (oldSelection == newSelection)
305        return false;
306
307    setCaretRectNeedsUpdate();
308
309    if (!newSelection.isNone() && !(options & DoNotSetFocus))
310        setFocusedElementIfNeeded();
311
312    // Always clear the x position used for vertical arrow navigation.
313    // It will be restored by the vertical arrow navigation code if necessary.
314    m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation();
315    selectFrameElementInParentIfFullySelected();
316    m_frame->editor().respondToChangedSelection(oldSelection, options);
317    m_frame->document()->enqueueDocumentEvent(Event::create(eventNames().selectionchangeEvent, false, false));
318
319    return true;
320}
321
322void FrameSelection::setSelection(const VisibleSelection& selection, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity)
323{
324    if (!setSelectionWithoutUpdatingAppearance(selection, options, align, granularity))
325        return;
326
327    Document* document = m_frame->document();
328    if (!document)
329        return;
330
331    m_shouldRevealSelection = options & RevealSelection;
332    m_alwaysAlignCursorOnScrollWhenRevealingSelection = align == AlignCursorOnScrollAlways;
333
334    m_pendingSelectionUpdate = true;
335
336    if (document->hasPendingStyleRecalc())
337        return;
338
339    FrameView* frameView = document->view();
340    if (frameView && frameView->layoutPending())
341        return;
342
343    updateAndRevealSelection();
344}
345
346static void updateSelectionByUpdatingLayoutOrStyle(Frame& frame)
347{
348#if ENABLE(TEXT_CARET)
349    frame.document()->updateLayoutIgnorePendingStylesheets();
350#else
351    frame.document()->updateStyleIfNeeded();
352#endif
353}
354
355void FrameSelection::setNeedsSelectionUpdate()
356{
357    m_pendingSelectionUpdate = true;
358    if (RenderView* view = m_frame->contentRenderer())
359        view->clearSelection();
360}
361
362void FrameSelection::updateAndRevealSelection()
363{
364    if (!m_pendingSelectionUpdate)
365        return;
366
367    m_pendingSelectionUpdate = false;
368
369    updateAppearance();
370
371    if (m_shouldRevealSelection) {
372        ScrollAlignment alignment;
373
374        if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed())
375            alignment = m_alwaysAlignCursorOnScrollWhenRevealingSelection ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
376        else
377            alignment = m_alwaysAlignCursorOnScrollWhenRevealingSelection ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
378
379        revealSelection(alignment, RevealExtent);
380    }
381
382    notifyAccessibilityForSelectionChange();
383}
384
385void FrameSelection::updateDataDetectorsForSelection()
386{
387#if ENABLE(TELEPHONE_NUMBER_DETECTION) && !PLATFORM(IOS)
388    m_frame->editor().scanSelectionForTelephoneNumbers();
389#endif
390}
391
392static bool removingNodeRemovesPosition(Node* node, const Position& position)
393{
394    if (!position.anchorNode())
395        return false;
396
397    if (position.anchorNode() == node)
398        return true;
399
400    if (!node->isElementNode())
401        return false;
402
403    Element* element = toElement(node);
404    return element->containsIncludingShadowDOM(position.anchorNode());
405}
406
407static void clearRenderViewSelection(Node& node)
408{
409    Ref<Document> document(node.document());
410    document->updateStyleIfNeeded();
411    if (RenderView* view = document->renderView())
412        view->clearSelection();
413}
414
415void DragCaretController::nodeWillBeRemoved(Node* node)
416{
417    if (!hasCaret() || (node && !node->inDocument()))
418        return;
419
420    if (!removingNodeRemovesPosition(node, m_position.deepEquivalent()))
421        return;
422
423    clearRenderViewSelection(*node);
424    clear();
425}
426
427void FrameSelection::nodeWillBeRemoved(Node* node)
428{
429    // There can't be a selection inside a fragment, so if a fragment's node is being removed,
430    // the selection in the document that created the fragment needs no adjustment.
431    if (isNone() || (node && !node->inDocument()))
432        return;
433
434    respondToNodeModification(node, removingNodeRemovesPosition(node, m_selection.base()), removingNodeRemovesPosition(node, m_selection.extent()),
435        removingNodeRemovesPosition(node, m_selection.start()), removingNodeRemovesPosition(node, m_selection.end()));
436}
437
438void FrameSelection::respondToNodeModification(Node* node, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved)
439{
440    bool clearRenderTreeSelection = false;
441    bool clearDOMTreeSelection = false;
442
443    if (startRemoved || endRemoved) {
444        Position start = m_selection.start();
445        Position end = m_selection.end();
446        if (startRemoved)
447            updatePositionForNodeRemoval(start, node);
448        if (endRemoved)
449            updatePositionForNodeRemoval(end, node);
450
451        if (start.isNotNull() && end.isNotNull()) {
452            if (m_selection.isBaseFirst())
453                m_selection.setWithoutValidation(start, end);
454            else
455                m_selection.setWithoutValidation(end, start);
456        } else
457            clearDOMTreeSelection = true;
458
459        clearRenderTreeSelection = true;
460    } else if (baseRemoved || extentRemoved) {
461        // The base and/or extent are about to be removed, but the start and end aren't.
462        // Change the base and extent to the start and end, but don't re-validate the
463        // selection, since doing so could move the start and end into the node
464        // that is about to be removed.
465        if (m_selection.isBaseFirst())
466            m_selection.setWithoutValidation(m_selection.start(), m_selection.end());
467        else
468            m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
469    } else if (RefPtr<Range> range = m_selection.firstRange()) {
470        ExceptionCode ec = 0;
471        Range::CompareResults compareResult = range->compareNode(node, ec);
472        if (!ec && (compareResult == Range::NODE_BEFORE_AND_AFTER || compareResult == Range::NODE_INSIDE)) {
473            // If we did nothing here, when this node's renderer was destroyed, the rect that it
474            // occupied would be invalidated, but, selection gaps that change as a result of
475            // the removal wouldn't be invalidated.
476            // FIXME: Don't do so much unnecessary invalidation.
477            clearRenderTreeSelection = true;
478        }
479    }
480
481    if (clearRenderTreeSelection) {
482        clearRenderViewSelection(*node);
483
484        // Trigger a selection update so the selection will be set again.
485        if (auto* renderView = node->document().renderView()) {
486            m_pendingSelectionUpdate = true;
487            renderView->setNeedsLayout();
488        }
489    }
490
491    if (clearDOMTreeSelection)
492        setSelection(VisibleSelection(), DoNotSetFocus);
493}
494
495static void updatePositionAfterAdoptingTextReplacement(Position& position, CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
496{
497    if (!position.anchorNode() || position.anchorNode() != node || position.anchorType() != Position::PositionIsOffsetInAnchor)
498        return;
499
500    // See: http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Mutation
501    ASSERT(position.offsetInContainerNode() >= 0);
502    unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
503    // Replacing text can be viewed as a deletion followed by insertion.
504    if (positionOffset >= offset && positionOffset <= offset + oldLength)
505        position.moveToOffset(offset);
506
507    // Adjust the offset if the position is after the end of the deleted contents
508    // (positionOffset > offset + oldLength) to avoid having a stale offset.
509    if (positionOffset > offset + oldLength)
510        position.moveToOffset(positionOffset - oldLength + newLength);
511
512    ASSERT(static_cast<unsigned>(position.offsetInContainerNode()) <= node->length());
513}
514
515void FrameSelection::textWasReplaced(CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
516{
517    // The fragment check is a performance optimization. See http://trac.webkit.org/changeset/30062.
518    if (isNone() || !node || !node->inDocument())
519        return;
520
521    Position base = m_selection.base();
522    Position extent = m_selection.extent();
523    Position start = m_selection.start();
524    Position end = m_selection.end();
525    updatePositionAfterAdoptingTextReplacement(base, node, offset, oldLength, newLength);
526    updatePositionAfterAdoptingTextReplacement(extent, node, offset, oldLength, newLength);
527    updatePositionAfterAdoptingTextReplacement(start, node, offset, oldLength, newLength);
528    updatePositionAfterAdoptingTextReplacement(end, node, offset, oldLength, newLength);
529
530    if (base != m_selection.base() || extent != m_selection.extent() || start != m_selection.start() || end != m_selection.end()) {
531        VisibleSelection newSelection;
532        if (base != extent)
533            newSelection.setWithoutValidation(base, extent);
534        else if (m_selection.isDirectional() && !m_selection.isBaseFirst())
535            newSelection.setWithoutValidation(end, start);
536        else
537            newSelection.setWithoutValidation(start, end);
538
539        setSelection(newSelection, DoNotSetFocus);
540    }
541}
542
543TextDirection FrameSelection::directionOfEnclosingBlock()
544{
545    return WebCore::directionOfEnclosingBlock(m_selection.extent());
546}
547
548TextDirection FrameSelection::directionOfSelection()
549{
550    InlineBox* startBox = 0;
551    InlineBox* endBox = 0;
552    int unusedOffset;
553    // Cache the VisiblePositions because visibleStart() and visibleEnd()
554    // can cause layout, which has the potential to invalidate lineboxes.
555    VisiblePosition startPosition = m_selection.visibleStart();
556    VisiblePosition endPosition = m_selection.visibleEnd();
557    if (startPosition.isNotNull())
558        startPosition.getInlineBoxAndOffset(startBox, unusedOffset);
559    if (endPosition.isNotNull())
560        endPosition.getInlineBoxAndOffset(endBox, unusedOffset);
561    if (startBox && endBox && startBox->direction() == endBox->direction())
562        return startBox->direction();
563
564    return directionOfEnclosingBlock();
565}
566
567void FrameSelection::willBeModified(EAlteration alter, SelectionDirection direction)
568{
569    if (alter != AlterationExtend)
570        return;
571
572    Position start = m_selection.start();
573    Position end = m_selection.end();
574
575    bool baseIsStart = true;
576
577    if (m_selection.isDirectional()) {
578        // Make base and extent match start and end so we extend the user-visible selection.
579        // This only matters for cases where base and extend point to different positions than
580        // start and end (e.g. after a double-click to select a word).
581        if (m_selection.isBaseFirst())
582            baseIsStart = true;
583        else
584            baseIsStart = false;
585    } else {
586        switch (direction) {
587        case DirectionRight:
588            if (directionOfSelection() == LTR)
589                baseIsStart = true;
590            else
591                baseIsStart = false;
592            break;
593        case DirectionForward:
594            baseIsStart = true;
595            break;
596        case DirectionLeft:
597            if (directionOfSelection() == LTR)
598                baseIsStart = false;
599            else
600                baseIsStart = true;
601            break;
602        case DirectionBackward:
603            baseIsStart = false;
604            break;
605        }
606    }
607    if (baseIsStart) {
608        m_selection.setBase(start);
609        m_selection.setExtent(end);
610    } else {
611        m_selection.setBase(end);
612        m_selection.setExtent(start);
613    }
614}
615
616VisiblePosition FrameSelection::positionForPlatform(bool isGetStart) const
617{
618    if (m_frame && m_frame->settings().editingBehaviorType() == EditingMacBehavior)
619        return isGetStart ? m_selection.visibleStart() : m_selection.visibleEnd();
620    // Linux and Windows always extend selections from the extent endpoint.
621    // FIXME: VisibleSelection should be fixed to ensure as an invariant that
622    // base/extent always point to the same nodes as start/end, but which points
623    // to which depends on the value of isBaseFirst. Then this can be changed
624    // to just return m_sel.extent().
625    return m_selection.isBaseFirst() ? m_selection.visibleEnd() : m_selection.visibleStart();
626}
627
628VisiblePosition FrameSelection::startForPlatform() const
629{
630    return positionForPlatform(true);
631}
632
633VisiblePosition FrameSelection::endForPlatform() const
634{
635    return positionForPlatform(false);
636}
637
638VisiblePosition FrameSelection::nextWordPositionForPlatform(const VisiblePosition &originalPosition)
639{
640    VisiblePosition positionAfterCurrentWord = nextWordPosition(originalPosition);
641
642    if (m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight()) {
643        // In order to skip spaces when moving right, we advance one
644        // word further and then move one word back. Given the
645        // semantics of previousWordPosition() this will put us at the
646        // beginning of the word following.
647        VisiblePosition positionAfterSpacingAndFollowingWord = nextWordPosition(positionAfterCurrentWord);
648        if (positionAfterSpacingAndFollowingWord != positionAfterCurrentWord)
649            positionAfterCurrentWord = previousWordPosition(positionAfterSpacingAndFollowingWord);
650
651        bool movingBackwardsMovedPositionToStartOfCurrentWord = positionAfterCurrentWord == previousWordPosition(nextWordPosition(originalPosition));
652        if (movingBackwardsMovedPositionToStartOfCurrentWord)
653            positionAfterCurrentWord = positionAfterSpacingAndFollowingWord;
654    }
655    return positionAfterCurrentWord;
656}
657
658#if ENABLE(USERSELECT_ALL)
659static void adjustPositionForUserSelectAll(VisiblePosition& pos, bool isForward)
660{
661    if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(pos.deepEquivalent().anchorNode()))
662        pos = isForward ? positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary) : positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary);
663}
664#endif
665
666VisiblePosition FrameSelection::modifyExtendingRight(TextGranularity granularity)
667{
668    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
669
670    // The difference between modifyExtendingRight and modifyExtendingForward is:
671    // modifyExtendingForward always extends forward logically.
672    // modifyExtendingRight behaves the same as modifyExtendingForward except for extending character or word,
673    // it extends forward logically if the enclosing block is LTR direction,
674    // but it extends backward logically if the enclosing block is RTL direction.
675    switch (granularity) {
676    case CharacterGranularity:
677        if (directionOfEnclosingBlock() == LTR)
678            pos = pos.next(CannotCrossEditingBoundary);
679        else
680            pos = pos.previous(CannotCrossEditingBoundary);
681        break;
682    case WordGranularity:
683        if (directionOfEnclosingBlock() == LTR)
684            pos = nextWordPositionForPlatform(pos);
685        else
686            pos = previousWordPosition(pos);
687        break;
688    case LineBoundary:
689        if (directionOfEnclosingBlock() == LTR)
690            pos = modifyExtendingForward(granularity);
691        else
692            pos = modifyExtendingBackward(granularity);
693        break;
694    case SentenceGranularity:
695    case LineGranularity:
696    case ParagraphGranularity:
697    case SentenceBoundary:
698    case ParagraphBoundary:
699    case DocumentBoundary:
700        // FIXME: implement all of the above?
701        pos = modifyExtendingForward(granularity);
702        break;
703#if PLATFORM(IOS)
704    case DocumentGranularity:
705        ASSERT_NOT_REACHED();
706        break;
707#endif
708    }
709#if ENABLE(USERSELECT_ALL)
710    adjustPositionForUserSelectAll(pos, directionOfEnclosingBlock() == LTR);
711#endif
712    return pos;
713}
714
715VisiblePosition FrameSelection::modifyExtendingForward(TextGranularity granularity)
716{
717    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
718    switch (granularity) {
719    case CharacterGranularity:
720        pos = pos.next(CannotCrossEditingBoundary);
721        break;
722    case WordGranularity:
723        pos = nextWordPositionForPlatform(pos);
724        break;
725    case SentenceGranularity:
726        pos = nextSentencePosition(pos);
727        break;
728    case LineGranularity:
729        pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
730        break;
731    case ParagraphGranularity:
732        pos = nextParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
733        break;
734#if PLATFORM(IOS)
735    case DocumentGranularity:
736        ASSERT_NOT_REACHED();
737        break;
738#endif
739    case SentenceBoundary:
740        pos = endOfSentence(endForPlatform());
741        break;
742    case LineBoundary:
743        pos = logicalEndOfLine(endForPlatform());
744        break;
745    case ParagraphBoundary:
746        pos = endOfParagraph(endForPlatform());
747        break;
748    case DocumentBoundary:
749        pos = endForPlatform();
750        if (isEditablePosition(pos.deepEquivalent()))
751            pos = endOfEditableContent(pos);
752        else
753            pos = endOfDocument(pos);
754        break;
755    }
756#if ENABLE(USERSELECT_ALL)
757     adjustPositionForUserSelectAll(pos, directionOfEnclosingBlock() == LTR);
758#endif
759    return pos;
760}
761
762VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity)
763{
764    VisiblePosition pos;
765    switch (granularity) {
766    case CharacterGranularity:
767        if (isRange()) {
768            if (directionOfSelection() == LTR)
769                pos = VisiblePosition(m_selection.end(), m_selection.affinity());
770            else
771                pos = VisiblePosition(m_selection.start(), m_selection.affinity());
772        } else
773            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
774        break;
775    case WordGranularity: {
776        // Visual word movement relies on isWordTextBreak which is not implemented in WinCE and QT.
777        // https://bugs.webkit.org/show_bug.cgi?id=81136.
778        bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight();
779        pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
780        break;
781    }
782    case SentenceGranularity:
783    case LineGranularity:
784    case ParagraphGranularity:
785    case SentenceBoundary:
786    case ParagraphBoundary:
787    case DocumentBoundary:
788        // FIXME: Implement all of the above.
789        pos = modifyMovingForward(granularity);
790        break;
791    case LineBoundary:
792        pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
793        break;
794#if PLATFORM(IOS)
795    case DocumentGranularity:
796        ASSERT_NOT_REACHED();
797        break;
798#endif
799    }
800    return pos;
801}
802
803VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity)
804{
805    VisiblePosition pos;
806    // FIXME: Stay in editable content for the less common granularities.
807    switch (granularity) {
808    case CharacterGranularity:
809        if (isRange())
810            pos = VisiblePosition(m_selection.end(), m_selection.affinity());
811        else
812            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
813        break;
814    case WordGranularity:
815        pos = nextWordPositionForPlatform(VisiblePosition(m_selection.extent(), m_selection.affinity()));
816        break;
817    case SentenceGranularity:
818        pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
819        break;
820    case LineGranularity: {
821        // down-arrowing from a range selection that ends at the start of a line needs
822        // to leave the selection at that line start (no need to call nextLinePosition!)
823        pos = endForPlatform();
824        if (!isRange() || !isStartOfLine(pos))
825            pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(START));
826        break;
827    }
828    case ParagraphGranularity:
829        pos = nextParagraphPosition(endForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
830        break;
831#if PLATFORM(IOS)
832    case DocumentGranularity:
833        ASSERT_NOT_REACHED();
834        break;
835#endif
836    case SentenceBoundary:
837        pos = endOfSentence(endForPlatform());
838        break;
839    case LineBoundary:
840        pos = logicalEndOfLine(endForPlatform());
841        break;
842    case ParagraphBoundary:
843        pos = endOfParagraph(endForPlatform());
844        break;
845    case DocumentBoundary:
846        pos = endForPlatform();
847        if (isEditablePosition(pos.deepEquivalent()))
848            pos = endOfEditableContent(pos);
849        else
850            pos = endOfDocument(pos);
851        break;
852    }
853    return pos;
854}
855
856VisiblePosition FrameSelection::modifyExtendingLeft(TextGranularity granularity)
857{
858    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
859
860    // The difference between modifyExtendingLeft and modifyExtendingBackward is:
861    // modifyExtendingBackward always extends backward logically.
862    // modifyExtendingLeft behaves the same as modifyExtendingBackward except for extending character or word,
863    // it extends backward logically if the enclosing block is LTR direction,
864    // but it extends forward logically if the enclosing block is RTL direction.
865    switch (granularity) {
866    case CharacterGranularity:
867        if (directionOfEnclosingBlock() == LTR)
868            pos = pos.previous(CannotCrossEditingBoundary);
869        else
870            pos = pos.next(CannotCrossEditingBoundary);
871        break;
872    case WordGranularity:
873        if (directionOfEnclosingBlock() == LTR)
874            pos = previousWordPosition(pos);
875        else
876            pos = nextWordPositionForPlatform(pos);
877        break;
878    case LineBoundary:
879        if (directionOfEnclosingBlock() == LTR)
880            pos = modifyExtendingBackward(granularity);
881        else
882            pos = modifyExtendingForward(granularity);
883        break;
884    case SentenceGranularity:
885    case LineGranularity:
886    case ParagraphGranularity:
887    case SentenceBoundary:
888    case ParagraphBoundary:
889    case DocumentBoundary:
890        pos = modifyExtendingBackward(granularity);
891        break;
892#if PLATFORM(IOS)
893    case DocumentGranularity:
894        ASSERT_NOT_REACHED();
895        break;
896#endif
897    }
898#if ENABLE(USERSELECT_ALL)
899    adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
900#endif
901    return pos;
902}
903
904VisiblePosition FrameSelection::modifyExtendingBackward(TextGranularity granularity)
905{
906    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
907
908    // Extending a selection backward by word or character from just after a table selects
909    // the table.  This "makes sense" from the user perspective, esp. when deleting.
910    // It was done here instead of in VisiblePosition because we want VPs to iterate
911    // over everything.
912    switch (granularity) {
913    case CharacterGranularity:
914        pos = pos.previous(CannotCrossEditingBoundary);
915        break;
916    case WordGranularity:
917        pos = previousWordPosition(pos);
918        break;
919    case SentenceGranularity:
920        pos = previousSentencePosition(pos);
921        break;
922    case LineGranularity:
923        pos = previousLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
924        break;
925    case ParagraphGranularity:
926        pos = previousParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
927        break;
928    case SentenceBoundary:
929        pos = startOfSentence(startForPlatform());
930        break;
931    case LineBoundary:
932        pos = logicalStartOfLine(startForPlatform());
933        break;
934    case ParagraphBoundary:
935        pos = startOfParagraph(startForPlatform());
936        break;
937    case DocumentBoundary:
938        pos = startForPlatform();
939        if (isEditablePosition(pos.deepEquivalent()))
940            pos = startOfEditableContent(pos);
941        else
942            pos = startOfDocument(pos);
943        break;
944#if PLATFORM(IOS)
945    case DocumentGranularity:
946        ASSERT_NOT_REACHED();
947        break;
948#endif
949    }
950#if ENABLE(USERSELECT_ALL)
951    adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
952#endif
953    return pos;
954}
955
956VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity)
957{
958    VisiblePosition pos;
959    switch (granularity) {
960    case CharacterGranularity:
961        if (isRange())
962            if (directionOfSelection() == LTR)
963                pos = VisiblePosition(m_selection.start(), m_selection.affinity());
964            else
965                pos = VisiblePosition(m_selection.end(), m_selection.affinity());
966        else
967            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
968        break;
969    case WordGranularity: {
970        bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight();
971        pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
972        break;
973    }
974    case SentenceGranularity:
975    case LineGranularity:
976    case ParagraphGranularity:
977    case SentenceBoundary:
978    case ParagraphBoundary:
979    case DocumentBoundary:
980        // FIXME: Implement all of the above.
981        pos = modifyMovingBackward(granularity);
982        break;
983    case LineBoundary:
984        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
985        break;
986#if PLATFORM(IOS)
987    case DocumentGranularity:
988        ASSERT_NOT_REACHED();
989        break;
990#endif
991    }
992    return pos;
993}
994
995VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity)
996{
997    VisiblePosition pos;
998    switch (granularity) {
999    case CharacterGranularity:
1000        if (isRange())
1001            pos = VisiblePosition(m_selection.start(), m_selection.affinity());
1002        else
1003            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
1004        break;
1005    case WordGranularity:
1006        pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
1007        break;
1008    case SentenceGranularity:
1009        pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
1010        break;
1011    case LineGranularity:
1012        pos = previousLinePosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
1013        break;
1014    case ParagraphGranularity:
1015        pos = previousParagraphPosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
1016        break;
1017    case SentenceBoundary:
1018        pos = startOfSentence(startForPlatform());
1019        break;
1020    case LineBoundary:
1021        pos = logicalStartOfLine(startForPlatform());
1022        break;
1023    case ParagraphBoundary:
1024        pos = startOfParagraph(startForPlatform());
1025        break;
1026    case DocumentBoundary:
1027        pos = startForPlatform();
1028        if (isEditablePosition(pos.deepEquivalent()))
1029            pos = startOfEditableContent(pos);
1030        else
1031            pos = startOfDocument(pos);
1032        break;
1033#if PLATFORM(IOS)
1034    case DocumentGranularity:
1035        ASSERT_NOT_REACHED();
1036        break;
1037#endif
1038    }
1039    return pos;
1040}
1041
1042static bool isBoundary(TextGranularity granularity)
1043{
1044    return granularity == LineBoundary || granularity == ParagraphBoundary || granularity == DocumentBoundary;
1045}
1046
1047bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered)
1048{
1049    if (userTriggered == UserTriggered) {
1050        FrameSelection trialFrameSelection;
1051        trialFrameSelection.setSelection(m_selection);
1052        trialFrameSelection.modify(alter, direction, granularity, NotUserTriggered);
1053
1054        bool change = shouldChangeSelection(trialFrameSelection.selection());
1055        if (!change)
1056            return false;
1057
1058        if (trialFrameSelection.selection().isRange() && m_selection.isCaret() && !dispatchSelectStart())
1059            return false;
1060    }
1061
1062    willBeModified(alter, direction);
1063
1064    bool wasRange = m_selection.isRange();
1065    Position originalStartPosition = m_selection.start();
1066    VisiblePosition position;
1067    switch (direction) {
1068    case DirectionRight:
1069        if (alter == AlterationMove)
1070            position = modifyMovingRight(granularity);
1071        else
1072            position = modifyExtendingRight(granularity);
1073        break;
1074    case DirectionForward:
1075        if (alter == AlterationExtend)
1076            position = modifyExtendingForward(granularity);
1077        else
1078            position = modifyMovingForward(granularity);
1079        break;
1080    case DirectionLeft:
1081        if (alter == AlterationMove)
1082            position = modifyMovingLeft(granularity);
1083        else
1084            position = modifyExtendingLeft(granularity);
1085        break;
1086    case DirectionBackward:
1087        if (alter == AlterationExtend)
1088            position = modifyExtendingBackward(granularity);
1089        else
1090            position = modifyMovingBackward(granularity);
1091        break;
1092    }
1093
1094    if (position.isNull())
1095        return false;
1096
1097    if (isSpatialNavigationEnabled(m_frame))
1098        if (!wasRange && alter == AlterationMove && position == originalStartPosition)
1099            return false;
1100
1101    // Some of the above operations set an xPosForVerticalArrowNavigation.
1102    // Setting a selection will clear it, so save it to possibly restore later.
1103    // Note: the START position type is arbitrary because it is unused, it would be
1104    // the requested position type if there were no xPosForVerticalArrowNavigation set.
1105    LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(START);
1106    m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_frame) || alter == AlterationExtend);
1107
1108    switch (alter) {
1109    case AlterationMove:
1110        moveTo(position, userTriggered);
1111        break;
1112    case AlterationExtend:
1113
1114        if (!m_selection.isCaret()
1115            && (granularity == WordGranularity || granularity == ParagraphGranularity || granularity == LineGranularity)
1116            && m_frame && !m_frame->editor().behavior().shouldExtendSelectionByWordOrLineAcrossCaret()) {
1117            // Don't let the selection go across the base position directly. Needed to match mac
1118            // behavior when, for instance, word-selecting backwards starting with the caret in
1119            // the middle of a word and then word-selecting forward, leaving the caret in the
1120            // same place where it was, instead of directly selecting to the end of the word.
1121            VisibleSelection newSelection = m_selection;
1122            newSelection.setExtent(position);
1123            if (m_selection.isBaseFirst() != newSelection.isBaseFirst())
1124                position = m_selection.base();
1125        }
1126
1127        // Standard Mac behavior when extending to a boundary is grow the selection rather than leaving the
1128        // base in place and moving the extent. Matches NSTextView.
1129        if (!m_frame || !m_frame->editor().behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity))
1130            setExtent(position, userTriggered);
1131        else {
1132            TextDirection textDirection = directionOfEnclosingBlock();
1133            if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft))
1134                setEnd(position, userTriggered);
1135            else
1136                setStart(position, userTriggered);
1137        }
1138        break;
1139    }
1140
1141    if (granularity == LineGranularity || granularity == ParagraphGranularity)
1142        m_xPosForVerticalArrowNavigation = x;
1143
1144    if (userTriggered == UserTriggered)
1145        m_granularity = CharacterGranularity;
1146
1147    setCaretRectNeedsUpdate();
1148
1149    return true;
1150}
1151
1152// FIXME: Maybe baseline would be better?
1153static bool absoluteCaretY(const VisiblePosition &c, int &y)
1154{
1155    IntRect rect = c.absoluteCaretBounds();
1156    if (rect.isEmpty())
1157        return false;
1158    y = rect.y() + rect.height() / 2;
1159    return true;
1160}
1161
1162bool FrameSelection::modify(EAlteration alter, unsigned verticalDistance, VerticalDirection direction, EUserTriggered userTriggered, CursorAlignOnScroll align)
1163{
1164    if (!verticalDistance)
1165        return false;
1166
1167    if (userTriggered == UserTriggered) {
1168        FrameSelection trialFrameSelection;
1169        trialFrameSelection.setSelection(m_selection);
1170        trialFrameSelection.modify(alter, verticalDistance, direction, NotUserTriggered);
1171
1172        bool change = shouldChangeSelection(trialFrameSelection.selection());
1173        if (!change)
1174            return false;
1175    }
1176
1177    willBeModified(alter, direction == DirectionUp ? DirectionBackward : DirectionForward);
1178
1179    VisiblePosition pos;
1180    LayoutUnit xPos = 0;
1181    switch (alter) {
1182    case AlterationMove:
1183        pos = VisiblePosition(direction == DirectionUp ? m_selection.start() : m_selection.end(), m_selection.affinity());
1184        xPos = lineDirectionPointForBlockDirectionNavigation(direction == DirectionUp ? START : END);
1185        m_selection.setAffinity(direction == DirectionUp ? UPSTREAM : DOWNSTREAM);
1186        break;
1187    case AlterationExtend:
1188        pos = VisiblePosition(m_selection.extent(), m_selection.affinity());
1189        xPos = lineDirectionPointForBlockDirectionNavigation(EXTENT);
1190        m_selection.setAffinity(DOWNSTREAM);
1191        break;
1192    }
1193
1194    int startY;
1195    if (!absoluteCaretY(pos, startY))
1196        return false;
1197    if (direction == DirectionUp)
1198        startY = -startY;
1199    int lastY = startY;
1200
1201    VisiblePosition result;
1202    VisiblePosition next;
1203    for (VisiblePosition p = pos; ; p = next) {
1204        if (direction == DirectionUp)
1205            next = previousLinePosition(p, xPos);
1206        else
1207            next = nextLinePosition(p, xPos);
1208
1209        if (next.isNull() || next == p)
1210            break;
1211        int nextY;
1212        if (!absoluteCaretY(next, nextY))
1213            break;
1214        if (direction == DirectionUp)
1215            nextY = -nextY;
1216        if (nextY - startY > static_cast<int>(verticalDistance))
1217            break;
1218        if (nextY >= lastY) {
1219            lastY = nextY;
1220            result = next;
1221        }
1222    }
1223
1224    if (result.isNull())
1225        return false;
1226
1227    switch (alter) {
1228    case AlterationMove:
1229        moveTo(result, userTriggered, align);
1230        break;
1231    case AlterationExtend:
1232        setExtent(result, userTriggered);
1233        break;
1234    }
1235
1236    if (userTriggered == UserTriggered)
1237        m_granularity = CharacterGranularity;
1238
1239    m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_frame) || alter == AlterationExtend);
1240
1241    return true;
1242}
1243
1244LayoutUnit FrameSelection::lineDirectionPointForBlockDirectionNavigation(EPositionType type)
1245{
1246    LayoutUnit x = 0;
1247
1248    if (isNone())
1249        return x;
1250
1251    Position pos;
1252    switch (type) {
1253    case START:
1254        pos = m_selection.start();
1255        break;
1256    case END:
1257        pos = m_selection.end();
1258        break;
1259    case BASE:
1260        pos = m_selection.base();
1261        break;
1262    case EXTENT:
1263        pos = m_selection.extent();
1264        break;
1265    }
1266
1267    Frame* frame = pos.anchorNode()->document().frame();
1268    if (!frame)
1269        return x;
1270
1271    if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation()) {
1272        VisiblePosition visiblePosition(pos, m_selection.affinity());
1273        // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
1274        // after the selection is created and before this function is called.
1275        x = visiblePosition.isNotNull() ? visiblePosition.lineDirectionPointForBlockDirectionNavigation() : 0;
1276        m_xPosForVerticalArrowNavigation = x;
1277    } else
1278        x = m_xPosForVerticalArrowNavigation;
1279
1280    return x;
1281}
1282
1283void FrameSelection::clear()
1284{
1285    m_granularity = CharacterGranularity;
1286    setSelection(VisibleSelection());
1287}
1288
1289void FrameSelection::prepareForDestruction()
1290{
1291    m_granularity = CharacterGranularity;
1292
1293#if ENABLE(TEXT_CARET)
1294    m_caretBlinkTimer.stop();
1295#endif
1296
1297    RenderView* view = m_frame->contentRenderer();
1298    if (view)
1299        view->clearSelection();
1300
1301    setSelectionWithoutUpdatingAppearance(VisibleSelection(), defaultSetSelectionOptions(), AlignCursorOnScrollIfNeeded, CharacterGranularity);
1302    m_previousCaretNode.clear();
1303}
1304
1305void FrameSelection::setStart(const VisiblePosition &pos, EUserTriggered trigger)
1306{
1307    if (m_selection.isBaseFirst())
1308        setBase(pos, trigger);
1309    else
1310        setExtent(pos, trigger);
1311}
1312
1313void FrameSelection::setEnd(const VisiblePosition &pos, EUserTriggered trigger)
1314{
1315    if (m_selection.isBaseFirst())
1316        setExtent(pos, trigger);
1317    else
1318        setBase(pos, trigger);
1319}
1320
1321void FrameSelection::setBase(const VisiblePosition &pos, EUserTriggered userTriggered)
1322{
1323    const bool selectionHasDirection = true;
1324    setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity(), selectionHasDirection), defaultSetSelectionOptions(userTriggered));
1325}
1326
1327void FrameSelection::setExtent(const VisiblePosition &pos, EUserTriggered userTriggered)
1328{
1329    const bool selectionHasDirection = true;
1330    setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity(), selectionHasDirection), defaultSetSelectionOptions(userTriggered));
1331}
1332
1333void FrameSelection::setBase(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
1334{
1335    const bool selectionHasDirection = true;
1336    setSelection(VisibleSelection(pos, m_selection.extent(), affinity, selectionHasDirection), defaultSetSelectionOptions(userTriggered));
1337}
1338
1339void FrameSelection::setExtent(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
1340{
1341    const bool selectionHasDirection = true;
1342    setSelection(VisibleSelection(m_selection.base(), pos, affinity, selectionHasDirection), defaultSetSelectionOptions(userTriggered));
1343}
1344
1345void CaretBase::clearCaretRect()
1346{
1347    m_caretLocalRect = LayoutRect();
1348}
1349
1350bool CaretBase::updateCaretRect(Document* document, const VisiblePosition& caretPosition)
1351{
1352    document->updateLayoutIgnorePendingStylesheets();
1353    m_caretRectNeedsUpdate = false;
1354    RenderObject* renderer;
1355    m_caretLocalRect = localCaretRectInRendererForCaretPainting(caretPosition, renderer);
1356    return !m_caretLocalRect.isEmpty();
1357}
1358
1359RenderObject* FrameSelection::caretRendererWithoutUpdatingLayout() const
1360{
1361    return rendererForCaretPainting(m_selection.start().deprecatedNode());
1362}
1363
1364RenderObject* DragCaretController::caretRenderer() const
1365{
1366    return rendererForCaretPainting(m_position.deepEquivalent().deprecatedNode());
1367}
1368
1369static bool isNonOrphanedCaret(const VisibleSelection& selection)
1370{
1371    return selection.isCaret() && !selection.start().isOrphan() && !selection.end().isOrphan();
1372}
1373
1374IntRect FrameSelection::absoluteCaretBounds()
1375{
1376    if (!m_frame)
1377        return IntRect();
1378    updateSelectionByUpdatingLayoutOrStyle(*m_frame);
1379    recomputeCaretRect();
1380    return m_absCaretBounds;
1381}
1382
1383static void repaintCaretForLocalRect(Node* node, const LayoutRect& rect)
1384{
1385    RenderObject* caretPainter = rendererForCaretPainting(node);
1386    if (!caretPainter)
1387        return;
1388
1389    caretPainter->repaintRectangle(rect);
1390}
1391
1392bool FrameSelection::recomputeCaretRect()
1393{
1394    if (!shouldUpdateCaretRect())
1395        return false;
1396
1397    if (!m_frame)
1398        return false;
1399
1400    FrameView* v = m_frame->document()->view();
1401    if (!v)
1402        return false;
1403
1404    LayoutRect oldRect = localCaretRectWithoutUpdate();
1405
1406    RefPtr<Node> caretNode = m_previousCaretNode;
1407    if (shouldUpdateCaretRect()) {
1408        if (!isNonOrphanedCaret(m_selection))
1409            clearCaretRect();
1410        else {
1411            VisiblePosition visibleStart = m_selection.visibleStart();
1412            if (updateCaretRect(m_frame->document(), visibleStart)) {
1413                caretNode = visibleStart.deepEquivalent().deprecatedNode();
1414                m_absCaretBoundsDirty = true;
1415            }
1416        }
1417    }
1418    LayoutRect newRect = localCaretRectWithoutUpdate();
1419
1420    if (caretNode == m_previousCaretNode && oldRect == newRect && !m_absCaretBoundsDirty)
1421        return false;
1422
1423    IntRect oldAbsCaretBounds = m_absCaretBounds;
1424    m_absCaretBounds = absoluteBoundsForLocalCaretRect(rendererForCaretPainting(caretNode.get()), newRect);
1425
1426    if (m_absCaretBoundsDirty && m_selection.isCaret()) // We should be able to always assert this condition.
1427        ASSERT(m_absCaretBounds == m_selection.visibleStart().absoluteCaretBounds());
1428
1429    m_absCaretBoundsDirty = false;
1430
1431    if (caretNode == m_previousCaretNode && oldAbsCaretBounds == m_absCaretBounds)
1432        return false;
1433
1434#if ENABLE(TEXT_CARET)
1435    if (RenderView* view = m_frame->document()->renderView()) {
1436        bool previousOrNewCaretNodeIsContentEditable = m_selection.isContentEditable() || (m_previousCaretNode && m_previousCaretNode->isContentEditable());
1437        if (shouldRepaintCaret(view, previousOrNewCaretNodeIsContentEditable)) {
1438            if (m_previousCaretNode)
1439                repaintCaretForLocalRect(m_previousCaretNode.get(), oldRect);
1440            m_previousCaretNode = caretNode;
1441            repaintCaretForLocalRect(caretNode.get(), newRect);
1442        }
1443    }
1444#endif
1445    return true;
1446}
1447
1448bool CaretBase::shouldRepaintCaret(const RenderView* view, bool isContentEditable) const
1449{
1450    ASSERT(view);
1451    Frame* frame = &view->frameView().frame(); // The frame where the selection started.
1452    bool caretBrowsing = frame && frame->settings().caretBrowsingEnabled();
1453    return (caretBrowsing || isContentEditable);
1454}
1455
1456void FrameSelection::invalidateCaretRect()
1457{
1458    if (!isCaret())
1459        return;
1460
1461    CaretBase::invalidateCaretRect(m_selection.start().deprecatedNode(), recomputeCaretRect());
1462}
1463
1464void CaretBase::invalidateCaretRect(Node* node, bool caretRectChanged)
1465{
1466    // EDIT FIXME: This is an unfortunate hack.
1467    // Basically, we can't trust this layout position since we
1468    // can't guarantee that the check to see if we are in unrendered
1469    // content will work at this point. We may have to wait for
1470    // a layout and re-render of the document to happen. So, resetting this
1471    // flag will cause another caret layout to happen the first time
1472    // that we try to paint the caret after this call. That one will work since
1473    // it happens after the document has accounted for any editing
1474    // changes which may have been done.
1475    // And, we need to leave this layout here so the caret moves right
1476    // away after clicking.
1477    m_caretRectNeedsUpdate = true;
1478
1479    if (caretRectChanged)
1480        return;
1481
1482    if (RenderView* view = node->document().renderView()) {
1483        if (shouldRepaintCaret(view, node->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable)))
1484            repaintCaretForLocalRect(node, localCaretRectWithoutUpdate());
1485    }
1486}
1487
1488void FrameSelection::paintCaret(GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect)
1489{
1490    if (m_selection.isCaret() && m_caretPaint)
1491        CaretBase::paintCaret(m_selection.start().deprecatedNode(), context, paintOffset, clipRect);
1492}
1493
1494void CaretBase::paintCaret(Node* node, GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const
1495{
1496#if ENABLE(TEXT_CARET)
1497    if (m_caretVisibility == Hidden)
1498        return;
1499
1500    LayoutRect drawingRect = localCaretRectWithoutUpdate();
1501    RenderObject* renderer = rendererForCaretPainting(node);
1502    if (renderer && renderer->isBox())
1503        toRenderBox(renderer)->flipForWritingMode(drawingRect);
1504    drawingRect.moveBy(roundedIntPoint(paintOffset));
1505    LayoutRect caret = intersection(drawingRect, clipRect);
1506    if (caret.isEmpty())
1507        return;
1508
1509    Color caretColor = Color::black;
1510    ColorSpace colorSpace = ColorSpaceDeviceRGB;
1511    Element* element = node->isElementNode() ? toElement(node) : node->parentElement();
1512
1513    if (element && element->renderer()) {
1514        caretColor = element->renderer()->style().visitedDependentColor(CSSPropertyColor);
1515        colorSpace = element->renderer()->style().colorSpace();
1516    }
1517
1518    context->fillRect(caret, caretColor, colorSpace);
1519#else
1520    UNUSED_PARAM(node);
1521    UNUSED_PARAM(context);
1522    UNUSED_PARAM(paintOffset);
1523    UNUSED_PARAM(clipRect);
1524#endif
1525}
1526
1527void FrameSelection::debugRenderer(RenderObject* r, bool selected) const
1528{
1529    if (r->node()->isElementNode()) {
1530        Element* element = toElement(r->node());
1531        fprintf(stderr, "%s%s\n", selected ? "==> " : "    ", element->localName().string().utf8().data());
1532    } else if (r->isText()) {
1533        RenderText* textRenderer = toRenderText(r);
1534        if (!textRenderer->textLength() || !textRenderer->firstTextBox()) {
1535            fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : "    ");
1536            return;
1537        }
1538
1539        static const int max = 36;
1540        String text = textRenderer->text();
1541        int textLength = text.length();
1542        if (selected) {
1543            int offset = 0;
1544            if (r->node() == m_selection.start().containerNode())
1545                offset = m_selection.start().computeOffsetInContainerNode();
1546            else if (r->node() == m_selection.end().containerNode())
1547                offset = m_selection.end().computeOffsetInContainerNode();
1548
1549            int pos;
1550            InlineTextBox* box = textRenderer->findNextInlineTextBox(offset, pos);
1551            text = text.substring(box->start(), box->len());
1552
1553            String show;
1554            int mid = max / 2;
1555            int caret = 0;
1556
1557            // text is shorter than max
1558            if (textLength < max) {
1559                show = text;
1560                caret = pos;
1561            } else if (pos - mid < 0) {
1562                // too few characters to left
1563                show = text.left(max - 3) + "...";
1564                caret = pos;
1565            } else if (pos - mid >= 0 && pos + mid <= textLength) {
1566                // enough characters on each side
1567                show = "..." + text.substring(pos - mid + 3, max - 6) + "...";
1568                caret = mid;
1569            } else {
1570                // too few characters on right
1571                show = "..." + text.right(max - 3);
1572                caret = pos - (textLength - show.length());
1573            }
1574
1575            show.replace('\n', ' ');
1576            show.replace('\r', ' ');
1577            fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.utf8().data(), pos);
1578            fprintf(stderr, "           ");
1579            for (int i = 0; i < caret; i++)
1580                fprintf(stderr, " ");
1581            fprintf(stderr, "^\n");
1582        } else {
1583            if ((int)text.length() > max)
1584                text = text.left(max - 3) + "...";
1585            else
1586                text = text.left(max);
1587            fprintf(stderr, "    #text : \"%s\"\n", text.utf8().data());
1588        }
1589    }
1590}
1591
1592bool FrameSelection::contains(const LayoutPoint& point)
1593{
1594    Document* document = m_frame->document();
1595
1596    // Treat a collapsed selection like no selection.
1597    if (!isRange())
1598        return false;
1599    if (!document->renderView())
1600        return false;
1601
1602    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1603    HitTestResult result(point);
1604    document->renderView()->hitTest(request, result);
1605    Node* innerNode = result.innerNode();
1606    if (!innerNode || !innerNode->renderer())
1607        return false;
1608
1609    VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint(), nullptr));
1610    if (visiblePos.isNull())
1611        return false;
1612
1613    if (m_selection.visibleStart().isNull() || m_selection.visibleEnd().isNull())
1614        return false;
1615
1616    Position start(m_selection.visibleStart().deepEquivalent());
1617    Position end(m_selection.visibleEnd().deepEquivalent());
1618    Position p(visiblePos.deepEquivalent());
1619
1620    return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;
1621}
1622
1623// Workaround for the fact that it's hard to delete a frame.
1624// Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
1625// Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
1626// for the focus to move to another frame. So instead we call it from places where we are selecting with the
1627// mouse or the keyboard after setting the selection.
1628void FrameSelection::selectFrameElementInParentIfFullySelected()
1629{
1630    // Find the parent frame; if there is none, then we have nothing to do.
1631    Frame* parent = m_frame->tree().parent();
1632    if (!parent)
1633        return;
1634    Page* page = m_frame->page();
1635    if (!page)
1636        return;
1637
1638    // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
1639    if (!isRange())
1640        return;
1641    if (!isStartOfDocument(selection().visibleStart()))
1642        return;
1643    if (!isEndOfDocument(selection().visibleEnd()))
1644        return;
1645
1646    // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
1647    Element* ownerElement = m_frame->ownerElement();
1648    if (!ownerElement)
1649        return;
1650    ContainerNode* ownerElementParent = ownerElement->parentNode();
1651    if (!ownerElementParent)
1652        return;
1653
1654    // 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.
1655    if (!ownerElementParent->hasEditableStyle())
1656        return;
1657
1658    // Create compute positions before and after the element.
1659    unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
1660    VisiblePosition beforeOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex, Position::PositionIsOffsetInAnchor)));
1661    VisiblePosition afterOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex + 1, Position::PositionIsOffsetInAnchor), VP_UPSTREAM_IF_POSSIBLE));
1662
1663    // Focus on the parent frame, and then select from before this element to after.
1664    VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
1665    if (parent->selection().shouldChangeSelection(newSelection)) {
1666        page->focusController().setFocusedFrame(parent);
1667        parent->selection().setSelection(newSelection);
1668    }
1669}
1670
1671void FrameSelection::selectAll()
1672{
1673    Document* document = m_frame->document();
1674
1675    Element* focusedElement = document->focusedElement();
1676    if (focusedElement && focusedElement->hasTagName(selectTag)) {
1677        HTMLSelectElement* selectElement = toHTMLSelectElement(document->focusedElement());
1678        if (selectElement->canSelectAll()) {
1679            selectElement->selectAll();
1680            return;
1681        }
1682    }
1683
1684    RefPtr<Node> root = 0;
1685    Node* selectStartTarget = 0;
1686    if (m_selection.isContentEditable()) {
1687        root = highestEditableRoot(m_selection.start());
1688        if (Node* shadowRoot = m_selection.nonBoundaryShadowTreeRootNode())
1689            selectStartTarget = shadowRoot->shadowHost();
1690        else
1691            selectStartTarget = root.get();
1692    } else {
1693        if (m_selection.isNone() && focusedElement) {
1694            if (focusedElement->isTextFormControl()) {
1695                toHTMLTextFormControlElement(focusedElement)->select();
1696                return;
1697            }
1698            root = focusedElement->nonBoundaryShadowTreeRootNode();
1699        } else
1700            root = m_selection.nonBoundaryShadowTreeRootNode();
1701
1702        if (root)
1703            selectStartTarget = root->shadowHost();
1704        else {
1705            root = document->documentElement();
1706            selectStartTarget = document->body();
1707        }
1708    }
1709    if (!root)
1710        return;
1711
1712    if (selectStartTarget && !selectStartTarget->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true)))
1713        return;
1714
1715    VisibleSelection newSelection(VisibleSelection::selectionFromContentsOfNode(root.get()));
1716
1717    if (shouldChangeSelection(newSelection))
1718        setSelection(newSelection, defaultSetSelectionOptions() | FireSelectEvent);
1719}
1720
1721bool FrameSelection::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
1722{
1723    if (!range || !range->startContainer() || !range->endContainer())
1724        return false;
1725    ASSERT(&range->startContainer()->document() == &range->endContainer()->document());
1726
1727    VisibleSelection newSelection(range, affinity);
1728
1729#if PLATFORM(IOS)
1730    // FIXME: Why do we need this check only in iOS?
1731    if (range->startContainer() && range->endContainer() && newSelection.isNone())
1732        return false;
1733#endif
1734
1735    setSelection(newSelection, ClearTypingStyle | (closeTyping ? CloseTyping : 0));
1736    return true;
1737}
1738
1739void FrameSelection::focusedOrActiveStateChanged()
1740{
1741    bool activeAndFocused = isFocusedAndActive();
1742    Ref<Document> document(*m_frame->document());
1743
1744    document->updateStyleIfNeeded();
1745
1746#if USE(UIKIT_EDITING)
1747    // Caret blinking (blinks | does not blink)
1748    if (activeAndFocused)
1749        setSelectionFromNone();
1750    setCaretVisible(activeAndFocused);
1751#else
1752    // Because RenderObject::selectionBackgroundColor() and
1753    // RenderObject::selectionForegroundColor() check if the frame is active,
1754    // we have to update places those colors were painted.
1755    if (RenderView* view = document->renderView())
1756        view->repaintSelection();
1757
1758    // Caret appears in the active frame.
1759    if (activeAndFocused)
1760        setSelectionFromNone();
1761    setCaretVisibility(activeAndFocused ? Visible : Hidden);
1762
1763    // Update for caps lock state
1764    m_frame->eventHandler().capsLockStateMayHaveChanged();
1765
1766    // Because StyleResolver::checkOneSelector() and
1767    // RenderTheme::isFocused() check if the frame is active, we have to
1768    // update style and theme state that depended on those.
1769    if (Element* element = document->focusedElement()) {
1770        element->setNeedsStyleRecalc();
1771        if (RenderObject* renderer = element->renderer())
1772            if (renderer && renderer->style().hasAppearance())
1773                renderer->theme().stateChanged(*renderer, ControlStates::FocusState);
1774    }
1775#endif
1776}
1777
1778void FrameSelection::pageActivationChanged()
1779{
1780    focusedOrActiveStateChanged();
1781}
1782
1783void FrameSelection::setFocused(bool flag)
1784{
1785    if (m_focused == flag)
1786        return;
1787    m_focused = flag;
1788
1789    focusedOrActiveStateChanged();
1790}
1791
1792bool FrameSelection::isFocusedAndActive() const
1793{
1794    return m_focused && m_frame->page() && m_frame->page()->focusController().isActive();
1795}
1796
1797#if ENABLE(TEXT_CARET)
1798inline static bool shouldStopBlinkingDueToTypingCommand(Frame* frame)
1799{
1800    return frame->editor().lastEditCommand() && frame->editor().lastEditCommand()->shouldStopCaretBlinking();
1801}
1802#endif
1803
1804void FrameSelection::updateAppearance()
1805{
1806#if PLATFORM(IOS)
1807    if (!m_updateAppearanceEnabled)
1808        return;
1809#endif
1810
1811    // Paint a block cursor instead of a caret in overtype mode unless the caret is at the end of a line (in this case
1812    // the FrameSelection will paint a blinking caret as usual).
1813    VisibleSelection oldSelection = selection();
1814    VisiblePosition forwardPosition;
1815    if (m_shouldShowBlockCursor && oldSelection.isCaret()) {
1816        forwardPosition = modifyExtendingForward(CharacterGranularity);
1817        m_caretPaint = forwardPosition.isNull();
1818    }
1819
1820#if ENABLE(TEXT_CARET)
1821    bool caretRectChangedOrCleared = recomputeCaretRect();
1822
1823    bool caretBrowsing = m_frame->settings().caretBrowsingEnabled();
1824    bool shouldBlink = caretIsVisible() && isCaret() && (oldSelection.isContentEditable() || caretBrowsing) && forwardPosition.isNull();
1825
1826    // If the caret moved, stop the blink timer so we can restart with a
1827    // black caret in the new location.
1828    if (caretRectChangedOrCleared || !shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame))
1829        m_caretBlinkTimer.stop();
1830
1831    // Start blinking with a black caret. Be sure not to restart if we're
1832    // already blinking in the right location.
1833    if (shouldBlink && !m_caretBlinkTimer.isActive()) {
1834        if (double blinkInterval = m_frame->page()->theme().caretBlinkInterval())
1835            m_caretBlinkTimer.startRepeating(blinkInterval);
1836
1837        if (!m_caretPaint) {
1838            m_caretPaint = true;
1839            invalidateCaretRect();
1840        }
1841    }
1842#endif
1843
1844    RenderView* view = m_frame->contentRenderer();
1845    if (!view)
1846        return;
1847
1848    // Construct a new VisibleSolution, since m_selection is not necessarily valid, and the following steps
1849    // assume a valid selection. See <https://bugs.webkit.org/show_bug.cgi?id=69563> and <rdar://problem/10232866>.
1850    VisibleSelection selection(oldSelection.visibleStart(), forwardPosition.isNotNull() ? forwardPosition : oldSelection.visibleEnd());
1851
1852    if (!selection.isRange()) {
1853        view->clearSelection();
1854        return;
1855    }
1856
1857    // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
1858    // Example: foo <a>bar</a>.  Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.   If we pass [foo, 3]
1859    // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
1860    // and will fill the gap before 'bar'.
1861    Position startPos = selection.start();
1862    Position candidate = startPos.downstream();
1863    if (candidate.isCandidate())
1864        startPos = candidate;
1865    Position endPos = selection.end();
1866    candidate = endPos.upstream();
1867    if (candidate.isCandidate())
1868        endPos = candidate;
1869
1870    // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
1871    // because we don't yet notify the FrameSelection of text removal.
1872    if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
1873        RenderObject* startRenderer = startPos.deprecatedNode()->renderer();
1874        RenderObject* endRenderer = endPos.deprecatedNode()->renderer();
1875        view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
1876    }
1877}
1878
1879void FrameSelection::setCaretVisibility(CaretVisibility visibility)
1880{
1881    if (caretVisibility() == visibility)
1882        return;
1883
1884    // FIXME: We shouldn't trigger a synchrnously layout here.
1885    if (m_frame)
1886        updateSelectionByUpdatingLayoutOrStyle(*m_frame);
1887
1888#if ENABLE(TEXT_CARET)
1889    if (m_caretPaint) {
1890        m_caretPaint = false;
1891        invalidateCaretRect();
1892    }
1893    CaretBase::setCaretVisibility(visibility);
1894#endif
1895
1896    updateAppearance();
1897}
1898
1899void FrameSelection::caretBlinkTimerFired(Timer<FrameSelection>&)
1900{
1901#if ENABLE(TEXT_CARET)
1902    ASSERT(caretIsVisible());
1903    ASSERT(isCaret());
1904    bool caretPaint = m_caretPaint;
1905    if (isCaretBlinkingSuspended() && caretPaint)
1906        return;
1907    m_caretPaint = !caretPaint;
1908    invalidateCaretRect();
1909#endif
1910}
1911
1912// Helper function that tells whether a particular node is an element that has an entire
1913// Frame and FrameView, a <frame>, <iframe>, or <object>.
1914static bool isFrameElement(const Node* n)
1915{
1916    if (!n)
1917        return false;
1918    RenderObject* renderer = n->renderer();
1919    if (!renderer || !renderer->isWidget())
1920        return false;
1921    Widget* widget = toRenderWidget(renderer)->widget();
1922    return widget && widget->isFrameView();
1923}
1924
1925void FrameSelection::setFocusedElementIfNeeded()
1926{
1927    if (isNone() || !isFocused())
1928        return;
1929
1930    bool caretBrowsing = m_frame->settings().caretBrowsingEnabled();
1931    if (caretBrowsing) {
1932        if (Element* anchor = enclosingAnchorElement(m_selection.base())) {
1933            m_frame->page()->focusController().setFocusedElement(anchor, m_frame);
1934            return;
1935        }
1936    }
1937
1938    if (Element* target = m_selection.rootEditableElement()) {
1939        // Walk up the DOM tree to search for an element to focus.
1940        while (target) {
1941            // We don't want to set focus on a subframe when selecting in a parent frame,
1942            // so add the !isFrameElement check here. There's probably a better way to make this
1943            // work in the long term, but this is the safest fix at this time.
1944            if (target->isMouseFocusable() && !isFrameElement(target)) {
1945                m_frame->page()->focusController().setFocusedElement(target, m_frame);
1946                return;
1947            }
1948            target = target->parentOrShadowHostElement();
1949        }
1950        m_frame->document()->setFocusedElement(0);
1951    }
1952
1953    if (caretBrowsing)
1954        m_frame->page()->focusController().setFocusedElement(0, m_frame);
1955}
1956
1957void DragCaretController::paintDragCaret(Frame* frame, GraphicsContext* p, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const
1958{
1959#if ENABLE(TEXT_CARET)
1960    if (m_position.deepEquivalent().deprecatedNode()->document().frame() == frame)
1961        paintCaret(m_position.deepEquivalent().deprecatedNode(), p, paintOffset, clipRect);
1962#else
1963    UNUSED_PARAM(frame);
1964    UNUSED_PARAM(p);
1965    UNUSED_PARAM(paintOffset);
1966    UNUSED_PARAM(clipRect);
1967#endif
1968}
1969
1970PassRefPtr<MutableStyleProperties> FrameSelection::copyTypingStyle() const
1971{
1972    if (!m_typingStyle || !m_typingStyle->style())
1973        return 0;
1974    return m_typingStyle->style()->mutableCopy();
1975}
1976
1977bool FrameSelection::shouldDeleteSelection(const VisibleSelection& selection) const
1978{
1979#if PLATFORM(IOS)
1980    if (m_frame->selectionChangeCallbacksDisabled())
1981        return true;
1982#endif
1983    return m_frame->editor().client()->shouldDeleteRange(selection.toNormalizedRange().get());
1984}
1985
1986FloatRect FrameSelection::selectionBounds(bool clipToVisibleContent) const
1987{
1988    if (!m_frame->document())
1989        return LayoutRect();
1990
1991    updateSelectionByUpdatingLayoutOrStyle(*m_frame);
1992    RenderView* root = m_frame->contentRenderer();
1993    FrameView* view = m_frame->view();
1994    if (!root || !view)
1995        return LayoutRect();
1996
1997    LayoutRect selectionRect = root->selectionBounds(clipToVisibleContent);
1998    return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect)) : selectionRect;
1999}
2000
2001void FrameSelection::getClippedVisibleTextRectangles(Vector<FloatRect>& rectangles) const
2002{
2003    RenderView* root = m_frame->contentRenderer();
2004    if (!root)
2005        return;
2006
2007    FloatRect visibleContentRect = m_frame->view()->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
2008
2009    Vector<FloatQuad> quads;
2010    toNormalizedRange()->textQuads(quads, true);
2011
2012    size_t size = quads.size();
2013    for (size_t i = 0; i < size; ++i) {
2014        FloatRect intersectionRect = intersection(quads[i].enclosingBoundingBox(), visibleContentRect);
2015        if (!intersectionRect.isEmpty())
2016            rectangles.append(intersectionRect);
2017    }
2018}
2019
2020// Scans logically forward from "start", including any child frames.
2021static HTMLFormElement* scanForForm(Element* start)
2022{
2023    if (!start)
2024        return nullptr;
2025
2026    auto descendants = descendantsOfType<HTMLElement>(start->document());
2027    for (auto it = descendants.from(*start), end = descendants.end(); it != end; ++it) {
2028        HTMLElement& element = *it;
2029        if (isHTMLFormElement(&element))
2030            return toHTMLFormElement(&element);
2031        if (isHTMLFormControlElement(element))
2032            return toHTMLFormControlElement(element).form();
2033        if (isHTMLFrameElementBase(element)) {
2034            Document* contentDocument = toHTMLFrameElementBase(element).contentDocument();
2035            if (!contentDocument)
2036                continue;
2037            if (HTMLFormElement* frameResult = scanForForm(contentDocument->documentElement()))
2038                return frameResult;
2039        }
2040    }
2041    return nullptr;
2042}
2043
2044// We look for either the form containing the current focus, or for one immediately after it
2045HTMLFormElement* FrameSelection::currentForm() const
2046{
2047    // Start looking either at the active (first responder) node, or where the selection is.
2048    Element* start = m_frame->document()->focusedElement();
2049    if (!start)
2050        start = m_selection.start().element();
2051    if (!start)
2052        return nullptr;
2053
2054    if (auto form = lineageOfType<HTMLFormElement>(*start).first())
2055        return form;
2056    if (auto formControl = lineageOfType<HTMLFormControlElement>(*start).first())
2057        return formControl->form();
2058
2059    // Try walking forward in the node tree to find a form element.
2060    return scanForForm(start);
2061}
2062
2063void FrameSelection::revealSelection(const ScrollAlignment& alignment, RevealExtentOption revealExtentOption)
2064{
2065    LayoutRect rect;
2066
2067    switch (m_selection.selectionType()) {
2068    case VisibleSelection::NoSelection:
2069        return;
2070    case VisibleSelection::CaretSelection:
2071        rect = absoluteCaretBounds();
2072        break;
2073    case VisibleSelection::RangeSelection:
2074        rect = revealExtentOption == RevealExtent ? VisiblePosition(m_selection.extent()).absoluteCaretBounds() : enclosingIntRect(selectionBounds(false));
2075        break;
2076    }
2077
2078    Position start = m_selection.start();
2079    ASSERT(start.deprecatedNode());
2080    if (start.deprecatedNode() && start.deprecatedNode()->renderer()) {
2081#if PLATFORM(IOS)
2082        if (RenderLayer* layer = start.deprecatedNode()->renderer()->enclosingLayer()) {
2083            if (!m_scrollingSuppressCount) {
2084                layer->setAdjustForIOSCaretWhenScrolling(true);
2085                layer->scrollRectToVisible(rect, alignment, alignment);
2086                layer->setAdjustForIOSCaretWhenScrolling(false);
2087                updateAppearance();
2088                if (m_frame->page())
2089                    m_frame->page()->chrome().client().notifyRevealedSelectionByScrollingFrame(m_frame);
2090            }
2091        }
2092#else
2093        // FIXME: This code only handles scrolling the startContainer's layer, but
2094        // the selection rect could intersect more than just that.
2095        // See <rdar://problem/4799899>.
2096        if (start.deprecatedNode()->renderer()->scrollRectToVisible(rect, alignment, alignment))
2097            updateAppearance();
2098#endif
2099    }
2100}
2101
2102void FrameSelection::setSelectionFromNone()
2103{
2104    // Put a caret inside the body if the entire frame is editable (either the
2105    // entire WebView is editable or designMode is on for this document).
2106
2107    Document* document = m_frame->document();
2108#if !PLATFORM(IOS)
2109    bool caretBrowsing = m_frame->settings().caretBrowsingEnabled();
2110    if (!isNone() || !(document->hasEditableStyle() || caretBrowsing))
2111        return;
2112#else
2113    if (!document || !(isNone() || isStartOfDocument(VisiblePosition(m_selection.start(), m_selection.affinity()))) || !document->hasEditableStyle())
2114        return;
2115#endif
2116
2117    Node* node = document->documentElement();
2118    while (node && !node->hasTagName(bodyTag))
2119        node = NodeTraversal::next(node);
2120    if (node)
2121        setSelection(VisibleSelection(firstPositionInOrBeforeNode(node), DOWNSTREAM));
2122}
2123
2124bool FrameSelection::shouldChangeSelection(const VisibleSelection& newSelection) const
2125{
2126#if PLATFORM(IOS)
2127    if (m_frame->selectionChangeCallbacksDisabled())
2128        return true;
2129#endif
2130    return m_frame->editor().shouldChangeSelection(selection(), newSelection, newSelection.affinity(), false);
2131}
2132
2133bool FrameSelection::dispatchSelectStart()
2134{
2135    Node* selectStartTarget = m_selection.extent().containerNode();
2136    if (!selectStartTarget)
2137        return true;
2138
2139    return selectStartTarget->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
2140}
2141
2142void FrameSelection::setShouldShowBlockCursor(bool shouldShowBlockCursor)
2143{
2144    m_shouldShowBlockCursor = shouldShowBlockCursor;
2145
2146    m_frame->document()->updateLayoutIgnorePendingStylesheets();
2147
2148    updateAppearance();
2149}
2150
2151void FrameSelection::didLayout()
2152{
2153    setCaretRectNeedsUpdate();
2154    updateAndRevealSelection();
2155    updateDataDetectorsForSelection();
2156}
2157
2158#ifndef NDEBUG
2159
2160void FrameSelection::formatForDebugger(char* buffer, unsigned length) const
2161{
2162    m_selection.formatForDebugger(buffer, length);
2163}
2164
2165void FrameSelection::showTreeForThis() const
2166{
2167    m_selection.showTreeForThis();
2168}
2169
2170#endif
2171
2172#if PLATFORM(IOS)
2173void FrameSelection::expandSelectionToElementContainingCaretSelection()
2174{
2175    RefPtr<Range> range = elementRangeContainingCaretSelection();
2176    if (!range)
2177        return;
2178    VisibleSelection selection(range.get(), DOWNSTREAM);
2179    setSelection(selection);
2180}
2181
2182PassRefPtr<Range> FrameSelection::elementRangeContainingCaretSelection() const
2183{
2184    if (m_selection.isNone())
2185        return nullptr;
2186
2187    VisibleSelection selection = m_selection;
2188    if (selection.isNone())
2189        return nullptr;
2190
2191    VisiblePosition visiblePos(selection.start(), VP_DEFAULT_AFFINITY);
2192    if (visiblePos.isNull())
2193        return nullptr;
2194
2195    Node* node = visiblePos.deepEquivalent().deprecatedNode();
2196    Element* element = deprecatedEnclosingBlockFlowElement(node);
2197    if (!element)
2198        return nullptr;
2199
2200    Position startPos = createLegacyEditingPosition(element, 0);
2201    Position endPos = createLegacyEditingPosition(element, element->childNodeCount());
2202
2203    VisiblePosition startVisiblePos(startPos, VP_DEFAULT_AFFINITY);
2204    VisiblePosition endVisiblePos(endPos, VP_DEFAULT_AFFINITY);
2205    if (startVisiblePos.isNull() || endVisiblePos.isNull())
2206        return nullptr;
2207
2208    selection.setBase(startVisiblePos);
2209    selection.setExtent(endVisiblePos);
2210
2211    return selection.toNormalizedRange();
2212}
2213
2214void FrameSelection::expandSelectionToWordContainingCaretSelection()
2215{
2216    VisibleSelection selection(wordSelectionContainingCaretSelection(m_selection));
2217    if (selection.isCaretOrRange())
2218        setSelection(selection);
2219}
2220
2221PassRefPtr<Range> FrameSelection::wordRangeContainingCaretSelection()
2222{
2223    return wordSelectionContainingCaretSelection(m_selection).toNormalizedRange();
2224}
2225
2226void FrameSelection::expandSelectionToStartOfWordContainingCaretSelection()
2227{
2228    if (m_selection.isNone() || isStartOfDocument(m_selection.start()))
2229        return;
2230
2231    VisiblePosition s1(m_selection.start());
2232    VisiblePosition e1(m_selection.end());
2233
2234    VisibleSelection expanded(wordSelectionContainingCaretSelection(m_selection));
2235    VisiblePosition s2(expanded.start());
2236
2237    // Don't allow the start to become greater after the expansion.
2238    if (s2.isNull() || s2 > s1)
2239        s2 = s1;
2240
2241    moveTo(s2, e1);
2242}
2243
2244UChar FrameSelection::characterInRelationToCaretSelection(int amount) const
2245{
2246    if (m_selection.isNone())
2247        return 0;
2248
2249    VisibleSelection selection = m_selection;
2250    ASSERT(selection.isCaretOrRange());
2251
2252    VisiblePosition visiblePosition(selection.start(), VP_DEFAULT_AFFINITY);
2253
2254    if (amount < 0) {
2255        int count = abs(amount);
2256        for (int i = 0; i < count; i++)
2257            visiblePosition = visiblePosition.previous();
2258        return visiblePosition.characterBefore();
2259    }
2260    for (int i = 0; i < amount; i++)
2261        visiblePosition = visiblePosition.next();
2262    return visiblePosition.characterAfter();
2263}
2264
2265UChar FrameSelection::characterBeforeCaretSelection() const
2266{
2267    if (m_selection.isNone())
2268        return 0;
2269
2270    VisibleSelection selection = m_selection;
2271    ASSERT(selection.isCaretOrRange());
2272
2273    VisiblePosition visiblePosition(selection.start(), VP_DEFAULT_AFFINITY);
2274    return visiblePosition.characterBefore();
2275}
2276
2277UChar FrameSelection::characterAfterCaretSelection() const
2278{
2279    if (m_selection.isNone())
2280        return 0;
2281
2282    VisibleSelection selection = m_selection;
2283    ASSERT(selection.isCaretOrRange());
2284
2285    VisiblePosition visiblePosition(selection.end(), VP_DEFAULT_AFFINITY);
2286    return visiblePosition.characterAfter();
2287}
2288
2289int FrameSelection::wordOffsetInRange(const Range *range) const
2290{
2291    if (!range)
2292        return -1;
2293
2294    VisibleSelection selection = m_selection;
2295    if (!selection.isCaret())
2296        return -1;
2297
2298    // FIXME: This will only work in cases where the selection remains in
2299    // the same node after it is expanded. Improve to handle more complicated
2300    // cases.
2301    ExceptionCode ec = 0;
2302    int result = selection.start().deprecatedEditingOffset() - range->startOffset(ec);
2303    ASSERT(!ec);
2304    if (result < 0)
2305        result = 0;
2306    return result;
2307}
2308
2309bool FrameSelection::spaceFollowsWordInRange(const Range *range) const
2310{
2311    if (!range)
2312        return false;
2313    ExceptionCode ec = 0;
2314    Node* node = range->endContainer(ec);
2315    ASSERT(!ec);
2316    int endOffset = range->endOffset(ec);
2317    ASSERT(!ec);
2318    VisiblePosition pos(createLegacyEditingPosition(node, endOffset), VP_DEFAULT_AFFINITY);
2319    return isSpaceOrNewline(pos.characterAfter());
2320}
2321
2322bool FrameSelection::selectionAtDocumentStart() const
2323{
2324    VisibleSelection selection = m_selection;
2325    if (selection.isNone())
2326        return false;
2327
2328    Position startPos(selection.start());
2329    VisiblePosition pos(createLegacyEditingPosition(startPos.deprecatedNode(), startPos.deprecatedEditingOffset()), VP_DEFAULT_AFFINITY);
2330    if (pos.isNull())
2331        return false;
2332
2333    return isStartOfDocument(pos);
2334}
2335
2336bool FrameSelection::selectionAtSentenceStart() const
2337{
2338    VisibleSelection selection = m_selection;
2339    if (selection.isNone())
2340        return false;
2341
2342    return actualSelectionAtSentenceStart(selection);
2343}
2344
2345bool FrameSelection::selectionAtWordStart() const
2346{
2347    VisibleSelection selection = m_selection;
2348    if (selection.isNone())
2349        return false;
2350
2351    Position startPos(selection.start());
2352    VisiblePosition pos(createLegacyEditingPosition(startPos.deprecatedNode(), startPos.deprecatedEditingOffset()), VP_DEFAULT_AFFINITY);
2353    if (pos.isNull())
2354        return false;
2355
2356    if (isStartOfParagraph(pos))
2357        return true;
2358
2359    bool result = true;
2360    unsigned previousCount = 0;
2361    for (pos = pos.previous(); !pos.isNull(); pos = pos.previous()) {
2362        previousCount++;
2363        if (isStartOfParagraph(pos)) {
2364            if (previousCount == 1)
2365                result = false;
2366            break;
2367        }
2368        UChar c(pos.characterAfter());
2369        if (c) {
2370            result = isSpaceOrNewline(c) || c == 0xA0 || (u_ispunct(c) && c != ',' && c != '-' && c != '\'');
2371            break;
2372        }
2373    }
2374
2375    return result;
2376}
2377
2378PassRefPtr<Range> FrameSelection::rangeByMovingCurrentSelection(int amount) const
2379{
2380    return rangeByAlteringCurrentSelection(AlterationMove, amount);
2381}
2382
2383PassRefPtr<Range> FrameSelection::rangeByExtendingCurrentSelection(int amount) const
2384{
2385    return rangeByAlteringCurrentSelection(AlterationExtend, amount);
2386}
2387
2388void FrameSelection::selectRangeOnElement(unsigned location, unsigned length, Node* node)
2389{
2390    RefPtr<Range> resultRange = m_frame->document()->createRange();
2391    ExceptionCode ec = 0;
2392    resultRange->setStart(node, location, ec);
2393    ASSERT(!ec);
2394    resultRange->setEnd(node, location + length, ec);
2395    ASSERT(!ec);
2396    VisibleSelection selection = VisibleSelection(resultRange.get(), SEL_DEFAULT_AFFINITY);
2397    setSelection(selection, true);
2398}
2399
2400VisibleSelection FrameSelection::wordSelectionContainingCaretSelection(const VisibleSelection& selection)
2401{
2402    if (selection.isNone())
2403        return VisibleSelection();
2404
2405    ASSERT(selection.isCaretOrRange());
2406    FrameSelection frameSelection;
2407    frameSelection.setSelection(selection);
2408
2409    Position startPosBeforeExpansion(selection.start());
2410    Position endPosBeforeExpansion(selection.end());
2411    VisiblePosition startVisiblePosBeforeExpansion(startPosBeforeExpansion, VP_DEFAULT_AFFINITY);
2412    VisiblePosition endVisiblePosBeforeExpansion(endPosBeforeExpansion, VP_DEFAULT_AFFINITY);
2413    if (endVisiblePosBeforeExpansion.isNull())
2414        return VisibleSelection();
2415
2416    if (isEndOfParagraph(endVisiblePosBeforeExpansion)) {
2417        UChar c(endVisiblePosBeforeExpansion.characterBefore());
2418        if (isSpaceOrNewline(c) || c == 0xA0) {
2419            // End of paragraph with space.
2420            return VisibleSelection();
2421        }
2422    }
2423
2424    // If at end of paragraph, move backwards one character.
2425    // This has the effect of selecting the word on the line (which is
2426    // what we want, rather than selecting past the end of the line).
2427    if (isEndOfParagraph(endVisiblePosBeforeExpansion) && !isStartOfParagraph(endVisiblePosBeforeExpansion))
2428        frameSelection.modify(FrameSelection::AlterationMove, DirectionBackward, CharacterGranularity);
2429
2430    VisibleSelection newSelection = frameSelection.selection();
2431    newSelection.expandUsingGranularity(WordGranularity);
2432    frameSelection.setSelection(newSelection, defaultSetSelectionOptions(), AlignCursorOnScrollIfNeeded, frameSelection.granularity());
2433
2434    Position startPos(frameSelection.selection().start());
2435    Position endPos(frameSelection.selection().end());
2436
2437    // Expansion cannot be allowed to change selection so that it is no longer
2438    // touches (or contains) the original, unexpanded selection.
2439    // Enforce this on the way into these additional calculations to give them
2440    // the best chance to yield a suitable answer.
2441    if (startPos > startPosBeforeExpansion)
2442        startPos = startPosBeforeExpansion;
2443    if (endPos < endPosBeforeExpansion)
2444        endPos = endPosBeforeExpansion;
2445
2446    VisiblePosition startVisiblePos(startPos, VP_DEFAULT_AFFINITY);
2447    VisiblePosition endVisiblePos(endPos, VP_DEFAULT_AFFINITY);
2448
2449    if (startVisiblePos.isNull() || endVisiblePos.isNull()) {
2450        // Start or end is nil
2451        return VisibleSelection();
2452    }
2453
2454    if (isEndOfLine(endVisiblePosBeforeExpansion)) {
2455        VisiblePosition previous(endVisiblePos.previous());
2456        if (previous == endVisiblePos) {
2457            // Empty document
2458            return VisibleSelection();
2459        }
2460        UChar c(previous.characterAfter());
2461        if (isSpaceOrNewline(c) || c == 0xA0) {
2462            // Space at end of line
2463            return VisibleSelection();
2464        }
2465    }
2466
2467    // Expansion has selected past end of line.
2468    // Try repositioning backwards.
2469    if (isEndOfLine(startVisiblePos) && isStartOfLine(endVisiblePos)) {
2470        VisiblePosition previous(startVisiblePos.previous());
2471        if (isEndOfLine(previous)) {
2472            // On empty line
2473            return VisibleSelection();
2474        }
2475        UChar c(previous.characterAfter());
2476        if (isSpaceOrNewline(c) || c == 0xA0) {
2477            // Space at end of line
2478            return VisibleSelection();
2479        }
2480        frameSelection.moveTo(startVisiblePos);
2481        frameSelection.modify(FrameSelection::AlterationExtend, DirectionBackward, WordGranularity);
2482        startPos = frameSelection.selection().start();
2483        endPos = frameSelection.selection().end();
2484        startVisiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY);
2485        endVisiblePos = VisiblePosition(endPos, VP_DEFAULT_AFFINITY);
2486        if (startVisiblePos.isNull() || endVisiblePos.isNull()) {
2487            // Start or end is nil
2488            return VisibleSelection();
2489        }
2490    }
2491
2492    // Now loop backwards until we find a non-space.
2493    while (endVisiblePos != startVisiblePos) {
2494        VisiblePosition previous(endVisiblePos.previous());
2495        UChar c(previous.characterAfter());
2496        if (!isSpaceOrNewline(c) && c != 0xA0)
2497            break;
2498        endVisiblePos = previous;
2499    }
2500
2501    // Expansion cannot be allowed to change selection so that it is no longer
2502    // touches (or contains) the original, unexpanded selection.
2503    // Enforce this on the way out of the function to preserve the invariant.
2504    if (startVisiblePos > startVisiblePosBeforeExpansion)
2505        startVisiblePos = startVisiblePosBeforeExpansion;
2506    if (endVisiblePos < endVisiblePosBeforeExpansion)
2507        endVisiblePos = endVisiblePosBeforeExpansion;
2508
2509    return VisibleSelection(startVisiblePos, endVisiblePos);
2510}
2511
2512bool FrameSelection::actualSelectionAtSentenceStart(const VisibleSelection& sel) const
2513{
2514    Position startPos(sel.start());
2515    VisiblePosition pos(createLegacyEditingPosition(startPos.deprecatedNode(), startPos.deprecatedEditingOffset()), VP_DEFAULT_AFFINITY);
2516    if (pos.isNull())
2517        return false;
2518
2519    if (isStartOfParagraph(pos))
2520        return true;
2521
2522    bool result = true;
2523    bool sawSpace = false;
2524    unsigned previousCount = 0;
2525    for (pos = pos.previous(); !pos.isNull(); pos = pos.previous()) {
2526        previousCount++;
2527        if (isStartOfParagraph(pos)) {
2528            if (previousCount == 1 || (previousCount == 2 && sawSpace))
2529                result = false;
2530            break;
2531        }
2532        UChar c(pos.characterAfter());
2533        if (c) {
2534            if (isSpaceOrNewline(c) || c == 0xA0) {
2535                sawSpace = true;
2536            }
2537            else {
2538                result = (c == '.' || c == '!' || c == '?');
2539                break;
2540            }
2541        }
2542    }
2543
2544    return result;
2545}
2546
2547PassRefPtr<Range> FrameSelection::rangeByAlteringCurrentSelection(EAlteration alteration, int amount) const
2548{
2549    if (m_selection.isNone())
2550        return nullptr;
2551
2552    if (!amount)
2553        return toNormalizedRange();
2554
2555    FrameSelection frameSelection;
2556    frameSelection.setSelection(m_selection);
2557    SelectionDirection direction = amount > 0 ? DirectionForward : DirectionBackward;
2558    for (int i = 0; i < abs(amount); i++)
2559        frameSelection.modify(alteration, direction, CharacterGranularity);
2560    return frameSelection.toNormalizedRange();
2561}
2562
2563void FrameSelection::clearCurrentSelection()
2564{
2565    setSelection(VisibleSelection());
2566}
2567
2568void FrameSelection::setCaretBlinks(bool caretBlinks)
2569{
2570    if (m_caretBlinks == caretBlinks)
2571        return;
2572#if ENABLE(TEXT_CARET)
2573    m_frame->document()->updateLayoutIgnorePendingStylesheets();
2574    if (m_caretPaint) {
2575        m_caretPaint = false;
2576        invalidateCaretRect();
2577    }
2578#endif
2579    if (caretBlinks)
2580        setFocusedElementIfNeeded();
2581    m_caretBlinks = caretBlinks;
2582    updateAppearance();
2583}
2584
2585void FrameSelection::setCaretColor(const Color& caretColor)
2586{
2587    if (m_caretColor != caretColor) {
2588        m_caretColor = caretColor;
2589        if (caretIsVisible() && m_caretBlinks && isCaret())
2590            invalidateCaretRect();
2591    }
2592}
2593#endif // PLATFORM(IOS)
2594
2595}
2596
2597#ifndef NDEBUG
2598
2599void showTree(const WebCore::FrameSelection& sel)
2600{
2601    sel.showTreeForThis();
2602}
2603
2604void showTree(const WebCore::FrameSelection* sel)
2605{
2606    if (sel)
2607        sel->showTreeForThis();
2608}
2609
2610#endif
2611