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