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