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