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