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