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