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