2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "SelectionController.h"
29 #include "CharacterData.h"
30 #include "DeleteSelectionCommand.h"
33 #include "EditorClient.h"
35 #include "EventHandler.h"
36 #include "ExceptionCode.h"
37 #include "FloatQuad.h"
38 #include "FocusController.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"
51 #include "RenderLayer.h"
52 #include "RenderTextControl.h"
53 #include "RenderTheme.h"
54 #include "RenderView.h"
55 #include "RenderWidget.h"
56 #include "SecureTextInput.h"
58 #include "TextIterator.h"
59 #include "TypingCommand.h"
60 #include "htmlediting.h"
61 #include "visible_units.h"
63 #include <wtf/text/CString.h>
69 using namespace HTMLNames;
71 const int NoXPosForVerticalArrowNavigation = INT_MIN;
73 SelectionController::SelectionController(Frame* frame, bool isDragCaretController)
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)
86 setIsDirectional(false);
89 void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered, CursorAlignOnScroll align)
91 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
93 options |= UserTriggered;
94 setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), options, align);
97 void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered)
99 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
101 options |= UserTriggered;
102 setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), options);
105 void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered)
107 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
109 options |= UserTriggered;
110 setSelection(VisibleSelection(pos, affinity), options);
113 void SelectionController::moveTo(const Range *r, EAffinity affinity, bool userTriggered)
115 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
117 options |= UserTriggered;
118 VisibleSelection selection = r ? VisibleSelection(r->startPosition(), r->endPosition(), affinity) : VisibleSelection(Position(), Position(), affinity);
119 setSelection(selection, options);
122 void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered)
124 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
126 options |= UserTriggered;
127 setSelection(VisibleSelection(base, extent, affinity), options);
130 void SelectionController::setSelection(const VisibleSelection& s, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity, DirectionalityPolicy directionalityPolicy)
132 m_granularity = granularity;
134 bool closeTyping = options & CloseTyping;
135 bool shouldClearTypingStyle = options & ClearTypingStyle;
136 bool userTriggered = options & UserTriggered;
138 setIsDirectional(directionalityPolicy == MakeDirectionalSelection);
140 if (m_isDragCaretController) {
141 invalidateCaretRect();
143 m_caretRectNeedsUpdate = true;
144 invalidateCaretRect();
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);
164 TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());
166 if (shouldClearTypingStyle)
169 if (m_selection == s) {
170 // Even if selection was not changed, selection offsets may have been changed.
171 notifyRendererOfSelectionChange(userTriggered);
175 VisibleSelection oldSelection = m_selection;
179 m_caretRectNeedsUpdate = true;
182 setFocusedNodeIfNeeded();
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);
193 ScrollAlignment alignment;
195 if (m_frame->editor()->behavior().shouldCenterAlignWhenSelectionIsRevealed())
196 alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
198 alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
200 revealSelection(alignment, true);
203 notifyAccessibilityForSelectionChange();
204 m_frame->document()->enqueueDocumentEvent(Event::create(eventNames().selectionchangeEvent, false, false));
207 static bool removingNodeRemovesPosition(Node* node, const Position& position)
209 if (!position.anchorNode())
212 if (position.anchorNode() == node)
215 if (!node->isElementNode())
218 Element* element = static_cast<Element*>(node);
219 return element->contains(position.anchorNode()) || element->contains(position.anchorNode()->shadowAncestorNode());
222 void SelectionController::nodeWillBeRemoved(Node *node)
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)
232 respondToNodeModification(node, removingNodeRemovesPosition(node, m_selection.base()), removingNodeRemovesPosition(node, m_selection.extent()),
233 removingNodeRemovesPosition(node, m_selection.start()), removingNodeRemovesPosition(node, m_selection.end()));
236 void SelectionController::respondToNodeModification(Node* node, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved)
238 bool clearRenderTreeSelection = false;
239 bool clearDOMTreeSelection = false;
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());
253 m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
254 } else if (m_selection.firstRange()) {
255 ExceptionCode ec = 0;
256 Range::CompareResults compareResult = m_selection.firstRange()->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;
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();
273 if (clearDOMTreeSelection)
274 setSelection(VisibleSelection(), 0);
277 enum EndPointType { EndPointIsStart, EndPointIsEnd };
279 static bool shouldRemovePositionAfterAdoptingTextReplacement(Position& position, EndPointType type, CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
281 if (!position.anchorNode() || position.anchorNode() != node || position.anchorType() != Position::PositionIsOffsetInAnchor)
284 ASSERT(position.offsetInContainerNode() >= 0);
285 unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
286 if (positionOffset > offset && positionOffset < offset + oldLength)
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);
298 void SelectionController::textWillBeReplaced(CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
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)
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);
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);
319 if (newSelection.isBaseFirst())
320 newSelection.setWithoutValidation(start, end);
322 newSelection.setWithoutValidation(end, start);
324 m_frame->document()->updateLayout();
325 setSelection(newSelection, 0);
329 respondToNodeModification(node, shouldRemoveBase, shouldRemoveExtent, shouldRemoveStart, shouldRemoveEnd);
332 void SelectionController::setIsDirectional(bool isDirectional)
334 m_isDirectional = !m_frame || m_frame->editor()->behavior().shouldConsiderSelectionAsDirectional() || isDirectional;
337 TextDirection SelectionController::directionOfEnclosingBlock()
339 return WebCore::directionOfEnclosingBlock(m_selection.extent());
342 void SelectionController::willBeModified(EAlteration alter, SelectionDirection direction)
344 if (alter != AlterationExtend)
347 Position start = m_selection.start();
348 Position end = m_selection.end();
350 bool baseIsStart = true;
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())
363 if (directionOfEnclosingBlock() == LTR)
368 case DirectionForward:
372 if (directionOfEnclosingBlock() == LTR)
377 case DirectionBackward:
383 m_selection.setBase(start);
384 m_selection.setExtent(end);
386 m_selection.setBase(end);
387 m_selection.setExtent(start);
391 VisiblePosition SelectionController::positionForPlatform(bool isGetStart) const
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();
404 VisiblePosition SelectionController::startForPlatform() const
406 return positionForPlatform(true);
409 VisiblePosition SelectionController::endForPlatform() const
411 return positionForPlatform(false);
414 VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granularity)
416 VisiblePosition pos(m_selection.extent(), m_selection.affinity());
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);
428 pos = pos.previous(CannotCrossEditingBoundary);
430 case WordGranularity:
431 if (directionOfEnclosingBlock() == LTR)
432 pos = nextWordPosition(pos);
434 pos = previousWordPosition(pos);
437 if (directionOfEnclosingBlock() == LTR)
438 pos = modifyExtendingForward(granularity);
440 pos = modifyExtendingBackward(granularity);
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);
451 case WebKitVisualWordGranularity:
457 VisiblePosition SelectionController::modifyExtendingForward(TextGranularity granularity)
459 VisiblePosition pos(m_selection.extent(), m_selection.affinity());
460 switch (granularity) {
461 case CharacterGranularity:
462 pos = pos.next(CannotCrossEditingBoundary);
464 case WordGranularity:
465 pos = nextWordPosition(pos);
467 case SentenceGranularity:
468 pos = nextSentencePosition(pos);
470 case LineGranularity:
471 pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
473 case ParagraphGranularity:
474 pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
476 case SentenceBoundary:
477 pos = endOfSentence(endForPlatform());
480 pos = logicalEndOfLine(endForPlatform());
482 case ParagraphBoundary:
483 pos = endOfParagraph(endForPlatform());
485 case DocumentBoundary:
486 pos = endForPlatform();
487 if (isEditablePosition(pos.deepEquivalent()))
488 pos = endOfEditableContent(pos);
490 pos = endOfDocument(pos);
492 case WebKitVisualWordGranularity:
499 VisiblePosition SelectionController::modifyMovingRight(TextGranularity granularity)
502 switch (granularity) {
503 case CharacterGranularity:
505 if (directionOfEnclosingBlock() == LTR)
506 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
508 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
510 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
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);
523 pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
525 case WebKitVisualWordGranularity:
526 pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
532 VisiblePosition SelectionController::modifyMovingForward(TextGranularity granularity)
535 // FIXME: Stay in editable content for the less common granularities.
536 switch (granularity) {
537 case CharacterGranularity:
539 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
541 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
543 case WordGranularity:
544 pos = nextWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
546 case SentenceGranularity:
547 pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
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));
557 case ParagraphGranularity:
558 pos = nextParagraphPosition(endForPlatform(), xPosForVerticalArrowNavigation(START));
560 case SentenceBoundary:
561 pos = endOfSentence(endForPlatform());
564 pos = logicalEndOfLine(endForPlatform());
566 case ParagraphBoundary:
567 pos = endOfParagraph(endForPlatform());
569 case DocumentBoundary:
570 pos = endForPlatform();
571 if (isEditablePosition(pos.deepEquivalent()))
572 pos = endOfEditableContent(pos);
574 pos = endOfDocument(pos);
576 case WebKitVisualWordGranularity:
582 VisiblePosition SelectionController::modifyExtendingLeft(TextGranularity granularity)
584 VisiblePosition pos(m_selection.extent(), m_selection.affinity());
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);
596 pos = pos.next(CannotCrossEditingBoundary);
598 case WordGranularity:
599 if (directionOfEnclosingBlock() == LTR)
600 pos = previousWordPosition(pos);
602 pos = nextWordPosition(pos);
605 if (directionOfEnclosingBlock() == LTR)
606 pos = modifyExtendingBackward(granularity);
608 pos = modifyExtendingForward(granularity);
610 case SentenceGranularity:
611 case LineGranularity:
612 case ParagraphGranularity:
613 case SentenceBoundary:
614 case ParagraphBoundary:
615 case DocumentBoundary:
616 pos = modifyExtendingBackward(granularity);
618 case WebKitVisualWordGranularity:
624 VisiblePosition SelectionController::modifyExtendingBackward(TextGranularity granularity)
626 VisiblePosition pos(m_selection.extent(), m_selection.affinity());
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
632 switch (granularity) {
633 case CharacterGranularity:
634 pos = pos.previous(CannotCrossEditingBoundary);
636 case WordGranularity:
637 pos = previousWordPosition(pos);
639 case SentenceGranularity:
640 pos = previousSentencePosition(pos);
642 case LineGranularity:
643 pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
645 case ParagraphGranularity:
646 pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
648 case SentenceBoundary:
649 pos = startOfSentence(startForPlatform());
652 pos = logicalStartOfLine(startForPlatform());
654 case ParagraphBoundary:
655 pos = startOfParagraph(startForPlatform());
657 case DocumentBoundary:
658 pos = startForPlatform();
659 if (isEditablePosition(pos.deepEquivalent()))
660 pos = startOfEditableContent(pos);
662 pos = startOfDocument(pos);
664 case WebKitVisualWordGranularity:
670 VisiblePosition SelectionController::modifyMovingLeft(TextGranularity granularity)
673 switch (granularity) {
674 case CharacterGranularity:
676 if (directionOfEnclosingBlock() == LTR)
677 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
679 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
681 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
683 case WordGranularity:
684 pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
686 case SentenceGranularity:
687 case LineGranularity:
688 case ParagraphGranularity:
689 case SentenceBoundary:
690 case ParagraphBoundary:
691 case DocumentBoundary:
692 // FIXME: Implement all of the above.
693 pos = modifyMovingBackward(granularity);
696 pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
698 case WebKitVisualWordGranularity:
699 pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
705 VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granularity)
708 switch (granularity) {
709 case CharacterGranularity:
711 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
713 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
715 case WordGranularity:
716 pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
718 case SentenceGranularity:
719 pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
721 case LineGranularity:
722 pos = previousLinePosition(startForPlatform(), xPosForVerticalArrowNavigation(START));
724 case ParagraphGranularity:
725 pos = previousParagraphPosition(startForPlatform(), xPosForVerticalArrowNavigation(START));
727 case SentenceBoundary:
728 pos = startOfSentence(startForPlatform());
731 pos = logicalStartOfLine(startForPlatform());
733 case ParagraphBoundary:
734 pos = startOfParagraph(startForPlatform());
736 case DocumentBoundary:
737 pos = startForPlatform();
738 if (isEditablePosition(pos.deepEquivalent()))
739 pos = startOfEditableContent(pos);
741 pos = startOfDocument(pos);
743 case WebKitVisualWordGranularity:
749 static bool isBoundary(TextGranularity granularity)
751 return granularity == LineBoundary || granularity == ParagraphBoundary || granularity == DocumentBoundary;
754 bool SelectionController::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, bool userTriggered)
757 SelectionController trialSelectionController;
758 trialSelectionController.setSelection(m_selection);
759 trialSelectionController.setIsDirectional(m_isDirectional);
760 trialSelectionController.modify(alter, direction, granularity, false);
762 bool change = shouldChangeSelection(trialSelectionController.selection());
767 willBeModified(alter, direction);
769 bool wasRange = m_selection.isRange();
770 Position originalStartPosition = m_selection.start();
771 VisiblePosition position;
774 if (alter == AlterationMove)
775 position = modifyMovingRight(granularity);
777 position = modifyExtendingRight(granularity);
779 case DirectionForward:
780 if (alter == AlterationExtend)
781 position = modifyExtendingForward(granularity);
783 position = modifyMovingForward(granularity);
786 if (alter == AlterationMove)
787 position = modifyMovingLeft(granularity);
789 position = modifyExtendingLeft(granularity);
791 case DirectionBackward:
792 if (alter == AlterationExtend)
793 position = modifyExtendingBackward(granularity);
795 position = modifyMovingBackward(granularity);
799 if (position.isNull())
802 if (isSpatialNavigationEnabled(m_frame))
803 if (!wasRange && alter == AlterationMove && position == originalStartPosition)
806 // Some of the above operations set an xPosForVerticalArrowNavigation.
807 // Setting a selection will clear it, so save it to possibly restore later.
808 // Note: the START position type is arbitrary because it is unused, it would be
809 // the requested position type if there were no xPosForVerticalArrowNavigation set.
810 int x = xPosForVerticalArrowNavigation(START);
814 moveTo(position, userTriggered);
816 case AlterationExtend:
817 // Standard Mac behavior when extending to a boundary is grow the selection rather than leaving the
818 // base in place and moving the extent. Matches NSTextView.
819 if (!m_frame || !m_frame->editor()->behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity))
820 setExtent(position, userTriggered);
822 TextDirection textDirection = directionOfEnclosingBlock();
823 if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft))
824 setEnd(position, userTriggered);
826 setStart(position, userTriggered);
831 if (granularity == LineGranularity || granularity == ParagraphGranularity)
832 m_xPosForVerticalArrowNavigation = x;
835 m_granularity = CharacterGranularity;
838 setCaretRectNeedsUpdate();
840 setIsDirectional(alter == AlterationExtend);
845 // FIXME: Maybe baseline would be better?
846 static bool absoluteCaretY(const VisiblePosition &c, int &y)
848 IntRect rect = c.absoluteCaretBounds();
851 y = rect.y() + rect.height() / 2;
855 bool SelectionController::modify(EAlteration alter, int verticalDistance, bool userTriggered, CursorAlignOnScroll align)
857 if (!verticalDistance)
861 SelectionController trialSelectionController;
862 trialSelectionController.setSelection(m_selection);
863 trialSelectionController.setIsDirectional(m_isDirectional);
864 trialSelectionController.modify(alter, verticalDistance, false);
866 bool change = shouldChangeSelection(trialSelectionController.selection());
871 bool up = verticalDistance < 0;
873 verticalDistance = -verticalDistance;
875 willBeModified(alter, up ? DirectionBackward : DirectionForward);
881 pos = VisiblePosition(up ? m_selection.start() : m_selection.end(), m_selection.affinity());
882 xPos = xPosForVerticalArrowNavigation(up ? START : END);
883 m_selection.setAffinity(up ? UPSTREAM : DOWNSTREAM);
885 case AlterationExtend:
886 pos = VisiblePosition(m_selection.extent(), m_selection.affinity());
887 xPos = xPosForVerticalArrowNavigation(EXTENT);
888 m_selection.setAffinity(DOWNSTREAM);
893 if (!absoluteCaretY(pos, startY))
899 VisiblePosition result;
900 VisiblePosition next;
901 for (VisiblePosition p = pos; ; p = next) {
902 next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
903 if (next.isNull() || next == p)
906 if (!absoluteCaretY(next, nextY))
910 if (nextY - startY > verticalDistance)
912 if (nextY >= lastY) {
923 moveTo(result, userTriggered, align);
925 case AlterationExtend:
926 setExtent(result, userTriggered);
931 m_granularity = CharacterGranularity;
933 setIsDirectional(alter == AlterationExtend);
938 int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
948 pos = m_selection.start();
951 pos = m_selection.end();
954 pos = m_selection.base();
957 pos = m_selection.extent();
961 Frame* frame = pos.anchorNode()->document()->frame();
965 if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation) {
966 VisiblePosition visiblePosition(pos, m_selection.affinity());
967 // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
968 // after the selection is created and before this function is called.
969 x = visiblePosition.isNotNull() ? visiblePosition.xOffsetForVerticalNavigation() : 0;
970 m_xPosForVerticalArrowNavigation = x;
972 x = m_xPosForVerticalArrowNavigation;
977 void SelectionController::clear()
979 m_granularity = CharacterGranularity;
980 setSelection(VisibleSelection());
983 void SelectionController::setStart(const VisiblePosition &pos, bool userTriggered)
985 if (m_selection.isBaseFirst())
986 setBase(pos, userTriggered);
988 setExtent(pos, userTriggered);
991 void SelectionController::setEnd(const VisiblePosition &pos, bool userTriggered)
993 if (m_selection.isBaseFirst())
994 setExtent(pos, userTriggered);
996 setBase(pos, userTriggered);
999 void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
1001 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
1003 options |= UserTriggered;
1004 setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity()), options);
1007 void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered)
1009 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
1011 options |= UserTriggered;
1012 setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity()), options);
1015 void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered)
1017 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
1019 options |= UserTriggered;
1020 setSelection(VisibleSelection(pos, m_selection.extent(), affinity), options);
1023 void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered)
1025 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
1027 options |= UserTriggered;
1028 setSelection(VisibleSelection(m_selection.base(), pos, affinity), options);
1031 void SelectionController::setCaretRectNeedsUpdate(bool flag)
1033 m_caretRectNeedsUpdate = flag;
1036 void SelectionController::updateCaretRect()
1038 if (isNone() || !m_selection.start().anchorNode()->inDocument() || !m_selection.end().anchorNode()->inDocument()) {
1039 m_caretRect = IntRect();
1043 m_selection.start().anchorNode()->document()->updateStyleIfNeeded();
1045 m_caretRect = IntRect();
1048 VisiblePosition pos(m_selection.start(), m_selection.affinity());
1049 if (pos.isNotNull()) {
1050 ASSERT(pos.deepEquivalent().deprecatedNode()->renderer());
1052 // First compute a rect local to the renderer at the selection start
1053 RenderObject* renderer;
1054 IntRect localRect = pos.localCaretRect(renderer);
1056 // Get the renderer that will be responsible for painting the caret (which
1057 // is either the renderer we just found, or one of its containers)
1058 RenderObject* caretPainter = caretRenderer();
1060 // Compute an offset between the renderer and the caretPainter
1061 bool unrooted = false;
1062 while (renderer != caretPainter) {
1063 RenderObject* containerObject = renderer->container();
1064 if (!containerObject) {
1068 localRect.move(renderer->offsetFromContainer(containerObject, localRect.location()));
1069 renderer = containerObject;
1073 m_caretRect = localRect;
1075 m_absCaretBoundsDirty = true;
1079 m_caretRectNeedsUpdate = false;
1082 RenderObject* SelectionController::caretRenderer() const
1084 Node* node = m_selection.start().deprecatedNode();
1088 RenderObject* renderer = node->renderer();
1092 // if caretNode is a block and caret is inside it then caret should be painted by that block
1093 bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(node);
1094 return paintedByBlock ? renderer : renderer->containingBlock();
1097 IntRect SelectionController::localCaretRect()
1099 if (m_caretRectNeedsUpdate)
1105 IntRect SelectionController::absoluteBoundsForLocalRect(const IntRect& rect) const
1107 RenderObject* caretPainter = caretRenderer();
1111 IntRect localRect(rect);
1112 if (caretPainter->isBox())
1113 toRenderBox(caretPainter)->flipForWritingMode(localRect);
1114 return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
1117 IntRect SelectionController::absoluteCaretBounds()
1119 recomputeCaretRect();
1120 return m_absCaretBounds;
1123 static IntRect repaintRectForCaret(IntRect caret)
1125 if (caret.isEmpty())
1127 // Ensure that the dirty rect intersects the block that paints the caret even in the case where
1128 // the caret itself is just outside the block. See <https://bugs.webkit.org/show_bug.cgi?id=19086>.
1133 IntRect SelectionController::caretRepaintRect() const
1135 return absoluteBoundsForLocalRect(repaintRectForCaret(localCaretRectForPainting()));
1138 bool SelectionController::recomputeCaretRect()
1140 if (!m_caretRectNeedsUpdate)
1146 FrameView* v = m_frame->document()->view();
1150 IntRect oldRect = m_caretRect;
1151 IntRect newRect = localCaretRect();
1152 if (oldRect == newRect && !m_absCaretBoundsDirty)
1155 IntRect oldAbsCaretBounds = m_absCaretBounds;
1156 // FIXME: Rename m_caretRect to m_localCaretRect.
1157 m_absCaretBounds = absoluteBoundsForLocalRect(m_caretRect);
1158 m_absCaretBoundsDirty = false;
1160 if (oldAbsCaretBounds == m_absCaretBounds)
1163 IntRect oldAbsoluteCaretRepaintBounds = m_absoluteCaretRepaintBounds;
1164 // We believe that we need to inflate the local rect before transforming it to obtain the repaint bounds.
1165 m_absoluteCaretRepaintBounds = caretRepaintRect();
1167 #if ENABLE(TEXT_CARET)
1168 if (RenderView* view = toRenderView(m_frame->document()->renderer())) {
1169 // FIXME: make caret repainting container-aware.
1170 view->repaintRectangleInViewAndCompositedLayers(oldAbsoluteCaretRepaintBounds, false);
1171 if (shouldRepaintCaret(view))
1172 view->repaintRectangleInViewAndCompositedLayers(m_absoluteCaretRepaintBounds, false);
1178 bool SelectionController::shouldRepaintCaret(const RenderView* view) const
1181 Frame* frame = view->frameView() ? view->frameView()->frame() : 0; // The frame where the selection started.
1182 bool caretBrowsing = frame && frame->settings() && frame->settings()->caretBrowsingEnabled();
1183 return (caretBrowsing || isContentEditable());
1186 void SelectionController::invalidateCaretRect()
1191 Document* d = m_selection.start().anchorNode()->document();
1193 // recomputeCaretRect will always return false for the drag caret,
1194 // because its m_frame is always 0.
1195 bool caretRectChanged = recomputeCaretRect();
1197 // EDIT FIXME: This is an unfortunate hack.
1198 // Basically, we can't trust this layout position since we
1199 // can't guarantee that the check to see if we are in unrendered
1200 // content will work at this point. We may have to wait for
1201 // a layout and re-render of the document to happen. So, resetting this
1202 // flag will cause another caret layout to happen the first time
1203 // that we try to paint the caret after this call. That one will work since
1204 // it happens after the document has accounted for any editing
1205 // changes which may have been done.
1206 // And, we need to leave this layout here so the caret moves right
1207 // away after clicking.
1208 m_caretRectNeedsUpdate = true;
1210 if (!caretRectChanged) {
1211 RenderView* view = toRenderView(d->renderer());
1212 if (view && shouldRepaintCaret(view))
1213 view->repaintRectangleInViewAndCompositedLayers(caretRepaintRect(), false);
1217 void SelectionController::paintCaret(GraphicsContext* context, int tx, int ty, const IntRect& clipRect)
1219 #if ENABLE(TEXT_CARET)
1220 if (!m_caretVisible)
1224 if (!m_selection.isCaret())
1227 IntRect drawingRect = localCaretRectForPainting();
1228 if (caretRenderer() && caretRenderer()->isBox())
1229 toRenderBox(caretRenderer())->flipForWritingMode(drawingRect);
1230 drawingRect.move(tx, ty);
1231 IntRect caret = intersection(drawingRect, clipRect);
1232 if (caret.isEmpty())
1235 Color caretColor = Color::black;
1236 ColorSpace colorSpace = ColorSpaceDeviceRGB;
1237 Element* element = rootEditableElement();
1238 if (element && element->renderer()) {
1239 caretColor = element->renderer()->style()->visitedDependentColor(CSSPropertyColor);
1240 colorSpace = element->renderer()->style()->colorSpace();
1243 context->fillRect(caret, caretColor, colorSpace);
1245 UNUSED_PARAM(context);
1248 UNUSED_PARAM(clipRect);
1252 void SelectionController::debugRenderer(RenderObject *r, bool selected) const
1254 if (r->node()->isElementNode()) {
1255 Element* element = static_cast<Element *>(r->node());
1256 fprintf(stderr, "%s%s\n", selected ? "==> " : " ", element->localName().string().utf8().data());
1257 } else if (r->isText()) {
1258 RenderText* textRenderer = toRenderText(r);
1259 if (!textRenderer->textLength() || !textRenderer->firstTextBox()) {
1260 fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : " ");
1264 static const int max = 36;
1265 String text = textRenderer->text();
1266 int textLength = text.length();
1269 if (r->node() == m_selection.start().containerNode())
1270 offset = m_selection.start().computeOffsetInContainerNode();
1271 else if (r->node() == m_selection.end().containerNode())
1272 offset = m_selection.end().computeOffsetInContainerNode();
1275 InlineTextBox* box = textRenderer->findNextInlineTextBox(offset, pos);
1276 text = text.substring(box->start(), box->len());
1282 // text is shorter than max
1283 if (textLength < max) {
1286 } else if (pos - mid < 0) {
1287 // too few characters to left
1288 show = text.left(max - 3) + "...";
1290 } else if (pos - mid >= 0 && pos + mid <= textLength) {
1291 // enough characters on each side
1292 show = "..." + text.substring(pos - mid + 3, max - 6) + "...";
1295 // too few characters on right
1296 show = "..." + text.right(max - 3);
1297 caret = pos - (textLength - show.length());
1300 show.replace('\n', ' ');
1301 show.replace('\r', ' ');
1302 fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.utf8().data(), pos);
1303 fprintf(stderr, " ");
1304 for (int i = 0; i < caret; i++)
1305 fprintf(stderr, " ");
1306 fprintf(stderr, "^\n");
1308 if ((int)text.length() > max)
1309 text = text.left(max - 3) + "...";
1311 text = text.left(max);
1312 fprintf(stderr, " #text : \"%s\"\n", text.utf8().data());
1317 bool SelectionController::contains(const IntPoint& point)
1319 Document* document = m_frame->document();
1321 // Treat a collapsed selection like no selection.
1324 if (!document->renderer())
1327 HitTestRequest request(HitTestRequest::ReadOnly |
1328 HitTestRequest::Active);
1329 HitTestResult result(point);
1330 document->renderView()->layer()->hitTest(request, result);
1331 Node* innerNode = result.innerNode();
1332 if (!innerNode || !innerNode->renderer())
1335 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint()));
1336 if (visiblePos.isNull())
1339 if (m_selection.visibleStart().isNull() || m_selection.visibleEnd().isNull())
1342 Position start(m_selection.visibleStart().deepEquivalent());
1343 Position end(m_selection.visibleEnd().deepEquivalent());
1344 Position p(visiblePos.deepEquivalent());
1346 return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;
1349 // Workaround for the fact that it's hard to delete a frame.
1350 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
1351 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
1352 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
1353 // mouse or the keyboard after setting the selection.
1354 void SelectionController::selectFrameElementInParentIfFullySelected()
1356 // Find the parent frame; if there is none, then we have nothing to do.
1357 Frame* parent = m_frame->tree()->parent();
1360 Page* page = m_frame->page();
1364 // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
1367 if (!isStartOfDocument(selection().visibleStart()))
1369 if (!isEndOfDocument(selection().visibleEnd()))
1372 // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
1373 Element* ownerElement = m_frame->ownerElement();
1376 ContainerNode* ownerElementParent = ownerElement->parentNode();
1377 if (!ownerElementParent)
1380 // 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.
1381 if (!ownerElementParent->rendererIsEditable())
1384 // Create compute positions before and after the element.
1385 unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
1386 VisiblePosition beforeOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex, Position::PositionIsOffsetInAnchor)));
1387 VisiblePosition afterOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex + 1, Position::PositionIsOffsetInAnchor), VP_UPSTREAM_IF_POSSIBLE));
1389 // Focus on the parent frame, and then select from before this element to after.
1390 VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
1391 if (parent->selection()->shouldChangeSelection(newSelection)) {
1392 page->focusController()->setFocusedFrame(parent);
1393 parent->selection()->setSelection(newSelection);
1397 void SelectionController::selectAll()
1399 Document* document = m_frame->document();
1401 if (document->focusedNode() && document->focusedNode()->canSelectAll()) {
1402 document->focusedNode()->selectAll();
1407 if (isContentEditable())
1408 root = highestEditableRoot(m_selection.start());
1410 root = shadowTreeRootNode();
1412 root = document->documentElement();
1416 VisibleSelection newSelection(VisibleSelection::selectionFromContentsOfNode(root));
1417 if (shouldChangeSelection(newSelection))
1418 setSelection(newSelection);
1419 selectFrameElementInParentIfFullySelected();
1420 notifyRendererOfSelectionChange(true);
1423 bool SelectionController::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
1428 ExceptionCode ec = 0;
1429 Node* startContainer = range->startContainer(ec);
1433 Node* endContainer = range->endContainer(ec);
1437 ASSERT(startContainer);
1438 ASSERT(endContainer);
1439 ASSERT(startContainer->document() == endContainer->document());
1441 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1443 // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
1444 // they start at the beginning of the next line instead
1445 bool collapsed = range->collapsed(ec);
1449 int startOffset = range->startOffset(ec);
1453 int endOffset = range->endOffset(ec);
1457 // FIXME: Can we provide extentAffinity?
1458 VisiblePosition visibleStart(Position(startContainer, startOffset, Position::PositionIsOffsetInAnchor), collapsed ? affinity : DOWNSTREAM);
1459 VisiblePosition visibleEnd(Position(endContainer, endOffset, Position::PositionIsOffsetInAnchor), SEL_DEFAULT_AFFINITY);
1460 SetSelectionOptions options = ClearTypingStyle;
1462 options |= CloseTyping;
1463 setSelection(VisibleSelection(visibleStart, visibleEnd), options);
1467 bool SelectionController::isInPasswordField() const
1469 ASSERT(start().isNull() || start().anchorType() == Position::PositionIsOffsetInAnchor
1470 || start().containerNode() || !start().anchorNode()->shadowAncestorNode());
1471 Node* startNode = start().containerNode();
1475 startNode = startNode->shadowAncestorNode();
1479 if (!startNode->hasTagName(inputTag))
1482 return static_cast<HTMLInputElement*>(startNode)->isPasswordField();
1485 bool SelectionController::caretRendersInsideNode(Node* node) const
1489 return !isTableElement(node) && !editingIgnoresContent(node);
1492 void SelectionController::focusedOrActiveStateChanged()
1494 bool activeAndFocused = isFocusedAndActive();
1496 // Because RenderObject::selectionBackgroundColor() and
1497 // RenderObject::selectionForegroundColor() check if the frame is active,
1498 // we have to update places those colors were painted.
1499 if (RenderView* view = toRenderView(m_frame->document()->renderer()))
1500 view->repaintRectangleInViewAndCompositedLayers(enclosingIntRect(bounds()));
1502 // Caret appears in the active frame.
1503 if (activeAndFocused)
1504 setSelectionFromNone();
1505 setCaretVisible(activeAndFocused);
1507 // Update for caps lock state
1508 m_frame->eventHandler()->capsLockStateMayHaveChanged();
1510 // Because CSSStyleSelector::checkOneSelector() and
1511 // RenderTheme::isFocused() check if the frame is active, we have to
1512 // update style and theme state that depended on those.
1513 if (Node* node = m_frame->document()->focusedNode()) {
1514 node->setNeedsStyleRecalc();
1515 if (RenderObject* renderer = node->renderer())
1516 if (renderer && renderer->style()->hasAppearance())
1517 renderer->theme()->stateChanged(renderer, FocusState);
1520 // Secure keyboard entry is set by the active frame.
1521 if (m_frame->document()->useSecureKeyboardEntryWhenActive())
1522 setUseSecureKeyboardEntry(activeAndFocused);
1525 void SelectionController::pageActivationChanged()
1527 focusedOrActiveStateChanged();
1530 void SelectionController::updateSecureKeyboardEntryIfActive()
1532 if (m_frame->document() && isFocusedAndActive())
1533 setUseSecureKeyboardEntry(m_frame->document()->useSecureKeyboardEntryWhenActive());
1536 void SelectionController::setUseSecureKeyboardEntry(bool enable)
1539 enableSecureTextInput();
1541 disableSecureTextInput();
1544 void SelectionController::setFocused(bool flag)
1546 if (m_focused == flag)
1550 focusedOrActiveStateChanged();
1553 bool SelectionController::isFocusedAndActive() const
1555 return m_focused && m_frame->page() && m_frame->page()->focusController()->isActive();
1558 void SelectionController::updateAppearance()
1560 ASSERT(!m_isDragCaretController);
1562 #if ENABLE(TEXT_CARET)
1563 bool caretRectChanged = recomputeCaretRect();
1565 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
1566 bool shouldBlink = m_caretVisible
1567 && isCaret() && (isContentEditable() || caretBrowsing);
1569 // If the caret moved, stop the blink timer so we can restart with a
1570 // black caret in the new location.
1571 if (caretRectChanged || !shouldBlink)
1572 m_caretBlinkTimer.stop();
1574 // Start blinking with a black caret. Be sure not to restart if we're
1575 // already blinking in the right location.
1576 if (shouldBlink && !m_caretBlinkTimer.isActive()) {
1577 if (double blinkInterval = m_frame->page()->theme()->caretBlinkInterval())
1578 m_caretBlinkTimer.startRepeating(blinkInterval);
1580 if (!m_caretPaint) {
1581 m_caretPaint = true;
1582 invalidateCaretRect();
1587 // We need to update style in case the node containing the selection is made display:none.
1588 m_frame->document()->updateStyleIfNeeded();
1590 RenderView* view = m_frame->contentRenderer();
1594 VisibleSelection selection = this->selection();
1596 if (!selection.isRange()) {
1597 view->clearSelection();
1601 // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
1602 // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. If we pass [foo, 3]
1603 // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
1604 // and will fill the gap before 'bar'.
1605 Position startPos = selection.start();
1606 Position candidate = startPos.downstream();
1607 if (candidate.isCandidate())
1608 startPos = candidate;
1609 Position endPos = selection.end();
1610 candidate = endPos.upstream();
1611 if (candidate.isCandidate())
1614 // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
1615 // because we don't yet notify the SelectionController of text removal.
1616 if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
1617 RenderObject* startRenderer = startPos.deprecatedNode()->renderer();
1618 RenderObject* endRenderer = endPos.deprecatedNode()->renderer();
1619 view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
1623 void SelectionController::setCaretVisible(bool flag)
1625 if (m_caretVisible == flag)
1627 clearCaretRectIfNeeded();
1628 m_caretVisible = flag;
1632 void SelectionController::clearCaretRectIfNeeded()
1634 #if ENABLE(TEXT_CARET)
1637 m_caretPaint = false;
1638 invalidateCaretRect();
1642 void SelectionController::caretBlinkTimerFired(Timer<SelectionController>*)
1644 #if ENABLE(TEXT_CARET)
1645 ASSERT(m_caretVisible);
1647 bool caretPaint = m_caretPaint;
1648 if (isCaretBlinkingSuspended() && caretPaint)
1650 m_caretPaint = !caretPaint;
1651 invalidateCaretRect();
1655 void SelectionController::notifyRendererOfSelectionChange(bool userTriggered)
1657 m_frame->document()->updateStyleIfNeeded();
1659 if (!rootEditableElement())
1662 RenderObject* renderer = rootEditableElement()->shadowAncestorNode()->renderer();
1663 if (!renderer || !renderer->isTextControl())
1666 toRenderTextControl(renderer)->selectionChanged(userTriggered);
1669 // Helper function that tells whether a particular node is an element that has an entire
1670 // Frame and FrameView, a <frame>, <iframe>, or <object>.
1671 static bool isFrameElement(const Node* n)
1675 RenderObject* renderer = n->renderer();
1676 if (!renderer || !renderer->isWidget())
1678 Widget* widget = toRenderWidget(renderer)->widget();
1679 return widget && widget->isFrameView();
1682 void SelectionController::setFocusedNodeIfNeeded()
1684 if (isNone() || !isFocused())
1687 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
1688 if (caretBrowsing) {
1689 if (Node* anchor = enclosingAnchorElement(base())) {
1690 m_frame->page()->focusController()->setFocusedNode(anchor, m_frame);
1695 if (Node* target = rootEditableElement()) {
1696 // Walk up the DOM tree to search for a node to focus.
1698 // We don't want to set focus on a subframe when selecting in a parent frame,
1699 // so add the !isFrameElement check here. There's probably a better way to make this
1700 // work in the long term, but this is the safest fix at this time.
1701 if (target && target->isMouseFocusable() && !isFrameElement(target)) {
1702 m_frame->page()->focusController()->setFocusedNode(target, m_frame);
1705 target = target->parentOrHostNode();
1707 m_frame->document()->setFocusedNode(0);
1711 m_frame->page()->focusController()->setFocusedNode(0, m_frame);
1714 void SelectionController::paintDragCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const
1716 #if ENABLE(TEXT_CARET)
1717 SelectionController* dragCaretController = m_frame->page()->dragCaretController();
1718 ASSERT(dragCaretController->selection().isCaret());
1719 if (dragCaretController->selection().start().anchorNode()->document()->frame() == m_frame)
1720 dragCaretController->paintCaret(p, tx, ty, clipRect);
1725 UNUSED_PARAM(clipRect);
1729 PassRefPtr<CSSMutableStyleDeclaration> SelectionController::copyTypingStyle() const
1731 if (!m_typingStyle || !m_typingStyle->style())
1733 return m_typingStyle->style()->copy();
1736 bool SelectionController::shouldDeleteSelection(const VisibleSelection& selection) const
1738 return m_frame->editor()->client()->shouldDeleteRange(selection.toNormalizedRange().get());
1741 FloatRect SelectionController::bounds(bool clipToVisibleContent) const
1743 RenderView* root = m_frame->contentRenderer();
1744 FrameView* view = m_frame->view();
1748 IntRect selectionRect = root->selectionBounds(clipToVisibleContent);
1749 return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect;
1752 void SelectionController::getClippedVisibleTextRectangles(Vector<FloatRect>& rectangles) const
1754 RenderView* root = m_frame->contentRenderer();
1758 FloatRect visibleContentRect = m_frame->view()->visibleContentRect();
1760 Vector<FloatQuad> quads;
1761 toNormalizedRange()->textQuads(quads, true);
1763 // FIXME: We are appending empty rectangles to the list for those that fall outside visibleContentRect.
1764 // It might be better to omit those rectangles entirely.
1765 size_t size = quads.size();
1766 for (size_t i = 0; i < size; ++i)
1767 rectangles.append(intersection(quads[i].enclosingBoundingBox(), visibleContentRect));
1770 // Scans logically forward from "start", including any child frames.
1771 static HTMLFormElement* scanForForm(Node* start)
1773 for (Node* node = start; node; node = node->traverseNextNode()) {
1774 if (node->hasTagName(formTag))
1775 return static_cast<HTMLFormElement*>(node);
1776 if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
1777 return static_cast<HTMLFormControlElement*>(node)->form();
1778 if (node->hasTagName(frameTag) || node->hasTagName(iframeTag)) {
1779 Node* childDocument = static_cast<HTMLFrameElementBase*>(node)->contentDocument();
1780 if (HTMLFormElement* frameResult = scanForForm(childDocument))
1787 // We look for either the form containing the current focus, or for one immediately after it
1788 HTMLFormElement* SelectionController::currentForm() const
1790 // Start looking either at the active (first responder) node, or where the selection is.
1791 Node* start = m_frame->document()->focusedNode();
1793 start = this->start().deprecatedNode();
1795 // Try walking up the node tree to find a form element.
1797 for (node = start; node; node = node->parentNode()) {
1798 if (node->hasTagName(formTag))
1799 return static_cast<HTMLFormElement*>(node);
1800 if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
1801 return static_cast<HTMLFormControlElement*>(node)->form();
1804 // Try walking forward in the node tree to find a form element.
1805 return scanForForm(start);
1808 void SelectionController::revealSelection(const ScrollAlignment& alignment, bool revealExtent)
1812 switch (selectionType()) {
1813 case VisibleSelection::NoSelection:
1815 case VisibleSelection::CaretSelection:
1816 rect = absoluteCaretBounds();
1818 case VisibleSelection::RangeSelection:
1819 rect = revealExtent ? VisiblePosition(extent()).absoluteCaretBounds() : enclosingIntRect(bounds(false));
1823 Position start = this->start();
1824 ASSERT(start.deprecatedNode());
1825 if (start.deprecatedNode() && start.deprecatedNode()->renderer()) {
1826 // FIXME: This code only handles scrolling the startContainer's layer, but
1827 // the selection rect could intersect more than just that.
1828 // See <rdar://problem/4799899>.
1829 if (RenderLayer* layer = start.deprecatedNode()->renderer()->enclosingLayer()) {
1830 layer->scrollRectToVisible(rect, false, alignment, alignment);
1836 void SelectionController::setSelectionFromNone()
1838 // Put a caret inside the body if the entire frame is editable (either the
1839 // entire WebView is editable or designMode is on for this document).
1841 Document* document = m_frame->document();
1842 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
1843 if (!isNone() || !(document->rendererIsEditable() || caretBrowsing))
1846 Node* node = document->documentElement();
1847 while (node && !node->hasTagName(bodyTag))
1848 node = node->traverseNextNode();
1850 setSelection(VisibleSelection(firstPositionInOrBeforeNode(node), DOWNSTREAM));
1853 bool SelectionController::shouldChangeSelection(const VisibleSelection& newSelection) const
1855 return m_frame->editor()->shouldChangeSelection(selection(), newSelection, newSelection.affinity(), false);
1860 void SelectionController::formatForDebugger(char* buffer, unsigned length) const
1862 m_selection.formatForDebugger(buffer, length);
1865 void SelectionController::showTreeForThis() const
1867 m_selection.showTreeForThis();
1876 void showTree(const WebCore::SelectionController& sel)
1878 sel.showTreeForThis();
1881 void showTree(const WebCore::SelectionController* sel)
1884 sel->showTreeForThis();