LayoutTests:
[WebKit-https.git] / WebCore / editing / SelectionController.cpp
1 /*
2  * Copyright (C) 2004 Apple Computer, 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 "DeleteSelectionCommand.h"
30 #include "Document.h"
31 #include "Editor.h"
32 #include "Element.h"
33 #include "EventNames.h"
34 #include "FocusController.h"
35 #include "Frame.h"
36 #include "FrameTree.h"
37 #include "FrameView.h"
38 #include "GraphicsContext.h"
39 #include "HTMLInputElement.h"
40 #include "HTMLNames.h"
41 #include "HitTestRequest.h"
42 #include "HitTestResult.h"
43 #include "Page.h"
44 #include "Range.h"
45 #include "RenderView.h"
46 #include "TextIterator.h"
47 #include "TypingCommand.h"
48 #include "htmlediting.h"
49 #include "visible_units.h"
50
51 #define EDIT_DEBUG 0
52
53 namespace WebCore {
54
55 using namespace EventNames;
56 using namespace HTMLNames;
57
58 const int NoXPosForVerticalArrowNavigation = INT_MIN;
59
60 SelectionController::SelectionController(Frame* frame, bool isDragCaretController)
61     : m_needsLayout(true)
62     , m_modifyBiasSet(false)
63     , m_frame(frame)
64     , m_isDragCaretController(isDragCaretController)
65     , m_isCaretBlinkingSuspended(false)
66 {
67 }
68
69 void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered)
70 {
71     setSelection(Selection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
72 }
73
74 void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered)
75 {
76     setSelection(Selection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), true, true, userTriggered);
77 }
78
79 void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered)
80 {
81     setSelection(Selection(pos, affinity), true, true, userTriggered);
82 }
83
84 void SelectionController::moveTo(const Range *r, EAffinity affinity, bool userTriggered)
85 {
86     setSelection(Selection(startPosition(r), endPosition(r), affinity), true, true, userTriggered);
87 }
88
89 void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered)
90 {
91     setSelection(Selection(base, extent, affinity), true, true, userTriggered);
92 }
93
94 void SelectionController::setSelection(const Selection& s, bool closeTyping, bool clearTypingStyle, bool userTriggered)
95 {
96     if (m_isDragCaretController) {
97         invalidateCaretRect();
98         m_sel = s;
99         m_needsLayout = true;
100         invalidateCaretRect();
101         return;
102     }
103     if (!m_frame) {
104         m_sel = s;
105         return;
106     }
107     
108     if (s.base().node() && s.base().node()->document() != m_frame->document()) {
109         s.base().node()->document()->frame()->selectionController()->setSelection(s, closeTyping, clearTypingStyle, userTriggered);
110         return;
111     }
112     
113     if (closeTyping)
114         TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());
115
116     if (clearTypingStyle) {
117         m_frame->clearTypingStyle();
118         m_frame->editor()->setRemovedAnchor(0);
119     }
120         
121     if (m_sel == s)
122         return;
123     
124     Selection oldSelection = m_sel;
125
126     m_sel = s;
127     
128     m_needsLayout = true;
129     
130     if (!s.isNone())
131         m_frame->setFocusedNodeIfNeeded();
132     
133     m_frame->selectionLayoutChanged();
134     // Always clear the x position used for vertical arrow navigation.
135     // It will be restored by the vertical arrow navigation code if necessary.
136     m_frame->setXPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation);
137     selectFrameElementInParentIfFullySelected();
138     m_frame->notifyRendererOfSelectionChange(userTriggered);
139     m_frame->respondToChangedSelection(oldSelection, closeTyping);
140     m_frame->editor()->respondToChangedSelection(oldSelection);
141     if (userTriggered)
142         m_frame->revealCaret(RenderLayer::gAlignToEdgeIfNeeded);
143 }
144
145 void SelectionController::nodeWillBeRemoved(Node *node)
146 {
147     if (isNone())
148         return;
149     
150     Node* base = m_sel.base().node();
151     Node* extent = m_sel.extent().node();
152     Node* start = m_sel.start().node();
153     Node* end = m_sel.end().node();
154     
155     bool baseRemoved = node == base || (base && base->isDescendantOf(node));
156     bool extentRemoved = node == extent || (extent && extent->isDescendantOf(node));
157     bool startRemoved = node == start || (start && start->isDescendantOf(node));
158     bool endRemoved = node == end || (end && end->isDescendantOf(node));
159     
160     bool clearRenderTreeSelection = false;
161     bool clearDOMTreeSelection = false;
162
163     if (startRemoved || endRemoved) {
164         // FIXME: When endpoints are removed, we should just alter the selection, instead of blowing it away.
165         clearRenderTreeSelection = true;
166         clearDOMTreeSelection = true;
167     } else if (baseRemoved || extentRemoved) {
168         if (m_sel.isBaseFirst()) {
169             m_sel.setBase(m_sel.start());
170             m_sel.setExtent(m_sel.end());
171         } else {
172             m_sel.setBase(m_sel.start());
173             m_sel.setExtent(m_sel.end());
174         }
175     // FIXME: This could be more efficient if we had an isNodeInRange function on Ranges.
176     } else if (Range::compareBoundaryPoints(m_sel.start(), Position(node, 0)) == -1 &&
177                Range::compareBoundaryPoints(m_sel.end(), Position(node, 0)) == 1) {
178         // If we did nothing here, when this node's renderer was destroyed, the rect that it 
179         // occupied would be invalidated, but, selection gaps that change as a result of 
180         // the removal wouldn't be invalidated.
181         // FIXME: Don't do so much unnecessary invalidation.
182         clearRenderTreeSelection = true;
183     }
184
185     if (clearRenderTreeSelection) {
186         RefPtr<Document> document = start->document();
187         document->updateRendering();
188         if (RenderView* view = static_cast<RenderView*>(document->renderer()))
189             view->clearSelection();
190     }
191
192     if (clearDOMTreeSelection)
193         setSelection(Selection(), false, false);
194 }
195
196 void SelectionController::setModifyBias(EAlteration alter, EDirection direction)
197 {
198     switch (alter) {
199         case MOVE:
200             m_modifyBiasSet = false;
201             break;
202         case EXTEND:
203             if (!m_modifyBiasSet) {
204                 m_modifyBiasSet = true;
205                 switch (direction) {
206                     // FIXME: right for bidi?
207                     case RIGHT:
208                     case FORWARD:
209                         m_sel.setBase(m_sel.start());
210                         m_sel.setExtent(m_sel.end());
211                         break;
212                     case LEFT:
213                     case BACKWARD:
214                         m_sel.setBase(m_sel.end());
215                         m_sel.setExtent(m_sel.start());
216                         break;
217                 }
218             }
219             break;
220     }
221 }
222
223 VisiblePosition SelectionController::modifyExtendingRightForward(TextGranularity granularity)
224 {
225     VisiblePosition pos(m_sel.extent(), m_sel.affinity());
226     switch (granularity) {
227         case CharacterGranularity:
228             if (isLastVisiblePositionBeforeTableElement(pos.deepEquivalent()))
229                 pos = VisiblePosition(positionAfterFollowingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY);
230             else
231                 pos = pos.next();
232             break;
233         case WordGranularity:
234             if (isLastVisiblePositionBeforeTableElement(pos.deepEquivalent()))
235                 pos = VisiblePosition(positionAfterFollowingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY);
236             else
237                 pos = nextWordPosition(pos);
238             break;
239         case SentenceGranularity:
240             pos = nextSentencePosition(pos);
241             break;
242         case LineGranularity:
243             pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
244             break;
245         case ParagraphGranularity:
246             pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
247             break;
248         case SentenceBoundary:
249             pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
250             break;
251         case LineBoundary:
252             pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
253             break;
254         case ParagraphBoundary:
255             pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
256             break;
257         case DocumentBoundary:
258             pos = VisiblePosition(m_sel.end(), m_sel.affinity());
259             if (pos.deepEquivalent().node()->isContentEditable())
260                 pos = endOfEditableContent(pos);
261             else
262                 pos = endOfDocument(pos);
263             break;
264     }
265     
266     return pos;
267 }
268
269 VisiblePosition SelectionController::modifyMovingRightForward(TextGranularity granularity)
270 {
271     VisiblePosition pos;
272     // FIXME: Stay in editable content for the less common granularities.
273     switch (granularity) {
274         case CharacterGranularity:
275             if (isRange()) 
276                 pos = VisiblePosition(m_sel.end(), m_sel.affinity());
277             else
278                 pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).next(true);
279             break;
280         case WordGranularity:
281             pos = nextWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
282             break;
283         case SentenceGranularity:
284             pos = nextSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
285             break;
286         case LineGranularity: {
287             // down-arrowing from a range selection that ends at the start of a line needs
288             // to leave the selection at that line start (no need to call nextLinePosition!)
289             pos = VisiblePosition(m_sel.end(), m_sel.affinity());
290             if (!isRange() || !isStartOfLine(pos))
291                 pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(END, isRange()));
292             break;
293         }
294         case ParagraphGranularity:
295             pos = nextParagraphPosition(VisiblePosition(m_sel.end(), m_sel.affinity()), xPosForVerticalArrowNavigation(END, isRange()));
296             break;
297         case SentenceBoundary:
298             pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
299             break;
300         case LineBoundary:
301             pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
302             break;
303         case ParagraphBoundary:
304             pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
305             break;
306         case DocumentBoundary:
307             pos = VisiblePosition(m_sel.end(), m_sel.affinity());
308             if (pos.deepEquivalent().node()->isContentEditable())
309                 pos = endOfEditableContent(pos);
310             else
311                 pos = endOfDocument(pos);
312             break;
313             
314     }
315     return pos;
316 }
317
318 VisiblePosition SelectionController::modifyExtendingLeftBackward(TextGranularity granularity)
319 {
320     VisiblePosition pos(m_sel.extent(), m_sel.affinity());
321         
322     // Extending a selection backward by word or character from just after a table selects
323     // the table.  This "makes sense" from the user perspective, esp. when deleting.
324     // It was done here instead of in VisiblePosition because we want VPs to iterate
325     // over everything.
326     switch (granularity) {
327         case CharacterGranularity:
328             if (isFirstVisiblePositionAfterTableElement(pos.deepEquivalent()))
329                 pos = VisiblePosition(positionBeforePrecedingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY);
330             else
331                 pos = pos.previous();
332             break;
333         case WordGranularity:
334             if (isFirstVisiblePositionAfterTableElement(pos.deepEquivalent()))
335                 pos = VisiblePosition(positionBeforePrecedingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY);
336             else
337                 pos = previousWordPosition(pos);
338             break;
339         case SentenceGranularity:
340             pos = previousSentencePosition(pos);
341             break;
342         case LineGranularity:
343             pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
344             break;
345         case ParagraphGranularity:
346             pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
347             break;
348         case SentenceBoundary:
349             pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
350             break;
351         case LineBoundary:
352             pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
353             break;
354         case ParagraphBoundary:
355             pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
356             break;
357         case DocumentBoundary:
358             pos = VisiblePosition(m_sel.start(), m_sel.affinity());
359             if (pos.deepEquivalent().node()->isContentEditable())
360                 pos = startOfEditableContent(pos);
361             else 
362                 pos = startOfDocument(VisiblePosition(m_sel.start(), m_sel.affinity()));
363             break;
364     }
365     return pos;
366 }
367
368 VisiblePosition SelectionController::modifyMovingLeftBackward(TextGranularity granularity)
369 {
370     VisiblePosition pos;
371     // FIXME: Stay in editable content for the less common granularities.
372     switch (granularity) {
373         case CharacterGranularity:
374             if (isRange()) 
375                 pos = VisiblePosition(m_sel.start(), m_sel.affinity());
376             else
377                 pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).previous(true);
378             break;
379         case WordGranularity:
380             pos = previousWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
381             break;
382         case SentenceGranularity:
383             pos = previousSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
384             break;
385         case LineGranularity:
386             pos = previousLinePosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START, isRange()));
387             break;
388         case ParagraphGranularity:
389             pos = previousParagraphPosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START, isRange()));
390             break;
391         case SentenceBoundary:
392             pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
393             break;
394         case LineBoundary:
395             pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
396             break;
397         case ParagraphBoundary:
398             pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
399             break;
400         case DocumentBoundary:
401             pos = VisiblePosition(m_sel.start(), m_sel.affinity());
402             if (pos.deepEquivalent().node()->isContentEditable())
403                 pos = startOfEditableContent(pos);
404             else 
405                 pos = startOfDocument(VisiblePosition(m_sel.start(), m_sel.affinity()));
406             break;
407     }
408     return pos;
409 }
410
411 bool SelectionController::modify(const String &alterString, const String &directionString, const String &granularityString, bool userTriggered)
412 {
413     String alterStringLower = alterString.lower();
414     EAlteration alter;
415     if (alterStringLower == "extend")
416         alter = EXTEND;
417     else if (alterStringLower == "move")
418         alter = MOVE;
419     else 
420         return false;
421     
422     String directionStringLower = directionString.lower();
423     EDirection direction;
424     if (directionStringLower == "forward")
425         direction = FORWARD;
426     else if (directionStringLower == "backward")
427         direction = BACKWARD;
428     else if (directionStringLower == "left")
429         direction = LEFT;
430     else if (directionStringLower == "right")
431         direction = RIGHT;
432     else
433         return false;
434         
435     String granularityStringLower = granularityString.lower();
436     TextGranularity granularity;
437     if (granularityStringLower == "character")
438         granularity = CharacterGranularity;
439     else if (granularityStringLower == "word")
440         granularity = WordGranularity;
441     else if (granularityStringLower == "sentence")
442         granularity = SentenceGranularity;
443     else if (granularityStringLower == "line")
444         granularity = LineGranularity;
445     else if (granularityStringLower == "paragraph")
446         granularity = ParagraphGranularity;
447     else if (granularityStringLower == "lineboundary")
448         granularity = LineBoundary;
449     else if (granularityStringLower == "paragraphboundary")
450         granularity = ParagraphBoundary;
451     else if (granularityStringLower == "documentboundary")
452         granularity = DocumentBoundary;
453     else
454         return false;
455                 
456     return modify(alter, direction, granularity, userTriggered);
457 }
458
459 bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranularity granularity, bool userTriggered)
460 {
461     if (userTriggered) {
462         SelectionController trialSelectionController;
463         trialSelectionController.setSelection(m_sel);
464         trialSelectionController.modify(alter, dir, granularity, false);
465
466         bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
467         if (!change)
468             return false;
469     }
470
471     if (m_frame)
472         m_frame->setSelectionGranularity(granularity);
473     
474     setModifyBias(alter, dir);
475
476     VisiblePosition pos;
477     switch (dir) {
478         // EDIT FIXME: These need to handle bidi
479         case RIGHT:
480         case FORWARD:
481             if (alter == EXTEND)
482                 pos = modifyExtendingRightForward(granularity);
483             else
484                 pos = modifyMovingRightForward(granularity);
485             break;
486         case LEFT:
487         case BACKWARD:
488             if (alter == EXTEND)
489                 pos = modifyExtendingLeftBackward(granularity);
490             else
491                 pos = modifyMovingLeftBackward(granularity);
492             break;
493     }
494
495     if (pos.isNull())
496         return false;
497
498     switch (alter) {
499         case MOVE:
500             moveTo(pos, userTriggered);
501             break;
502         case EXTEND:
503             setExtent(pos, userTriggered);
504             break;
505     }
506
507     if (userTriggered) {
508         // User modified selection change also sets the granularity back to character.
509         // NOTE: The one exception is that we need to keep word granularity to
510         // preserve smart delete behavior when extending by word (e.g. double-click),
511         // then shift-option-right arrow, then delete needs to smart delete, per TextEdit.
512         if (!(alter == EXTEND && granularity == WordGranularity && m_frame->selectionGranularity() == WordGranularity))
513             m_frame->setSelectionGranularity(CharacterGranularity);
514     }
515
516     setNeedsLayout();
517
518     return true;
519 }
520
521 // FIXME: Maybe baseline would be better?
522 static bool caretY(const VisiblePosition &c, int &y)
523 {
524     Position p = c.deepEquivalent();
525     Node *n = p.node();
526     if (!n)
527         return false;
528     RenderObject *r = p.node()->renderer();
529     if (!r)
530         return false;
531     IntRect rect = r->caretRect(p.offset());
532     if (rect.isEmpty())
533         return false;
534     y = rect.y() + rect.height() / 2;
535     return true;
536 }
537
538 bool SelectionController::modify(EAlteration alter, int verticalDistance, bool userTriggered)
539 {
540     if (verticalDistance == 0)
541         return false;
542
543     if (userTriggered) {
544         SelectionController trialSelectionController;
545         trialSelectionController.setSelection(m_sel);
546         trialSelectionController.modify(alter, verticalDistance, false);
547
548         bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
549         if (!change)
550             return false;
551     }
552
553     bool up = verticalDistance < 0;
554     if (up)
555         verticalDistance = -verticalDistance;
556
557     setModifyBias(alter, up ? BACKWARD : FORWARD);
558
559     VisiblePosition pos;
560     int xPos = 0;
561     switch (alter) {
562         case MOVE:
563             pos = VisiblePosition(up ? m_sel.start() : m_sel.end(), m_sel.affinity());
564             xPos = xPosForVerticalArrowNavigation(up ? START : END, isRange());
565             m_sel.setAffinity(up ? UPSTREAM : DOWNSTREAM);
566             break;
567         case EXTEND:
568             pos = VisiblePosition(m_sel.extent(), m_sel.affinity());
569             xPos = xPosForVerticalArrowNavigation(EXTENT);
570             m_sel.setAffinity(DOWNSTREAM);
571             break;
572     }
573
574     int startY;
575     if (!caretY(pos, startY))
576         return false;
577     if (up)
578         startY = -startY;
579     int lastY = startY;
580
581     VisiblePosition result;
582     VisiblePosition next;
583     for (VisiblePosition p = pos; ; p = next) {
584         next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
585         if (next.isNull() || next == p)
586             break;
587         int nextY;
588         if (!caretY(next, nextY))
589             break;
590         if (up)
591             nextY = -nextY;
592         if (nextY - startY > verticalDistance)
593             break;
594         if (nextY >= lastY) {
595             lastY = nextY;
596             result = next;
597         }
598     }
599
600     if (result.isNull())
601         return false;
602
603     switch (alter) {
604         case MOVE:
605             moveTo(result, userTriggered);
606             break;
607         case EXTEND:
608             setExtent(result, userTriggered);
609             break;
610     }
611
612     if (userTriggered)
613         m_frame->setSelectionGranularity(CharacterGranularity);
614
615     return true;
616 }
617
618 bool SelectionController::expandUsingGranularity(TextGranularity granularity)
619 {
620     if (isNone())
621         return false;
622
623     m_sel.expandUsingGranularity(granularity);
624     m_needsLayout = true;
625     return true;
626 }
627
628 int SelectionController::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const
629 {
630     int x = 0;
631
632     if (isNone())
633         return x;
634
635     Position pos;
636     switch (type) {
637         case START:
638             pos = m_sel.start();
639             break;
640         case END:
641             pos = m_sel.end();
642             break;
643         case BASE:
644             pos = m_sel.base();
645             break;
646         case EXTENT:
647             pos = m_sel.extent();
648             break;
649     }
650
651     Frame *frame = pos.node()->document()->frame();
652     if (!frame)
653         return x;
654         
655     if (recalc || frame->xPosForVerticalArrowNavigation() == NoXPosForVerticalArrowNavigation) {
656         pos = VisiblePosition(pos, m_sel.affinity()).deepEquivalent();
657         x = pos.node()->renderer()->caretRect(pos.offset(), m_sel.affinity()).x();
658         frame->setXPosForVerticalArrowNavigation(x);
659     }
660     else {
661         x = frame->xPosForVerticalArrowNavigation();
662     }
663     return x;
664 }
665
666 void SelectionController::clear()
667 {
668     setSelection(Selection());
669 }
670
671 void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
672 {
673     setSelection(Selection(pos.deepEquivalent(), m_sel.extent(), pos.affinity()), true, true, userTriggered);
674 }
675
676 void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered)
677 {
678     setSelection(Selection(m_sel.base(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
679 }
680
681 void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered)
682 {
683     setSelection(Selection(pos, m_sel.extent(), affinity), true, true, userTriggered);
684 }
685
686 void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered)
687 {
688     setSelection(Selection(m_sel.base(), pos, affinity), true, true, userTriggered);
689 }
690
691 void SelectionController::setNeedsLayout(bool flag)
692 {
693     m_needsLayout = flag;
694 }
695
696 String SelectionController::type() const
697 {
698     if (isNone())
699         return "None";
700     else if (isCaret())
701         return "Caret";
702     else
703         return "Range";
704 }
705
706 String SelectionController::toString() const
707 {
708     return String(plainText(m_sel.toRange().get()));
709 }
710
711 PassRefPtr<Range> SelectionController::getRangeAt(int index) const
712 {
713     return index == 0 ? m_sel.toRange() : 0;
714 }
715
716 void SelectionController::removeAllRanges()
717 {
718     clear();
719 }
720
721 // Adds r to the currently selected range.
722 void SelectionController::addRange(const Range* r)
723 {
724     if (isNone()) {
725         setSelection(Selection(r));
726         return;
727     }
728
729     RefPtr<Range> range = m_sel.toRange();
730     ExceptionCode ec = 0;
731     if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), ec) == -1) {
732         // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
733         if (r->compareBoundaryPoints(Range::END_TO_START, range.get(), ec) > -1) {
734             if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1)
735                 // The original range and r intersect.
736                 setSelection(Selection(r->startPosition(), range->endPosition(), DOWNSTREAM));
737             else
738                 // r contains the original range.
739                 setSelection(Selection(r));
740         }
741     } else {
742         // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
743         if (r->compareBoundaryPoints(Range::START_TO_END, range.get(), ec) < 1) {
744             if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1)
745                 // The original range contains r.
746                 setSelection(Selection(range.get()));
747             else
748                 // The original range and r intersect.
749                 setSelection(Selection(range->startPosition(), r->endPosition(), DOWNSTREAM));
750         }
751     }
752 }
753
754 void SelectionController::setBaseAndExtent(Node *baseNode, int baseOffset, Node *extentNode, int extentOffset)
755 {
756     VisiblePosition visibleBase = VisiblePosition(baseNode, baseOffset, DOWNSTREAM);
757     VisiblePosition visibleExtent = VisiblePosition(extentNode, extentOffset, DOWNSTREAM);
758     
759     moveTo(visibleBase, visibleExtent);
760 }
761
762 void SelectionController::setPosition(Node *node, int offset)
763 {
764     moveTo(VisiblePosition(node, offset, DOWNSTREAM));
765 }
766
767 void SelectionController::collapse(Node *node, int offset)
768 {
769     moveTo(VisiblePosition(node, offset, DOWNSTREAM));
770 }
771
772 void SelectionController::collapseToEnd()
773 {
774     moveTo(VisiblePosition(m_sel.end(), DOWNSTREAM));
775 }
776
777 void SelectionController::collapseToStart()
778 {
779     moveTo(VisiblePosition(m_sel.start(), DOWNSTREAM));
780 }
781
782 void SelectionController::empty()
783 {
784     moveTo(VisiblePosition());
785 }
786
787 void SelectionController::extend(Node *node, int offset)
788 {
789     moveTo(VisiblePosition(node, offset, DOWNSTREAM));
790 }
791
792 void SelectionController::layout()
793 {
794     if (isNone() || !m_sel.start().node()->inDocument() || !m_sel.end().node()->inDocument()) {
795         m_caretRect = IntRect();
796         m_caretPositionOnLayout = IntPoint();
797         return;
798     }
799
800     m_sel.start().node()->document()->updateRendering();
801     
802     m_caretRect = IntRect();
803     m_caretPositionOnLayout = IntPoint();
804         
805     if (isCaret()) {
806         Position pos = m_sel.start();
807         pos = VisiblePosition(m_sel.start(), m_sel.affinity()).deepEquivalent();
808         if (pos.isNotNull()) {
809             ASSERT(pos.node()->renderer());
810             m_caretRect = pos.node()->renderer()->caretRect(pos.offset(), m_sel.affinity());
811             
812             int x, y;
813             pos.node()->renderer()->absolutePositionForContent(x, y);
814             m_caretPositionOnLayout = IntPoint(x, y);
815         }
816     }
817
818     m_needsLayout = false;
819 }
820
821 IntRect SelectionController::caretRect() const
822 {
823     if (m_needsLayout)
824         const_cast<SelectionController *>(this)->layout();
825     
826     IntRect caret = m_caretRect;
827
828     if (m_sel.start().node() && m_sel.start().node()->renderer()) {
829         int x, y;
830         m_sel.start().node()->renderer()->absolutePositionForContent(x, y);
831         caret.move(IntPoint(x, y) - m_caretPositionOnLayout);
832     }
833
834     return caret;
835 }
836
837 static IntRect repaintRectForCaret(IntRect caret)
838 {
839     if (caret.isEmpty())
840         return IntRect();
841     caret.inflate(1);
842     return caret;
843 }
844
845 IntRect SelectionController::caretRepaintRect() const
846 {
847     return repaintRectForCaret(caretRect());
848 }
849
850 bool SelectionController::recomputeCaretRect()
851 {
852     if (!m_frame || !m_frame->document())
853         return false;
854         
855     FrameView* v = m_frame->document()->view();
856     if (!v)
857         return false;
858
859     if (!m_needsLayout)
860         return false;
861
862     IntRect oldRect = m_caretRect;
863     m_needsLayout = true;
864     IntRect newRect = caretRect();
865     if (oldRect == newRect)
866         return false;
867
868     v->updateContents(repaintRectForCaret(oldRect), false);
869     v->updateContents(repaintRectForCaret(newRect), false);
870     return true;
871 }
872
873 void SelectionController::invalidateCaretRect()
874 {
875     if (!isCaret())
876         return;
877
878     FrameView* v = m_sel.start().node()->document()->view();
879     if (!v)
880         return;
881
882     bool caretRectChanged = recomputeCaretRect();
883
884     // EDIT FIXME: This is an unfortunate hack.
885     // Basically, we can't trust this layout position since we 
886     // can't guarantee that the check to see if we are in unrendered 
887     // content will work at this point. We may have to wait for
888     // a layout and re-render of the document to happen. So, resetting this
889     // flag will cause another caret layout to happen the first time
890     // that we try to paint the caret after this call. That one will work since
891     // it happens after the document has accounted for any editing
892     // changes which may have been done.
893     // And, we need to leave this layout here so the caret moves right 
894     // away after clicking.
895     m_needsLayout = true;
896
897     if (!caretRectChanged)
898         v->updateContents(caretRepaintRect(), false);
899 }
900
901 void SelectionController::paintCaret(GraphicsContext *p, const IntRect &rect)
902 {
903     if (! m_sel.isCaret())
904         return;
905
906     if (m_needsLayout)
907         layout();
908         
909     IntRect caret = intersection(caretRect(), rect);
910     if (!caret.isEmpty()) {
911         Color caretColor = Color::black;
912         Element* element = rootEditableElement();
913         if (element && element->renderer())
914             caretColor = element->renderer()->style()->color();
915
916         p->fillRect(caret, caretColor);
917     }
918 }
919
920 void SelectionController::debugRenderer(RenderObject *r, bool selected) const
921 {
922     if (r->node()->isElementNode()) {
923         Element *element = static_cast<Element *>(r->node());
924         fprintf(stderr, "%s%s\n", selected ? "==> " : "    ", element->localName().deprecatedString().latin1());
925     }
926     else if (r->isText()) {
927         RenderText* textRenderer = static_cast<RenderText*>(r);
928         if (textRenderer->textLength() == 0 || !textRenderer->firstTextBox()) {
929             fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : "    ");
930             return;
931         }
932         
933         static const int max = 36;
934         DeprecatedString text = String(textRenderer->text()).deprecatedString();
935         int textLength = text.length();
936         if (selected) {
937             int offset = 0;
938             if (r->node() == m_sel.start().node())
939                 offset = m_sel.start().offset();
940             else if (r->node() == m_sel.end().node())
941                 offset = m_sel.end().offset();
942                 
943             int pos;
944             InlineTextBox *box = textRenderer->findNextInlineTextBox(offset, pos);
945             text = text.mid(box->m_start, box->m_len);
946             
947             DeprecatedString show;
948             int mid = max / 2;
949             int caret = 0;
950             
951             // text is shorter than max
952             if (textLength < max) {
953                 show = text;
954                 caret = pos;
955             }
956             
957             // too few characters to left
958             else if (pos - mid < 0) {
959                 show = text.left(max - 3) + "...";
960                 caret = pos;
961             }
962             
963             // enough characters on each side
964             else if (pos - mid >= 0 && pos + mid <= textLength) {
965                 show = "..." + text.mid(pos - mid + 3, max - 6) + "...";
966                 caret = mid;
967             }
968             
969             // too few characters on right
970             else {
971                 show = "..." + text.right(max - 3);
972                 caret = pos - (textLength - show.length());
973             }
974             
975             show.replace('\n', ' ');
976             show.replace('\r', ' ');
977             fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.latin1(), pos);
978             fprintf(stderr, "           ");
979             for (int i = 0; i < caret; i++)
980                 fprintf(stderr, " ");
981             fprintf(stderr, "^\n");
982         }
983         else {
984             if ((int)text.length() > max)
985                 text = text.left(max - 3) + "...";
986             else
987                 text = text.left(max);
988             fprintf(stderr, "    #text : \"%s\"\n", text.latin1());
989         }
990     }
991 }
992
993 bool SelectionController::contains(const IntPoint& point)
994 {
995     Document* document = m_frame->document();
996     
997     // Treat a collapsed selection like no selection.
998     if (!isRange())
999         return false;
1000     if (!document->renderer()) 
1001         return false;
1002     
1003     HitTestRequest request(true, true);
1004     HitTestResult result(point);
1005     document->renderer()->layer()->hitTest(request, result);
1006     Node *innerNode = result.innerNode();
1007     if (!innerNode || !innerNode->renderer())
1008         return false;
1009     
1010     Position pos(innerNode->renderer()->positionForPoint(result.localPoint()).deepEquivalent());
1011     if (pos.isNull())
1012         return false;
1013
1014     Node *n = start().node();
1015     while (n) {
1016         if (n == pos.node()) {
1017             if ((n == start().node() && pos.offset() < start().offset()) ||
1018                 (n == end().node() && pos.offset() > end().offset())) {
1019                 return false;
1020             }
1021             return true;
1022         }
1023         if (n == end().node())
1024             break;
1025         n = n->traverseNextNode();
1026     }
1027
1028    return false;
1029 }
1030
1031 // Workaround for the fact that it's hard to delete a frame.
1032 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
1033 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
1034 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
1035 // mouse or the keyboard after setting the selection.
1036 void SelectionController::selectFrameElementInParentIfFullySelected()
1037 {
1038     // Find the parent frame; if there is none, then we have nothing to do.
1039     Frame* parent = m_frame->tree()->parent();
1040     if (!parent)
1041         return;
1042     Page* page = m_frame->page();
1043     if (!page)
1044         return;
1045
1046     // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
1047     if (!isRange())
1048         return;
1049     if (!isStartOfDocument(selection().visibleStart()))
1050         return;
1051     if (!isEndOfDocument(selection().visibleEnd()))
1052         return;
1053
1054     // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
1055     Document* doc = m_frame->document();
1056     if (!doc)
1057         return;
1058     Element* ownerElement = doc->ownerElement();
1059     if (!ownerElement)
1060         return;
1061     Node* ownerElementParent = ownerElement->parentNode();
1062     if (!ownerElementParent)
1063         return;
1064         
1065     // 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.
1066     if (!ownerElementParent->isContentEditable())
1067         return;
1068
1069     // Create compute positions before and after the element.
1070     unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
1071     VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
1072     VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
1073
1074     // Focus on the parent frame, and then select from before this element to after.
1075     Selection newSelection(beforeOwnerElement, afterOwnerElement);
1076     if (parent->shouldChangeSelection(newSelection)) {
1077         page->focusController()->setFocusedFrame(parent);
1078         parent->selectionController()->setSelection(newSelection);
1079     }
1080 }
1081
1082 void SelectionController::selectAll()
1083 {
1084     Document* document = m_frame->document();
1085     if (!document)
1086         return;
1087     
1088     if (document->focusedNode() && document->focusedNode()->canSelectAll()) {
1089         document->focusedNode()->selectAll();
1090         return;
1091     }
1092     
1093     Node* root = isContentEditable() ? highestEditableRoot(m_sel.start()) : document->documentElement();
1094     if (!root->renderer() || !root->renderer()->canSelect())
1095         return;
1096     Selection newSelection(Selection::selectionFromContentsOfNode(root));
1097     if (m_frame->shouldChangeSelection(newSelection))
1098         setSelection(newSelection);
1099     selectFrameElementInParentIfFullySelected();
1100     m_frame->notifyRendererOfSelectionChange(true);
1101 }
1102
1103 void SelectionController::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping, ExceptionCode& ec)
1104 {
1105     ec = 0;
1106     
1107     Node* startContainer = range->startContainer(ec);
1108     if (ec)
1109         return;
1110
1111     Node* endContainer = range->endContainer(ec);
1112     if (ec)
1113         return;
1114     
1115     ASSERT(startContainer);
1116     ASSERT(endContainer);
1117     ASSERT(startContainer->document() == endContainer->document());
1118     
1119     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1120
1121     // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
1122     // they start at the beginning of the next line instead
1123     bool collapsed = range->collapsed(ec);
1124     if (ec)
1125         return;
1126     
1127     int startOffset = range->startOffset(ec);
1128     if (ec)
1129         return;
1130
1131     int endOffset = range->endOffset(ec);
1132     if (ec)
1133         return;
1134     
1135     // FIXME: Can we provide extentAffinity?
1136     VisiblePosition visibleStart(startContainer, startOffset, collapsed ? affinity : DOWNSTREAM);
1137     VisiblePosition visibleEnd(endContainer, endOffset, SEL_DEFAULT_AFFINITY);
1138     setSelection(Selection(visibleStart, visibleEnd), closeTyping);
1139 }
1140
1141 bool SelectionController::isInPasswordField() const
1142 {
1143     Node* startNode = start().node();
1144     if (!startNode)
1145         return false;
1146
1147     startNode = startNode->shadowAncestorNode();
1148     if (!startNode)
1149         return false;
1150
1151     if (!startNode->hasTagName(inputTag))
1152         return false;
1153     
1154     return static_cast<HTMLInputElement*>(startNode)->inputType() == HTMLInputElement::PASSWORD;
1155 }
1156   
1157 #ifndef NDEBUG
1158
1159 void SelectionController::formatForDebugger(char* buffer, unsigned length) const
1160 {
1161     m_sel.formatForDebugger(buffer, length);
1162 }
1163
1164 void SelectionController::showTreeForThis() const
1165 {
1166     m_sel.showTreeForThis();
1167 }
1168
1169 #endif
1170
1171 }
1172
1173 #ifndef NDEBUG
1174
1175 void showTree(const WebCore::SelectionController& sel)
1176 {
1177     sel.showTreeForThis();
1178 }
1179
1180 void showTree(const WebCore::SelectionController* sel)
1181 {
1182     if (sel)
1183         sel->showTreeForThis();
1184 }
1185
1186 #endif