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