git-svn-id: https://svn.webkit.org/repository/webkit/trunk@14916 268f45cc-cd09-0410...
[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 "Document.h"
30 #include "Element.h"
31 #include "EventNames.h"
32 #include "Frame.h"
33 #include "GraphicsContext.h"
34 #include "RenderView.h"
35 #include "TextIterator.h"
36 #include "htmlediting.h"
37 #include "visible_units.h"
38
39 #define EDIT_DEBUG 0
40
41 namespace WebCore {
42
43 using namespace EventNames;
44
45 SelectionController::SelectionController()
46     : m_needsLayout(true)
47 {
48     setSelection(Selection());
49 }
50
51 SelectionController::SelectionController(const Selection &sel)
52     : m_needsLayout(true)
53     , m_modifyBiasSet(false)
54 {
55     setSelection(sel);
56 }
57
58 SelectionController::SelectionController(const Position &pos, EAffinity affinity)
59     : m_needsLayout(true)
60     , m_modifyBiasSet(false)
61 {
62     setSelection(Selection(pos, pos, affinity));
63 }
64
65 SelectionController::SelectionController(const Range *r, EAffinity affinity)
66     : m_needsLayout(true)
67     , m_modifyBiasSet(false)
68 {
69     setSelection(Selection(startPosition(r), endPosition(r), affinity));
70 }
71
72 SelectionController::SelectionController(const Position &base, const Position &extent, EAffinity affinity)
73     : m_needsLayout(true)
74     , m_modifyBiasSet(false)
75 {
76     setSelection(Selection(base, extent, affinity));
77 }
78
79 SelectionController::SelectionController(const VisiblePosition &visiblePos)
80     : m_needsLayout(true)
81     , m_modifyBiasSet(false)
82 {
83     setSelection(Selection(visiblePos.deepEquivalent(), visiblePos.deepEquivalent(), visiblePos.affinity()));
84 }
85
86 SelectionController::SelectionController(const VisiblePosition &base, const VisiblePosition &extent)
87     : m_needsLayout(true)
88     , m_modifyBiasSet(false)
89 {
90     setSelection(Selection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()));
91 }
92
93 SelectionController::SelectionController(const SelectionController &o)
94     : m_needsLayout(o.m_needsLayout)
95     , m_modifyBiasSet(o.m_modifyBiasSet)
96 {
97     setSelection(o.m_sel); 
98     // Only copy the coordinates over if the other object
99     // has had a layout, otherwise keep the current
100     // coordinates. This prevents drawing artifacts from
101     // remaining when the caret is painted and then moves,
102     // and the old rectangle needs to be repainted.
103     if (!m_needsLayout) {
104         m_caretRect = o.m_caretRect;
105         m_caretPositionOnLayout = o.m_caretPositionOnLayout;
106     }
107 }
108
109 SelectionController &SelectionController::operator=(const SelectionController &o)
110 {
111     setSelection(o.m_sel);
112
113     m_needsLayout = o.m_needsLayout;
114     m_modifyBiasSet = o.m_modifyBiasSet;
115     
116     // Only copy the coordinates over if the other object
117     // has had a layout, otherwise keep the current
118     // coordinates. This prevents drawing artifacts from
119     // remaining when the caret is painted and then moves,
120     // and the old rectangle needs to be repainted.
121     if (!m_needsLayout) {
122         m_caretRect = o.m_caretRect;
123         m_caretPositionOnLayout = o.m_caretPositionOnLayout;
124     }
125     
126     return *this;
127 }
128
129 void SelectionController::moveTo(const VisiblePosition &pos)
130 {
131     setSelection(Selection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()));
132     m_needsLayout = true;
133 }
134
135 void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent)
136 {
137     setSelection(Selection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()));
138     m_needsLayout = true;
139 }
140
141 void SelectionController::moveTo(const SelectionController &o)
142 {
143     setSelection(o.m_sel);
144     m_needsLayout = true;
145 }
146
147 void SelectionController::moveTo(const Position &pos, EAffinity affinity)
148 {
149     setSelection(Selection(pos, affinity));
150     m_needsLayout = true;
151 }
152
153 void SelectionController::moveTo(const Range *r, EAffinity affinity)
154 {
155     setSelection(Selection(startPosition(r), endPosition(r), affinity));
156     m_needsLayout = true;
157 }
158
159 void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity)
160 {
161     setSelection(Selection(base, extent, affinity));
162     m_needsLayout = true;
163 }
164
165 void SelectionController::setSelection(const Selection& newSelection)
166 {
167     m_sel = newSelection;
168 }
169
170 void SelectionController::nodeWillBeRemoved(Node *node)
171 {
172     if (isNone())
173         return;
174     
175     Node* base = m_sel.base().node();
176     Node* extent = m_sel.extent().node();
177     Node* start = m_sel.start().node();
178     Node* end = m_sel.end().node();
179     
180     bool baseRemoved = node == base || base->isAncestor(node);
181     bool extentRemoved = node == extent || extent->isAncestor(node);
182     bool startRemoved = node == start || start->isAncestor(node);
183     bool endRemoved = node == end || end->isAncestor(node);
184     
185     if (startRemoved || endRemoved) {
186     
187         // FIXME (6498): This doesn't notify the editing delegate of a selection change.
188
189         // FIXME: When endpoints are removed, we should just alter the selection, instead of blowing it away.
190         
191         static_cast<RenderView*>(start->document()->renderer())->clearSelection();
192         setSelection(Selection());
193         
194     } else if (baseRemoved || extentRemoved) {
195         if (m_sel.isBaseFirst()) {
196             m_sel.setBase(m_sel.start());
197             m_sel.setExtent(m_sel.end());
198         } else {
199             m_sel.setBase(m_sel.start());
200             m_sel.setExtent(m_sel.end());
201         }
202     // FIXME: This could be more efficient if we had an isNodeInRange function on Ranges.
203     } else if (Range::compareBoundaryPoints(m_sel.start(), Position(node, 0)) == -1 &&
204                Range::compareBoundaryPoints(m_sel.end(), Position(node, 0)) == 1) {
205         // If we did nothing here, when this node's renderer was destroyed, the rect that it 
206         // occupied would be invalidated, but, selection gaps that change as a result of 
207         // the removal wouldn't be invalidated.
208         // FIXME: Don't do so much unnecessary invalidation.
209         static_cast<RenderView*>(start->document()->renderer())->clearSelection();
210     }
211 }
212
213 void SelectionController::setModifyBias(EAlter alter, EDirection direction)
214 {
215     switch (alter) {
216         case MOVE:
217             m_modifyBiasSet = false;
218             break;
219         case EXTEND:
220             if (!m_modifyBiasSet) {
221                 m_modifyBiasSet = true;
222                 switch (direction) {
223                     // FIXME: right for bidi?
224                     case RIGHT:
225                     case FORWARD:
226                         m_sel.setBase(m_sel.start());
227                         m_sel.setExtent(m_sel.end());
228                         break;
229                     case LEFT:
230                     case BACKWARD:
231                         m_sel.setBase(m_sel.end());
232                         m_sel.setExtent(m_sel.start());
233                         break;
234                 }
235             }
236             break;
237     }
238 }
239
240 VisiblePosition SelectionController::modifyExtendingRightForward(TextGranularity granularity)
241 {
242     VisiblePosition pos(m_sel.extent(), m_sel.affinity());
243     switch (granularity) {
244         case CharacterGranularity:
245             if (isLastVisiblePositionBeforeTableElement(pos.deepEquivalent()))
246                 pos = VisiblePosition(positionAfterFollowingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY);
247             else
248                 pos = pos.next();
249             break;
250         case WordGranularity:
251             if (isLastVisiblePositionBeforeTableElement(pos.deepEquivalent()))
252                 pos = VisiblePosition(positionAfterFollowingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY);
253             else
254                 pos = nextWordPosition(pos);
255             break;
256         case SentenceGranularity:
257             pos = nextSentencePosition(pos);
258             break;
259         case LineGranularity:
260             pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
261             break;
262         case ParagraphGranularity:
263             pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
264             break;
265         case SentenceBoundary:
266             pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
267             break;
268         case LineBoundary:
269             pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
270             break;
271         case ParagraphBoundary:
272             pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
273             break;
274         case DocumentBoundary:
275             pos = endOfDocument(pos);
276             break;
277     }
278     
279     return pos;
280 }
281
282 VisiblePosition SelectionController::modifyMovingRightForward(TextGranularity granularity)
283 {
284     VisiblePosition pos;
285     switch (granularity) {
286         case CharacterGranularity:
287             if (isRange()) 
288                 pos = VisiblePosition(m_sel.end(), m_sel.affinity());
289             else
290                 pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).next();
291             break;
292         case WordGranularity:
293             pos = nextWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
294             break;
295         case SentenceGranularity:
296             pos = nextSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
297             break;
298         case LineGranularity: {
299             // down-arrowing from a range selection that ends at the start of a line needs
300             // to leave the selection at that line start (no need to call nextLinePosition!)
301             pos = VisiblePosition(m_sel.end(), m_sel.affinity());
302             if (!isRange() || !isStartOfLine(pos))
303                 pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(END, isRange()));
304             break;
305         }
306         case ParagraphGranularity:
307             pos = nextParagraphPosition(VisiblePosition(m_sel.end(), m_sel.affinity()), xPosForVerticalArrowNavigation(END, isRange()));
308             break;
309         case SentenceBoundary:
310             pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
311             break;
312         case LineBoundary:
313             pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
314             break;
315         case ParagraphBoundary:
316             pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
317             break;
318         case DocumentBoundary:
319             pos = endOfDocument(VisiblePosition(m_sel.end(), m_sel.affinity()));
320             break;
321     }
322     return pos;
323 }
324
325 VisiblePosition SelectionController::modifyExtendingLeftBackward(TextGranularity granularity)
326 {
327     VisiblePosition pos(m_sel.extent(), m_sel.affinity());
328         
329     // Extending a selection backward by word or character from just after a table selects
330     // the table.  This "makes sense" from the user perspective, esp. when deleting.
331     // It was done here instead of in VisiblePosition because we want VPs to iterate
332     // over everything.
333     switch (granularity) {
334         case CharacterGranularity:
335             if (isFirstVisiblePositionAfterTableElement(pos.deepEquivalent()))
336                 pos = VisiblePosition(positionBeforePrecedingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY);
337             else
338                 pos = pos.previous();
339             break;
340         case WordGranularity:
341             if (isFirstVisiblePositionAfterTableElement(pos.deepEquivalent()))
342                 pos = VisiblePosition(positionBeforePrecedingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY);
343             else
344                 pos = previousWordPosition(pos);
345             break;
346         case SentenceGranularity:
347             pos = previousSentencePosition(pos);
348             break;
349         case LineGranularity:
350             pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
351             break;
352         case ParagraphGranularity:
353             pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
354             break;
355         case SentenceBoundary:
356             pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
357             break;
358         case LineBoundary:
359             pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
360             break;
361         case ParagraphBoundary:
362             pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
363             break;
364         case DocumentBoundary:
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();
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, isRange()));
389             break;
390         case ParagraphGranularity:
391             pos = previousParagraphPosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START, isRange()));
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 = startOfDocument(VisiblePosition(m_sel.start(), m_sel.affinity()));
404             break;
405     }
406     return pos;
407 }
408
409 bool SelectionController::modify(const String &alterString, const String &directionString, const String &granularityString)
410 {
411     String alterStringLower = alterString.lower();
412     EAlter alter;
413     if (alterStringLower == "extend")
414         alter = EXTEND;
415     else if (alterStringLower == "move")
416         alter = MOVE;
417     else 
418         return false;
419     
420     String directionStringLower = directionString.lower();
421     EDirection direction;
422     if (directionStringLower == "forward")
423         direction = FORWARD;
424     else if (directionStringLower == "backward")
425         direction = BACKWARD;
426     else if (directionStringLower == "left")
427         direction = LEFT;
428     else if (directionStringLower == "right")
429         direction = RIGHT;
430     else
431         return false;
432         
433     String granularityStringLower = granularityString.lower();
434     TextGranularity granularity;
435     if (granularityStringLower == "character")
436         granularity = CharacterGranularity;
437     else if (granularityStringLower == "word")
438         granularity = WordGranularity;
439     else if (granularityStringLower == "sentence")
440         granularity = SentenceGranularity;
441     else if (granularityStringLower == "line")
442         granularity = LineGranularity;
443     else if (granularityStringLower == "paragraph")
444         granularity = ParagraphGranularity;
445     else
446         return false;
447                 
448     return modify(alter, direction, granularity);
449 }
450
451 bool SelectionController::modify(EAlter alter, EDirection dir, TextGranularity granularity)
452 {
453     if (frame())
454         frame()->setSelectionGranularity(granularity);
455     
456     setModifyBias(alter, dir);
457
458     VisiblePosition pos;
459     switch (dir) {
460         // EDIT FIXME: These need to handle bidi
461         case RIGHT:
462         case FORWARD:
463             if (alter == EXTEND)
464                 pos = modifyExtendingRightForward(granularity);
465             else
466                 pos = modifyMovingRightForward(granularity);
467             break;
468         case LEFT:
469         case BACKWARD:
470             if (alter == EXTEND)
471                 pos = modifyExtendingLeftBackward(granularity);
472             else
473                 pos = modifyMovingLeftBackward(granularity);
474             break;
475     }
476
477     if (pos.isNull())
478         return false;
479
480     switch (alter) {
481         case MOVE:
482             moveTo(pos);
483             break;
484         case EXTEND:
485             setExtent(pos);
486             break;
487     }
488
489     setNeedsLayout();
490
491     return true;
492 }
493
494 // FIXME: Maybe baseline would be better?
495 static bool caretY(const VisiblePosition &c, int &y)
496 {
497     Position p = c.deepEquivalent();
498     Node *n = p.node();
499     if (!n)
500         return false;
501     RenderObject *r = p.node()->renderer();
502     if (!r)
503         return false;
504     IntRect rect = r->caretRect(p.offset());
505     if (rect.isEmpty())
506         return false;
507     y = rect.y() + rect.height() / 2;
508     return true;
509 }
510
511 bool SelectionController::modify(EAlter alter, int verticalDistance)
512 {
513     if (verticalDistance == 0)
514         return false;
515
516     bool up = verticalDistance < 0;
517     if (up)
518         verticalDistance = -verticalDistance;
519
520     setModifyBias(alter, up ? BACKWARD : FORWARD);
521
522     VisiblePosition pos;
523     int xPos = 0;
524     switch (alter) {
525         case MOVE:
526             pos = VisiblePosition(up ? m_sel.start() : m_sel.end(), m_sel.affinity());
527             xPos = xPosForVerticalArrowNavigation(up ? START : END, isRange());
528             m_sel.setAffinity(up ? UPSTREAM : DOWNSTREAM);
529             break;
530         case EXTEND:
531             pos = VisiblePosition(m_sel.extent(), m_sel.affinity());
532             xPos = xPosForVerticalArrowNavigation(EXTENT);
533             m_sel.setAffinity(DOWNSTREAM);
534             break;
535     }
536
537     int startY;
538     if (!caretY(pos, startY))
539         return false;
540     if (up)
541         startY = -startY;
542     int lastY = startY;
543
544     VisiblePosition result;
545     VisiblePosition next;
546     for (VisiblePosition p = pos; ; p = next) {
547         next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
548         if (next.isNull() || next == p)
549             break;
550         int nextY;
551         if (!caretY(next, nextY))
552             break;
553         if (up)
554             nextY = -nextY;
555         if (nextY - startY > verticalDistance)
556             break;
557         if (nextY >= lastY) {
558             lastY = nextY;
559             result = next;
560         }
561     }
562
563     if (result.isNull())
564         return false;
565
566     switch (alter) {
567         case MOVE:
568             moveTo(result);
569             break;
570         case EXTEND:
571             setExtent(result);
572             break;
573     }
574
575     return true;
576 }
577
578 bool SelectionController::expandUsingGranularity(TextGranularity granularity)
579 {
580     if (isNone())
581         return false;
582
583     m_sel.expandUsingGranularity(granularity);
584     m_needsLayout = true;
585     return true;
586 }
587
588 int SelectionController::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const
589 {
590     int x = 0;
591
592     if (isNone())
593         return x;
594
595     Position pos;
596     switch (type) {
597         case START:
598             pos = m_sel.start();
599             break;
600         case END:
601             pos = m_sel.end();
602             break;
603         case BASE:
604             pos = m_sel.base();
605             break;
606         case EXTENT:
607             pos = m_sel.extent();
608             break;
609     }
610
611     Frame *frame = pos.node()->document()->frame();
612     if (!frame)
613         return x;
614         
615     if (recalc || frame->xPosForVerticalArrowNavigation() == Frame::NoXPosForVerticalArrowNavigation) {
616         pos = VisiblePosition(pos, m_sel.affinity()).deepEquivalent();
617         x = pos.node()->renderer()->caretRect(pos.offset(), m_sel.affinity()).x();
618         frame->setXPosForVerticalArrowNavigation(x);
619     }
620     else {
621         x = frame->xPosForVerticalArrowNavigation();
622     }
623     return x;
624 }
625
626 void SelectionController::clear()
627 {
628     setSelection(Selection());
629     m_needsLayout = true;
630 }
631
632 void SelectionController::setBase(const VisiblePosition &pos)
633 {
634     setSelection(Selection(pos.deepEquivalent(), m_sel.extent(), pos.affinity()));
635     m_needsLayout = true;
636 }
637
638 void SelectionController::setExtent(const VisiblePosition &pos)
639 {
640     setSelection(Selection(m_sel.base(), pos.deepEquivalent(), pos.affinity()));
641     m_needsLayout = true;
642 }
643
644 void SelectionController::setBase(const Position &pos, EAffinity affinity)
645 {
646     setSelection(Selection(pos, m_sel.extent(), affinity));
647     m_needsLayout = true;
648 }
649
650 void SelectionController::setExtent(const Position &pos, EAffinity affinity)
651 {
652     setSelection(Selection(m_sel.base(), pos, affinity));
653     m_needsLayout = true;
654 }
655
656 void SelectionController::setNeedsLayout(bool flag)
657 {
658     m_needsLayout = flag;
659 }
660
661 String SelectionController::type() const
662 {
663     if (isNone())
664         return "None";
665     else if (isCaret())
666         return "Caret";
667     else
668         return "Range";
669 }
670
671 String SelectionController::toString() const
672 {
673     return String(plainText(m_sel.toRange().get()));
674 }
675
676 PassRefPtr<Range> SelectionController::getRangeAt(int index) const
677 {
678     return index == 0 ? m_sel.toRange() : 0;
679 }
680
681 Frame *SelectionController::frame() const
682 {
683     return !isNone() ? m_sel.start().node()->document()->frame() : 0;
684 }
685
686 void SelectionController::setBaseAndExtent(Node *baseNode, int baseOffset, Node *extentNode, int extentOffset)
687 {
688     VisiblePosition visibleBase = VisiblePosition(baseNode, baseOffset, DOWNSTREAM);
689     VisiblePosition visibleExtent = VisiblePosition(extentNode, extentOffset, DOWNSTREAM);
690     
691     moveTo(visibleBase, visibleExtent);
692 }
693
694 void SelectionController::setPosition(Node *node, int offset)
695 {
696     moveTo(VisiblePosition(node, offset, DOWNSTREAM));
697 }
698
699 void SelectionController::collapse(Node *node, int offset)
700 {
701     moveTo(VisiblePosition(node, offset, DOWNSTREAM));
702 }
703
704 void SelectionController::collapseToEnd()
705 {
706     moveTo(VisiblePosition(m_sel.end(), DOWNSTREAM));
707 }
708
709 void SelectionController::collapseToStart()
710 {
711     moveTo(VisiblePosition(m_sel.start(), DOWNSTREAM));
712 }
713
714 void SelectionController::empty()
715 {
716     moveTo(SelectionController());
717 }
718
719 void SelectionController::extend(Node *node, int offset)
720 {
721     moveTo(VisiblePosition(node, offset, DOWNSTREAM));
722 }
723
724 void SelectionController::layout()
725 {
726     if (isNone() || !m_sel.start().node()->inDocument() || !m_sel.end().node()->inDocument()) {
727         m_caretRect = IntRect();
728         m_caretPositionOnLayout = IntPoint();
729         return;
730     }
731
732     m_sel.start().node()->document()->updateRendering();
733     
734     m_caretRect = IntRect();
735     m_caretPositionOnLayout = IntPoint();
736         
737     if (isCaret()) {
738         Position pos = m_sel.start();
739         pos = VisiblePosition(m_sel.start(), m_sel.affinity()).deepEquivalent();
740         if (pos.isNotNull()) {
741             ASSERT(pos.node()->renderer());
742             m_caretRect = pos.node()->renderer()->caretRect(pos.offset(), m_sel.affinity());
743             
744             int x, y;
745             pos.node()->renderer()->absolutePositionForContent(x, y);
746             m_caretPositionOnLayout = IntPoint(x, y);
747         }
748     }
749
750     m_needsLayout = false;
751 }
752
753 IntRect SelectionController::caretRect() const
754 {
755     if (m_needsLayout)
756         const_cast<SelectionController *>(this)->layout();
757     
758     IntRect caret = m_caretRect;
759
760     if (m_sel.start().node() && m_sel.start().node()->renderer()) {
761         int x, y;
762         m_sel.start().node()->renderer()->absolutePositionForContent(x, y);
763         caret.move(IntPoint(x, y) - m_caretPositionOnLayout);
764     }
765
766     return caret;
767 }
768
769 IntRect SelectionController::caretRepaintRect() const
770 {
771     // FIXME: Add one pixel of slop on each side to make sure we don't leave behind artifacts.
772     IntRect r = caretRect();
773     if (r.isEmpty())
774         return IntRect();
775     return IntRect(r.x() - 1, r.y() - 1, r.width() + 2, r.height() + 2);
776 }
777
778 void SelectionController::needsCaretRepaint()
779 {
780     if (!isCaret())
781         return;
782
783     FrameView *v = m_sel.start().node()->document()->view();
784     if (!v)
785         return;
786
787     if (m_needsLayout) {
788         // repaint old position and calculate new position
789         v->updateContents(caretRepaintRect(), false);
790         layout();
791         
792         // EDIT FIXME: This is an unfortunate hack.
793         // Basically, we can't trust this layout position since we 
794         // can't guarantee that the check to see if we are in unrendered 
795         // content will work at this point. We may have to wait for
796         // a layout and re-render of the document to happen. So, resetting this
797         // flag will cause another caret layout to happen the first time
798         // that we try to paint the caret after this call. That one will work since
799         // it happens after the document has accounted for any editing
800         // changes which may have been done.
801         // And, we need to leave this layout here so the caret moves right 
802         // away after clicking.
803         m_needsLayout = true;
804     }
805     v->updateContents(caretRepaintRect(), false);
806 }
807
808 void SelectionController::paintCaret(GraphicsContext *p, const IntRect &rect)
809 {
810     if (! m_sel.isCaret())
811         return;
812
813     if (m_needsLayout)
814         layout();
815         
816     IntRect caret = intersection(caretRect(), rect);
817     if (!caret.isEmpty())
818         p->fillRect(caret, Color::black);
819 }
820
821 void SelectionController::debugRenderer(RenderObject *r, bool selected) const
822 {
823     if (r->node()->isElementNode()) {
824         Element *element = static_cast<Element *>(r->node());
825         fprintf(stderr, "%s%s\n", selected ? "==> " : "    ", element->localName().deprecatedString().latin1());
826     }
827     else if (r->isText()) {
828         RenderText *textRenderer = static_cast<RenderText *>(r);
829         if (textRenderer->stringLength() == 0 || !textRenderer->firstTextBox()) {
830             fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : "    ");
831             return;
832         }
833         
834         static const int max = 36;
835         DeprecatedString text = String(textRenderer->string()).deprecatedString();
836         int textLength = text.length();
837         if (selected) {
838             int offset = 0;
839             if (r->node() == m_sel.start().node())
840                 offset = m_sel.start().offset();
841             else if (r->node() == m_sel.end().node())
842                 offset = m_sel.end().offset();
843                 
844             int pos;
845             InlineTextBox *box = textRenderer->findNextInlineTextBox(offset, pos);
846             text = text.mid(box->m_start, box->m_len);
847             
848             DeprecatedString show;
849             int mid = max / 2;
850             int caret = 0;
851             
852             // text is shorter than max
853             if (textLength < max) {
854                 show = text;
855                 caret = pos;
856             }
857             
858             // too few characters to left
859             else if (pos - mid < 0) {
860                 show = text.left(max - 3) + "...";
861                 caret = pos;
862             }
863             
864             // enough characters on each side
865             else if (pos - mid >= 0 && pos + mid <= textLength) {
866                 show = "..." + text.mid(pos - mid + 3, max - 6) + "...";
867                 caret = mid;
868             }
869             
870             // too few characters on right
871             else {
872                 show = "..." + text.right(max - 3);
873                 caret = pos - (textLength - show.length());
874             }
875             
876             show.replace('\n', ' ');
877             show.replace('\r', ' ');
878             fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.latin1(), pos);
879             fprintf(stderr, "           ");
880             for (int i = 0; i < caret; i++)
881                 fprintf(stderr, " ");
882             fprintf(stderr, "^\n");
883         }
884         else {
885             if ((int)text.length() > max)
886                 text = text.left(max - 3) + "...";
887             else
888                 text = text.left(max);
889             fprintf(stderr, "    #text : \"%s\"\n", text.latin1());
890         }
891     }
892 }
893
894 #ifndef NDEBUG
895
896 void SelectionController::formatForDebugger(char* buffer, unsigned length) const
897 {
898     m_sel.formatForDebugger(buffer, length);
899 }
900
901 void SelectionController::showTreeForThis() const
902 {
903     m_sel.showTreeForThis();
904 }
905
906 #endif
907
908 }
909
910 #ifndef NDEBUG
911
912 void showTree(const WebCore::SelectionController& sel)
913 {
914     sel.showTreeForThis();
915 }
916
917 void showTree(const WebCore::SelectionController* sel)
918 {
919     if (sel)
920         sel->showTreeForThis();
921 }
922
923 #endif