• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2004, 2008 Apple 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 "CString.h"
30 #include "DeleteSelectionCommand.h"
31 #include "Document.h"
32 #include "Editor.h"
33 #include "Element.h"
34 #include "EventHandler.h"
35 #include "ExceptionCode.h"
36 #include "FocusController.h"
37 #include "FloatQuad.h"
38 #include "Frame.h"
39 #include "FrameTree.h"
40 #include "FrameView.h"
41 #include "GraphicsContext.h"
42 #include "HTMLInputElement.h"
43 #include "HTMLNames.h"
44 #include "HitTestRequest.h"
45 #include "HitTestResult.h"
46 #include "Page.h"
47 #include "Range.h"
48 #include "RenderTheme.h"
49 #include "RenderView.h"
50 #include "TextIterator.h"
51 #include "TypingCommand.h"
52 #include "htmlediting.h"
53 #include "visible_units.h"
54 #include <stdio.h>
55 
56 #define EDIT_DEBUG 0
57 
58 namespace WebCore {
59 
60 using namespace HTMLNames;
61 
62 const int NoXPosForVerticalArrowNavigation = INT_MIN;
63 
SelectionController(Frame * frame,bool isDragCaretController)64 SelectionController::SelectionController(Frame* frame, bool isDragCaretController)
65     : m_frame(frame)
66     , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation)
67     , m_needsLayout(true)
68     , m_absCaretBoundsDirty(true)
69     , m_lastChangeWasHorizontalExtension(false)
70     , m_isDragCaretController(isDragCaretController)
71     , m_isCaretBlinkingSuspended(false)
72     , m_focused(frame && frame->page() && frame->page()->focusController()->focusedFrame() == frame)
73 {
74 }
75 
moveTo(const VisiblePosition & pos,bool userTriggered)76 void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered)
77 {
78     setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
79 }
80 
moveTo(const VisiblePosition & base,const VisiblePosition & extent,bool userTriggered)81 void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered)
82 {
83     setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), true, true, userTriggered);
84 }
85 
moveTo(const Position & pos,EAffinity affinity,bool userTriggered)86 void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered)
87 {
88     setSelection(VisibleSelection(pos, affinity), true, true, userTriggered);
89 }
90 
moveTo(const Range * r,EAffinity affinity,bool userTriggered)91 void SelectionController::moveTo(const Range *r, EAffinity affinity, bool userTriggered)
92 {
93     setSelection(VisibleSelection(startPosition(r), endPosition(r), affinity), true, true, userTriggered);
94 }
95 
moveTo(const Position & base,const Position & extent,EAffinity affinity,bool userTriggered)96 void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered)
97 {
98     setSelection(VisibleSelection(base, extent, affinity), true, true, userTriggered);
99 }
100 
setSelection(const VisibleSelection & s,bool closeTyping,bool clearTypingStyle,bool userTriggered)101 void SelectionController::setSelection(const VisibleSelection& s, bool closeTyping, bool clearTypingStyle, bool userTriggered)
102 {
103     m_lastChangeWasHorizontalExtension = false;
104 
105     if (m_isDragCaretController) {
106         invalidateCaretRect();
107         m_sel = s;
108         m_needsLayout = true;
109         invalidateCaretRect();
110         return;
111     }
112     if (!m_frame) {
113         m_sel = s;
114         return;
115     }
116 
117     Node* baseNode = s.base().node();
118     Document* document = 0;
119     if (baseNode)
120         document = baseNode->document();
121 
122     // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at SelectionController::setSelection
123     // if document->frame() == m_frame we can get into an infinite loop
124     if (document && document->frame() != m_frame && document != m_frame->document()) {
125         document->frame()->selection()->setSelection(s, closeTyping, clearTypingStyle, userTriggered);
126         return;
127     }
128 
129     if (closeTyping)
130         TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());
131 
132     if (clearTypingStyle)
133         m_frame->clearTypingStyle();
134 
135     if (m_sel == s)
136         return;
137 
138     VisibleSelection oldSelection = m_sel;
139 
140     m_sel = s;
141 
142     m_needsLayout = true;
143 
144     if (!s.isNone())
145         m_frame->setFocusedNodeIfNeeded();
146 
147     m_frame->selectionLayoutChanged();
148     // Always clear the x position used for vertical arrow navigation.
149     // It will be restored by the vertical arrow navigation code if necessary.
150     m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
151     selectFrameElementInParentIfFullySelected();
152     m_frame->notifyRendererOfSelectionChange(userTriggered);
153     m_frame->respondToChangedSelection(oldSelection, closeTyping);
154     if (userTriggered)
155         m_frame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded, true);
156 
157     notifyAccessibilityForSelectionChange();
158 }
159 
removingNodeRemovesPosition(Node * node,const Position & position)160 static bool removingNodeRemovesPosition(Node* node, const Position& position)
161 {
162     if (!position.node())
163         return false;
164 
165     if (position.node() == node)
166         return true;
167 
168     if (!node->isElementNode())
169         return false;
170 
171     Element* element = static_cast<Element*>(node);
172     return element->contains(position.node()) || element->contains(position.node()->shadowAncestorNode());
173 }
174 
nodeWillBeRemoved(Node * node)175 void SelectionController::nodeWillBeRemoved(Node *node)
176 {
177     if (isNone())
178         return;
179 
180     // There can't be a selection inside a fragment, so if a fragment's node is being removed,
181     // the selection in the document that created the fragment needs no adjustment.
182     if (node && highestAncestor(node)->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
183         return;
184 
185     bool baseRemoved = removingNodeRemovesPosition(node, m_sel.base());
186     bool extentRemoved = removingNodeRemovesPosition(node, m_sel.extent());
187     bool startRemoved = removingNodeRemovesPosition(node, m_sel.start());
188     bool endRemoved = removingNodeRemovesPosition(node, m_sel.end());
189 
190     bool clearRenderTreeSelection = false;
191     bool clearDOMTreeSelection = false;
192 
193     if (startRemoved || endRemoved) {
194         // FIXME: When endpoints are removed, we should just alter the selection, instead of blowing it away.
195         clearRenderTreeSelection = true;
196         clearDOMTreeSelection = true;
197     } else if (baseRemoved || extentRemoved) {
198         // The base and/or extent are about to be removed, but the start and end aren't.
199         // Change the base and extent to the start and end, but don't re-validate the
200         // selection, since doing so could move the start and end into the node
201         // that is about to be removed.
202         if (m_sel.isBaseFirst())
203             m_sel.setWithoutValidation(m_sel.start(), m_sel.end());
204         else
205             m_sel.setWithoutValidation(m_sel.end(), m_sel.start());
206     // FIXME: This could be more efficient if we had an isNodeInRange function on Ranges.
207     } else if (comparePositions(m_sel.start(), Position(node, 0)) == -1 && comparePositions(m_sel.end(), Position(node, 0)) == 1) {
208         // If we did nothing here, when this node's renderer was destroyed, the rect that it
209         // occupied would be invalidated, but, selection gaps that change as a result of
210         // the removal wouldn't be invalidated.
211         // FIXME: Don't do so much unnecessary invalidation.
212         clearRenderTreeSelection = true;
213     }
214 
215     if (clearRenderTreeSelection) {
216         RefPtr<Document> document = m_sel.start().node()->document();
217         document->updateStyleIfNeeded();
218         if (RenderView* view = toRenderView(document->renderer()))
219             view->clearSelection();
220     }
221 
222     if (clearDOMTreeSelection)
223         setSelection(VisibleSelection(), false, false);
224 }
225 
willBeModified(EAlteration alter,EDirection direction)226 void SelectionController::willBeModified(EAlteration alter, EDirection direction)
227 {
228     if (alter != EXTEND)
229         return;
230     if (m_lastChangeWasHorizontalExtension)
231         return;
232 
233     Position start = m_sel.start();
234     Position end = m_sel.end();
235     // FIXME: This is probably not correct for right and left when the direction is RTL.
236     switch (direction) {
237         case RIGHT:
238         case FORWARD:
239             m_sel.setBase(start);
240             m_sel.setExtent(end);
241             break;
242         case LEFT:
243         case BACKWARD:
244             m_sel.setBase(end);
245             m_sel.setExtent(start);
246             break;
247     }
248 }
249 
directionOfEnclosingBlock()250 TextDirection SelectionController::directionOfEnclosingBlock()
251 {
252     Node* n = m_sel.extent().node();
253     Node* enclosingBlockNode = enclosingBlock(n);
254     if (!enclosingBlockNode)
255         return LTR;
256     RenderObject* renderer = enclosingBlockNode->renderer();
257     if (renderer)
258         return renderer->style()->direction();
259     return LTR;
260 }
261 
modifyExtendingRight(TextGranularity granularity)262 VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granularity)
263 {
264     VisiblePosition pos(m_sel.extent(), m_sel.affinity());
265 
266     // The difference between modifyExtendingRight and modifyExtendingForward is:
267     // modifyExtendingForward always extends forward logically.
268     // modifyExtendingRight behaves the same as modifyExtendingForward except for extending character or word,
269     // it extends forward logically if the enclosing block is LTR direction,
270     // but it extends backward logically if the enclosing block is RTL direction.
271     switch (granularity) {
272         case CharacterGranularity:
273             if (directionOfEnclosingBlock() == LTR)
274                 pos = pos.next(true);
275             else
276                 pos = pos.previous(true);
277             break;
278         case WordGranularity:
279             if (directionOfEnclosingBlock() == LTR)
280                 pos = nextWordPosition(pos);
281             else
282                 pos = previousWordPosition(pos);
283             break;
284         case SentenceGranularity:
285         case LineGranularity:
286         case ParagraphGranularity:
287         case SentenceBoundary:
288         case LineBoundary:
289         case ParagraphBoundary:
290         case DocumentBoundary:
291             // FIXME: implement all of the above?
292             pos = modifyExtendingForward(granularity);
293     }
294     return pos;
295 }
296 
modifyExtendingForward(TextGranularity granularity)297 VisiblePosition SelectionController::modifyExtendingForward(TextGranularity granularity)
298 {
299     VisiblePosition pos(m_sel.extent(), m_sel.affinity());
300     switch (granularity) {
301         case CharacterGranularity:
302             pos = pos.next(true);
303             break;
304         case WordGranularity:
305             pos = nextWordPosition(pos);
306             break;
307         case SentenceGranularity:
308             pos = nextSentencePosition(pos);
309             break;
310         case LineGranularity:
311             pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
312             break;
313         case ParagraphGranularity:
314             pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
315             break;
316         case SentenceBoundary:
317             pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
318             break;
319         case LineBoundary:
320             pos = logicalEndOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
321             break;
322         case ParagraphBoundary:
323             pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
324             break;
325         case DocumentBoundary:
326             pos = VisiblePosition(m_sel.end(), m_sel.affinity());
327             if (isEditablePosition(pos.deepEquivalent()))
328                 pos = endOfEditableContent(pos);
329             else
330                 pos = endOfDocument(pos);
331             break;
332     }
333 
334     return pos;
335 }
336 
modifyMovingRight(TextGranularity granularity)337 VisiblePosition SelectionController::modifyMovingRight(TextGranularity granularity)
338 {
339     VisiblePosition pos;
340     switch (granularity) {
341         case CharacterGranularity:
342             if (isRange())
343                 pos = VisiblePosition(m_sel.end(), m_sel.affinity());
344             else
345                 pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).right(true);
346             break;
347         case WordGranularity:
348         case SentenceGranularity:
349         case LineGranularity:
350         case ParagraphGranularity:
351         case SentenceBoundary:
352         case LineBoundary:
353         case ParagraphBoundary:
354         case DocumentBoundary:
355             // FIXME: Implement all of the above.
356             pos = modifyMovingForward(granularity);
357             break;
358     }
359     return pos;
360 }
361 
modifyMovingForward(TextGranularity granularity)362 VisiblePosition SelectionController::modifyMovingForward(TextGranularity granularity)
363 {
364     VisiblePosition pos;
365     // FIXME: Stay in editable content for the less common granularities.
366     switch (granularity) {
367         case CharacterGranularity:
368             if (isRange())
369                 pos = VisiblePosition(m_sel.end(), m_sel.affinity());
370             else
371                 pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).next(true);
372             break;
373         case WordGranularity:
374             pos = nextWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
375             break;
376         case SentenceGranularity:
377             pos = nextSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
378             break;
379         case LineGranularity: {
380             // down-arrowing from a range selection that ends at the start of a line needs
381             // to leave the selection at that line start (no need to call nextLinePosition!)
382             pos = VisiblePosition(m_sel.end(), m_sel.affinity());
383             if (!isRange() || !isStartOfLine(pos))
384                 pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(START));
385             break;
386         }
387         case ParagraphGranularity:
388             pos = nextParagraphPosition(VisiblePosition(m_sel.end(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
389             break;
390         case SentenceBoundary:
391             pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
392             break;
393         case LineBoundary:
394             pos = logicalEndOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
395             break;
396         case ParagraphBoundary:
397             pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
398             break;
399         case DocumentBoundary:
400             pos = VisiblePosition(m_sel.end(), m_sel.affinity());
401             if (isEditablePosition(pos.deepEquivalent()))
402                 pos = endOfEditableContent(pos);
403             else
404                 pos = endOfDocument(pos);
405             break;
406 
407     }
408     return pos;
409 }
410 
modifyExtendingLeft(TextGranularity granularity)411 VisiblePosition SelectionController::modifyExtendingLeft(TextGranularity granularity)
412 {
413     VisiblePosition pos(m_sel.extent(), m_sel.affinity());
414 
415     // The difference between modifyExtendingLeft and modifyExtendingBackward is:
416     // modifyExtendingBackward always extends backward logically.
417     // modifyExtendingLeft behaves the same as modifyExtendingBackward except for extending character or word,
418     // it extends backward logically if the enclosing block is LTR direction,
419     // but it extends forward logically if the enclosing block is RTL direction.
420     switch (granularity) {
421         case CharacterGranularity:
422             if (directionOfEnclosingBlock() == LTR)
423                 pos = pos.previous(true);
424             else
425                 pos = pos.next(true);
426             break;
427         case WordGranularity:
428             if (directionOfEnclosingBlock() == LTR)
429                 pos = previousWordPosition(pos);
430             else
431                 pos = nextWordPosition(pos);
432             break;
433         case SentenceGranularity:
434         case LineGranularity:
435         case ParagraphGranularity:
436         case SentenceBoundary:
437         case LineBoundary:
438         case ParagraphBoundary:
439         case DocumentBoundary:
440             pos = modifyExtendingBackward(granularity);
441     }
442     return pos;
443 }
444 
modifyExtendingBackward(TextGranularity granularity)445 VisiblePosition SelectionController::modifyExtendingBackward(TextGranularity granularity)
446 {
447     VisiblePosition pos(m_sel.extent(), m_sel.affinity());
448 
449     // Extending a selection backward by word or character from just after a table selects
450     // the table.  This "makes sense" from the user perspective, esp. when deleting.
451     // It was done here instead of in VisiblePosition because we want VPs to iterate
452     // over everything.
453     switch (granularity) {
454         case CharacterGranularity:
455             pos = pos.previous(true);
456             break;
457         case WordGranularity:
458             pos = previousWordPosition(pos);
459             break;
460         case SentenceGranularity:
461             pos = previousSentencePosition(pos);
462             break;
463         case LineGranularity:
464             pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
465             break;
466         case ParagraphGranularity:
467             pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
468             break;
469         case SentenceBoundary:
470             pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
471             break;
472         case LineBoundary:
473             pos = logicalStartOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
474             break;
475         case ParagraphBoundary:
476             pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
477             break;
478         case DocumentBoundary:
479             pos = VisiblePosition(m_sel.start(), m_sel.affinity());
480             if (isEditablePosition(pos.deepEquivalent()))
481                 pos = startOfEditableContent(pos);
482             else
483                 pos = startOfDocument(pos);
484             break;
485     }
486     return pos;
487 }
488 
modifyMovingLeft(TextGranularity granularity)489 VisiblePosition SelectionController::modifyMovingLeft(TextGranularity granularity)
490 {
491     VisiblePosition pos;
492     switch (granularity) {
493         case CharacterGranularity:
494             if (isRange())
495                 pos = VisiblePosition(m_sel.start(), m_sel.affinity());
496             else
497                 pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).left(true);
498             break;
499         case WordGranularity:
500         case SentenceGranularity:
501         case LineGranularity:
502         case ParagraphGranularity:
503         case SentenceBoundary:
504         case LineBoundary:
505         case ParagraphBoundary:
506         case DocumentBoundary:
507             // FIXME: Implement all of the above.
508             pos = modifyMovingBackward(granularity);
509             break;
510     }
511     return pos;
512 }
513 
modifyMovingBackward(TextGranularity granularity)514 VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granularity)
515 {
516     VisiblePosition pos;
517     switch (granularity) {
518         case CharacterGranularity:
519             if (isRange())
520                 pos = VisiblePosition(m_sel.start(), m_sel.affinity());
521             else
522                 pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).previous(true);
523             break;
524         case WordGranularity:
525             pos = previousWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
526             break;
527         case SentenceGranularity:
528             pos = previousSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
529             break;
530         case LineGranularity:
531             pos = previousLinePosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
532             break;
533         case ParagraphGranularity:
534             pos = previousParagraphPosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
535             break;
536         case SentenceBoundary:
537             pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
538             break;
539         case LineBoundary:
540             pos = logicalStartOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
541             break;
542         case ParagraphBoundary:
543             pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
544             break;
545         case DocumentBoundary:
546             pos = VisiblePosition(m_sel.start(), m_sel.affinity());
547             if (isEditablePosition(pos.deepEquivalent()))
548                 pos = startOfEditableContent(pos);
549             else
550                 pos = startOfDocument(pos);
551             break;
552     }
553     return pos;
554 }
555 
modify(EAlteration alter,EDirection dir,TextGranularity granularity,bool userTriggered)556 bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranularity granularity, bool userTriggered)
557 {
558     if (userTriggered) {
559         SelectionController trialSelectionController;
560         trialSelectionController.setSelection(m_sel);
561         trialSelectionController.setLastChangeWasHorizontalExtension(m_lastChangeWasHorizontalExtension);
562         trialSelectionController.modify(alter, dir, granularity, false);
563 
564         bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
565         if (!change)
566             return false;
567     }
568 
569     if (m_frame)
570         m_frame->setSelectionGranularity(granularity);
571 
572     willBeModified(alter, dir);
573 
574     VisiblePosition pos;
575     switch (dir) {
576         case RIGHT:
577             if (alter == MOVE)
578                 pos = modifyMovingRight(granularity);
579             else
580                 pos = modifyExtendingRight(granularity);
581             break;
582         case FORWARD:
583             if (alter == EXTEND)
584                 pos = modifyExtendingForward(granularity);
585             else
586                 pos = modifyMovingForward(granularity);
587             break;
588         case LEFT:
589             if (alter == MOVE)
590                 pos = modifyMovingLeft(granularity);
591             else
592                 pos = modifyExtendingLeft(granularity);
593             break;
594         case BACKWARD:
595             if (alter == EXTEND)
596                 pos = modifyExtendingBackward(granularity);
597             else
598                 pos = modifyMovingBackward(granularity);
599             break;
600     }
601 
602     if (pos.isNull())
603         return false;
604 
605     // Some of the above operations set an xPosForVerticalArrowNavigation.
606     // Setting a selection will clear it, so save it to possibly restore later.
607     // Note: the START position type is arbitrary because it is unused, it would be
608     // the requested position type if there were no xPosForVerticalArrowNavigation set.
609     int x = xPosForVerticalArrowNavigation(START);
610 
611     switch (alter) {
612         case MOVE:
613             moveTo(pos, userTriggered);
614             break;
615         case EXTEND:
616             setExtent(pos, userTriggered);
617             break;
618     }
619 
620     if (granularity == LineGranularity || granularity == ParagraphGranularity)
621         m_xPosForVerticalArrowNavigation = x;
622 
623     if (userTriggered) {
624         // User modified selection change also sets the granularity back to character.
625         // NOTE: The one exception is that we need to keep word granularity to
626         // preserve smart delete behavior when extending by word (e.g. double-click),
627         // then shift-option-right arrow, then delete needs to smart delete, per TextEdit.
628         if (!(alter == EXTEND && granularity == WordGranularity && m_frame->selectionGranularity() == WordGranularity))
629             m_frame->setSelectionGranularity(CharacterGranularity);
630     }
631 
632     setNeedsLayout();
633 
634     m_lastChangeWasHorizontalExtension = alter == EXTEND;
635 
636     return true;
637 }
638 
639 // FIXME: Maybe baseline would be better?
absoluteCaretY(const VisiblePosition & c,int & y)640 static bool absoluteCaretY(const VisiblePosition &c, int &y)
641 {
642     IntRect rect = c.absoluteCaretBounds();
643     if (rect.isEmpty())
644         return false;
645     y = rect.y() + rect.height() / 2;
646     return true;
647 }
648 
modify(EAlteration alter,int verticalDistance,bool userTriggered)649 bool SelectionController::modify(EAlteration alter, int verticalDistance, bool userTriggered)
650 {
651     if (verticalDistance == 0)
652         return false;
653 
654     if (userTriggered) {
655         SelectionController trialSelectionController;
656         trialSelectionController.setSelection(m_sel);
657         trialSelectionController.setLastChangeWasHorizontalExtension(m_lastChangeWasHorizontalExtension);
658         trialSelectionController.modify(alter, verticalDistance, false);
659 
660         bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
661         if (!change)
662             return false;
663     }
664 
665     bool up = verticalDistance < 0;
666     if (up)
667         verticalDistance = -verticalDistance;
668 
669     willBeModified(alter, up ? BACKWARD : FORWARD);
670 
671     VisiblePosition pos;
672     int xPos = 0;
673     switch (alter) {
674         case MOVE:
675             pos = VisiblePosition(up ? m_sel.start() : m_sel.end(), m_sel.affinity());
676             xPos = xPosForVerticalArrowNavigation(up ? START : END);
677             m_sel.setAffinity(up ? UPSTREAM : DOWNSTREAM);
678             break;
679         case EXTEND:
680             pos = VisiblePosition(m_sel.extent(), m_sel.affinity());
681             xPos = xPosForVerticalArrowNavigation(EXTENT);
682             m_sel.setAffinity(DOWNSTREAM);
683             break;
684     }
685 
686     int startY;
687     if (!absoluteCaretY(pos, startY))
688         return false;
689     if (up)
690         startY = -startY;
691     int lastY = startY;
692 
693     VisiblePosition result;
694     VisiblePosition next;
695     for (VisiblePosition p = pos; ; p = next) {
696         next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
697         if (next.isNull() || next == p)
698             break;
699         int nextY;
700         if (!absoluteCaretY(next, nextY))
701             break;
702         if (up)
703             nextY = -nextY;
704         if (nextY - startY > verticalDistance)
705             break;
706         if (nextY >= lastY) {
707             lastY = nextY;
708             result = next;
709         }
710     }
711 
712     if (result.isNull())
713         return false;
714 
715     switch (alter) {
716         case MOVE:
717             moveTo(result, userTriggered);
718             break;
719         case EXTEND:
720             setExtent(result, userTriggered);
721             break;
722     }
723 
724     if (userTriggered)
725         m_frame->setSelectionGranularity(CharacterGranularity);
726 
727     return true;
728 }
729 
expandUsingGranularity(TextGranularity granularity)730 bool SelectionController::expandUsingGranularity(TextGranularity granularity)
731 {
732     if (isNone())
733         return false;
734 
735     m_sel.expandUsingGranularity(granularity);
736     m_needsLayout = true;
737     return true;
738 }
739 
xPosForVerticalArrowNavigation(EPositionType type)740 int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
741 {
742     int x = 0;
743 
744     if (isNone())
745         return x;
746 
747     Position pos;
748     switch (type) {
749         case START:
750             pos = m_sel.start();
751             break;
752         case END:
753             pos = m_sel.end();
754             break;
755         case BASE:
756             pos = m_sel.base();
757             break;
758         case EXTENT:
759             pos = m_sel.extent();
760             break;
761     }
762 
763     Frame *frame = pos.node()->document()->frame();
764     if (!frame)
765         return x;
766 
767     if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation) {
768         VisiblePosition visiblePosition(pos, m_sel.affinity());
769         // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
770         // after the selection is created and before this function is called.
771         x = visiblePosition.isNotNull() ? visiblePosition.xOffsetForVerticalNavigation() : 0;
772         m_xPosForVerticalArrowNavigation = x;
773     }
774     else
775         x = m_xPosForVerticalArrowNavigation;
776 
777     return x;
778 }
779 
clear()780 void SelectionController::clear()
781 {
782     setSelection(VisibleSelection());
783 }
784 
setBase(const VisiblePosition & pos,bool userTriggered)785 void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
786 {
787     setSelection(VisibleSelection(pos.deepEquivalent(), m_sel.extent(), pos.affinity()), true, true, userTriggered);
788 }
789 
setExtent(const VisiblePosition & pos,bool userTriggered)790 void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered)
791 {
792     setSelection(VisibleSelection(m_sel.base(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
793 }
794 
setBase(const Position & pos,EAffinity affinity,bool userTriggered)795 void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered)
796 {
797     setSelection(VisibleSelection(pos, m_sel.extent(), affinity), true, true, userTriggered);
798 }
799 
setExtent(const Position & pos,EAffinity affinity,bool userTriggered)800 void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered)
801 {
802     setSelection(VisibleSelection(m_sel.base(), pos, affinity), true, true, userTriggered);
803 }
804 
setNeedsLayout(bool flag)805 void SelectionController::setNeedsLayout(bool flag)
806 {
807     m_needsLayout = flag;
808 }
809 
layout()810 void SelectionController::layout()
811 {
812     if (isNone() || !m_sel.start().node()->inDocument() || !m_sel.end().node()->inDocument()) {
813         m_caretRect = IntRect();
814         return;
815     }
816 
817     m_sel.start().node()->document()->updateStyleIfNeeded();
818 
819     m_caretRect = IntRect();
820 
821     if (isCaret()) {
822         VisiblePosition pos(m_sel.start(), m_sel.affinity());
823         if (pos.isNotNull()) {
824             ASSERT(pos.deepEquivalent().node()->renderer());
825 
826             // First compute a rect local to the renderer at the selection start
827             RenderObject* renderer;
828             IntRect localRect = pos.localCaretRect(renderer);
829 
830             // Get the renderer that will be responsible for painting the caret (which
831             // is either the renderer we just found, or one of its containers)
832             RenderObject* caretPainter = caretRenderer();
833 
834             // Compute an offset between the renderer and the caretPainter
835             IntSize offsetFromPainter;
836             bool unrooted = false;
837             while (renderer != caretPainter) {
838                 RenderObject* containerObject = renderer->container();
839                 if (!containerObject) {
840                     unrooted = true;
841                     break;
842                 }
843                 offsetFromPainter += renderer->offsetFromContainer(containerObject);
844                 renderer = containerObject;
845             }
846 
847             if (!unrooted) {
848                 // Move the caret rect to the coords of the painter
849                 localRect.move(offsetFromPainter);
850                 m_caretRect = localRect;
851             }
852 
853             m_absCaretBoundsDirty = true;
854         }
855     }
856 
857     m_needsLayout = false;
858 }
859 
caretRenderer() const860 RenderObject* SelectionController::caretRenderer() const
861 {
862     Node* node = m_sel.start().node();
863     if (!node)
864         return 0;
865 
866     RenderObject* renderer = node->renderer();
867     if (!renderer)
868         return 0;
869 
870     // if caretNode is a block and caret is inside it then caret should be painted by that block
871     bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(node);
872     return paintedByBlock ? renderer : renderer->containingBlock();
873 }
874 
localCaretRect() const875 IntRect SelectionController::localCaretRect() const
876 {
877     if (m_needsLayout)
878         const_cast<SelectionController*>(this)->layout();
879 
880     return m_caretRect;
881 }
882 
absoluteBoundsForLocalRect(const IntRect & rect) const883 IntRect SelectionController::absoluteBoundsForLocalRect(const IntRect& rect) const
884 {
885     RenderObject* caretPainter = caretRenderer();
886     if (!caretPainter)
887         return IntRect();
888 
889     return caretPainter->localToAbsoluteQuad(FloatRect(rect)).enclosingBoundingBox();
890 }
891 
absoluteCaretBounds()892 IntRect SelectionController::absoluteCaretBounds()
893 {
894     recomputeCaretRect();
895     return m_absCaretBounds;
896 }
897 
repaintRectForCaret(IntRect caret)898 static IntRect repaintRectForCaret(IntRect caret)
899 {
900     if (caret.isEmpty())
901         return IntRect();
902     // Ensure that the dirty rect intersects the block that paints the caret even in the case where
903     // the caret itself is just outside the block. See <https://bugs.webkit.org/show_bug.cgi?id=19086>.
904     caret.inflateX(1);
905     return caret;
906 }
907 
caretRepaintRect() const908 IntRect SelectionController::caretRepaintRect() const
909 {
910     return absoluteBoundsForLocalRect(repaintRectForCaret(localCaretRect()));
911 }
912 
recomputeCaretRect()913 bool SelectionController::recomputeCaretRect()
914 {
915     if (!m_frame)
916         return false;
917 
918     FrameView* v = m_frame->document()->view();
919     if (!v)
920         return false;
921 
922     if (!m_needsLayout)
923         return false;
924 
925     IntRect oldRect = m_caretRect;
926     IntRect newRect = localCaretRect();
927     if (oldRect == newRect && !m_absCaretBoundsDirty)
928         return false;
929 
930     IntRect oldAbsCaretBounds = m_absCaretBounds;
931     // FIXME: Rename m_caretRect to m_localCaretRect.
932     m_absCaretBounds = absoluteBoundsForLocalRect(m_caretRect);
933     m_absCaretBoundsDirty = false;
934 
935     if (oldAbsCaretBounds == m_absCaretBounds)
936         return false;
937 
938     IntRect oldAbsoluteCaretRepaintBounds = m_absoluteCaretRepaintBounds;
939     // We believe that we need to inflate the local rect before transforming it to obtain the repaint bounds.
940     m_absoluteCaretRepaintBounds = caretRepaintRect();
941 
942     if (RenderView* view = toRenderView(m_frame->document()->renderer())) {
943         // FIXME: make caret repainting container-aware.
944         view->repaintRectangleInViewAndCompositedLayers(oldAbsoluteCaretRepaintBounds, false);
945         view->repaintRectangleInViewAndCompositedLayers(m_absoluteCaretRepaintBounds, false);
946     }
947 
948     return true;
949 }
950 
invalidateCaretRect()951 void SelectionController::invalidateCaretRect()
952 {
953     if (!isCaret())
954         return;
955 
956     Document* d = m_sel.start().node()->document();
957 
958     // recomputeCaretRect will always return false for the drag caret,
959     // because its m_frame is always 0.
960     bool caretRectChanged = recomputeCaretRect();
961 
962     // EDIT FIXME: This is an unfortunate hack.
963     // Basically, we can't trust this layout position since we
964     // can't guarantee that the check to see if we are in unrendered
965     // content will work at this point. We may have to wait for
966     // a layout and re-render of the document to happen. So, resetting this
967     // flag will cause another caret layout to happen the first time
968     // that we try to paint the caret after this call. That one will work since
969     // it happens after the document has accounted for any editing
970     // changes which may have been done.
971     // And, we need to leave this layout here so the caret moves right
972     // away after clicking.
973     m_needsLayout = true;
974 
975     if (!caretRectChanged) {
976         if (RenderView* view = toRenderView(d->renderer()))
977             view->repaintRectangleInViewAndCompositedLayers(caretRepaintRect(), false);
978     }
979 }
980 
paintCaret(GraphicsContext * p,int tx,int ty,const IntRect & clipRect)981 void SelectionController::paintCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect)
982 {
983     if (! m_sel.isCaret())
984         return;
985 
986     if (m_needsLayout)
987         layout();
988 
989     IntRect drawingRect = localCaretRect();
990     drawingRect.move(tx, ty);
991     IntRect caret = intersection(drawingRect, clipRect);
992     if (!caret.isEmpty()) {
993         Color caretColor = Color::black;
994         Element* element = rootEditableElement();
995         if (element && element->renderer())
996             caretColor = element->renderer()->style()->color();
997 
998         p->fillRect(caret, caretColor);
999     }
1000 }
1001 
debugRenderer(RenderObject * r,bool selected) const1002 void SelectionController::debugRenderer(RenderObject *r, bool selected) const
1003 {
1004     if (r->node()->isElementNode()) {
1005         Element *element = static_cast<Element *>(r->node());
1006         fprintf(stderr, "%s%s\n", selected ? "==> " : "    ", element->localName().string().utf8().data());
1007     }
1008     else if (r->isText()) {
1009         RenderText* textRenderer = toRenderText(r);
1010         if (textRenderer->textLength() == 0 || !textRenderer->firstTextBox()) {
1011             fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : "    ");
1012             return;
1013         }
1014 
1015         static const int max = 36;
1016         String text = textRenderer->text();
1017         int textLength = text.length();
1018         if (selected) {
1019             int offset = 0;
1020             if (r->node() == m_sel.start().node())
1021                 offset = m_sel.start().deprecatedEditingOffset();
1022             else if (r->node() == m_sel.end().node())
1023                 offset = m_sel.end().deprecatedEditingOffset();
1024 
1025             int pos;
1026             InlineTextBox *box = textRenderer->findNextInlineTextBox(offset, pos);
1027             text = text.substring(box->start(), box->len());
1028 
1029             String show;
1030             int mid = max / 2;
1031             int caret = 0;
1032 
1033             // text is shorter than max
1034             if (textLength < max) {
1035                 show = text;
1036                 caret = pos;
1037             }
1038 
1039             // too few characters to left
1040             else if (pos - mid < 0) {
1041                 show = text.left(max - 3) + "...";
1042                 caret = pos;
1043             }
1044 
1045             // enough characters on each side
1046             else if (pos - mid >= 0 && pos + mid <= textLength) {
1047                 show = "..." + text.substring(pos - mid + 3, max - 6) + "...";
1048                 caret = mid;
1049             }
1050 
1051             // too few characters on right
1052             else {
1053                 show = "..." + text.right(max - 3);
1054                 caret = pos - (textLength - show.length());
1055             }
1056 
1057             show.replace('\n', ' ');
1058             show.replace('\r', ' ');
1059             fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.utf8().data(), pos);
1060             fprintf(stderr, "           ");
1061             for (int i = 0; i < caret; i++)
1062                 fprintf(stderr, " ");
1063             fprintf(stderr, "^\n");
1064         }
1065         else {
1066             if ((int)text.length() > max)
1067                 text = text.left(max - 3) + "...";
1068             else
1069                 text = text.left(max);
1070             fprintf(stderr, "    #text : \"%s\"\n", text.utf8().data());
1071         }
1072     }
1073 }
1074 
contains(const IntPoint & point)1075 bool SelectionController::contains(const IntPoint& point)
1076 {
1077     Document* document = m_frame->document();
1078 
1079     // Treat a collapsed selection like no selection.
1080     if (!isRange())
1081         return false;
1082     if (!document->renderer())
1083         return false;
1084 
1085     HitTestRequest request(HitTestRequest::ReadOnly |
1086                            HitTestRequest::Active);
1087     HitTestResult result(point);
1088     document->renderView()->layer()->hitTest(request, result);
1089     Node* innerNode = result.innerNode();
1090     if (!innerNode || !innerNode->renderer())
1091         return false;
1092 
1093     VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint()));
1094     if (visiblePos.isNull())
1095         return false;
1096 
1097     if (m_sel.visibleStart().isNull() || m_sel.visibleEnd().isNull())
1098         return false;
1099 
1100     Position start(m_sel.visibleStart().deepEquivalent());
1101     Position end(m_sel.visibleEnd().deepEquivalent());
1102     Position p(visiblePos.deepEquivalent());
1103 
1104     return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;
1105 }
1106 
1107 // Workaround for the fact that it's hard to delete a frame.
1108 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
1109 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
1110 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
1111 // mouse or the keyboard after setting the selection.
selectFrameElementInParentIfFullySelected()1112 void SelectionController::selectFrameElementInParentIfFullySelected()
1113 {
1114     // Find the parent frame; if there is none, then we have nothing to do.
1115     Frame* parent = m_frame->tree()->parent();
1116     if (!parent)
1117         return;
1118     Page* page = m_frame->page();
1119     if (!page)
1120         return;
1121 
1122     // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
1123     if (!isRange())
1124         return;
1125     if (!isStartOfDocument(selection().visibleStart()))
1126         return;
1127     if (!isEndOfDocument(selection().visibleEnd()))
1128         return;
1129 
1130     // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
1131     Document* doc = m_frame->document();
1132     Element* ownerElement = doc->ownerElement();
1133     if (!ownerElement)
1134         return;
1135     Node* ownerElementParent = ownerElement->parentNode();
1136     if (!ownerElementParent)
1137         return;
1138 
1139     // 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.
1140     if (!ownerElementParent->isContentEditable())
1141         return;
1142 
1143     // Create compute positions before and after the element.
1144     unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
1145     VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
1146     VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
1147 
1148     // Focus on the parent frame, and then select from before this element to after.
1149     VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
1150     if (parent->shouldChangeSelection(newSelection)) {
1151         page->focusController()->setFocusedFrame(parent);
1152         parent->selection()->setSelection(newSelection);
1153     }
1154 }
1155 
selectAll()1156 void SelectionController::selectAll()
1157 {
1158     Document* document = m_frame->document();
1159 
1160     if (document->focusedNode() && document->focusedNode()->canSelectAll()) {
1161         document->focusedNode()->selectAll();
1162         return;
1163     }
1164 
1165     Node* root = 0;
1166     if (isContentEditable())
1167         root = highestEditableRoot(m_sel.start());
1168     else {
1169         root = shadowTreeRootNode();
1170         if (!root)
1171             root = document->documentElement();
1172     }
1173     if (!root)
1174         return;
1175     VisibleSelection newSelection(VisibleSelection::selectionFromContentsOfNode(root));
1176     if (m_frame->shouldChangeSelection(newSelection))
1177         setSelection(newSelection);
1178     selectFrameElementInParentIfFullySelected();
1179     m_frame->notifyRendererOfSelectionChange(true);
1180 }
1181 
setSelectedRange(Range * range,EAffinity affinity,bool closeTyping)1182 bool SelectionController::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
1183 {
1184     if (!range)
1185         return false;
1186 
1187     ExceptionCode ec = 0;
1188     Node* startContainer = range->startContainer(ec);
1189     if (ec)
1190         return false;
1191 
1192     Node* endContainer = range->endContainer(ec);
1193     if (ec)
1194         return false;
1195 
1196     ASSERT(startContainer);
1197     ASSERT(endContainer);
1198     ASSERT(startContainer->document() == endContainer->document());
1199 
1200     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1201 
1202     // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
1203     // they start at the beginning of the next line instead
1204     bool collapsed = range->collapsed(ec);
1205     if (ec)
1206         return false;
1207 
1208     int startOffset = range->startOffset(ec);
1209     if (ec)
1210         return false;
1211 
1212     int endOffset = range->endOffset(ec);
1213     if (ec)
1214         return false;
1215 
1216     // FIXME: Can we provide extentAffinity?
1217     VisiblePosition visibleStart(startContainer, startOffset, collapsed ? affinity : DOWNSTREAM);
1218     VisiblePosition visibleEnd(endContainer, endOffset, SEL_DEFAULT_AFFINITY);
1219     setSelection(VisibleSelection(visibleStart, visibleEnd), closeTyping);
1220     return true;
1221 }
1222 
isInPasswordField() const1223 bool SelectionController::isInPasswordField() const
1224 {
1225     Node* startNode = start().node();
1226     if (!startNode)
1227         return false;
1228 
1229     startNode = startNode->shadowAncestorNode();
1230     if (!startNode)
1231         return false;
1232 
1233     if (!startNode->hasTagName(inputTag))
1234         return false;
1235 
1236     return static_cast<HTMLInputElement*>(startNode)->inputType() == HTMLInputElement::PASSWORD;
1237 }
1238 
caretRendersInsideNode(Node * node) const1239 bool SelectionController::caretRendersInsideNode(Node* node) const
1240 {
1241     if (!node)
1242         return false;
1243     return !isTableElement(node) && !editingIgnoresContent(node);
1244 }
1245 
focusedOrActiveStateChanged()1246 void SelectionController::focusedOrActiveStateChanged()
1247 {
1248     bool activeAndFocused = isFocusedAndActive();
1249 
1250     // Because RenderObject::selectionBackgroundColor() and
1251     // RenderObject::selectionForegroundColor() check if the frame is active,
1252     // we have to update places those colors were painted.
1253     if (RenderView* view = toRenderView(m_frame->document()->renderer()))
1254         view->repaintRectangleInViewAndCompositedLayers(enclosingIntRect(m_frame->selectionBounds()));
1255 
1256     // Caret appears in the active frame.
1257     if (activeAndFocused)
1258         m_frame->setSelectionFromNone();
1259     m_frame->setCaretVisible(activeAndFocused);
1260 
1261     // Update for caps lock state
1262     m_frame->eventHandler()->capsLockStateMayHaveChanged();
1263 
1264     // Because CSSStyleSelector::checkOneSelector() and
1265     // RenderTheme::isFocused() check if the frame is active, we have to
1266     // update style and theme state that depended on those.
1267     if (Node* node = m_frame->document()->focusedNode()) {
1268         node->setNeedsStyleRecalc();
1269         if (RenderObject* renderer = node->renderer())
1270             if (renderer && renderer->style()->hasAppearance())
1271                 renderer->theme()->stateChanged(renderer, FocusState);
1272     }
1273 
1274     // Secure keyboard entry is set by the active frame.
1275     if (m_frame->document()->useSecureKeyboardEntryWhenActive())
1276         m_frame->setUseSecureKeyboardEntry(activeAndFocused);
1277 }
1278 
pageActivationChanged()1279 void SelectionController::pageActivationChanged()
1280 {
1281     focusedOrActiveStateChanged();
1282 }
1283 
setFocused(bool flag)1284 void SelectionController::setFocused(bool flag)
1285 {
1286     if (m_focused == flag)
1287         return;
1288     m_focused = flag;
1289 
1290     focusedOrActiveStateChanged();
1291 }
1292 
isFocusedAndActive() const1293 bool SelectionController::isFocusedAndActive() const
1294 {
1295     return m_focused && m_frame->page() && m_frame->page()->focusController()->isActive();
1296 }
1297 
1298 #ifndef NDEBUG
1299 
formatForDebugger(char * buffer,unsigned length) const1300 void SelectionController::formatForDebugger(char* buffer, unsigned length) const
1301 {
1302     m_sel.formatForDebugger(buffer, length);
1303 }
1304 
showTreeForThis() const1305 void SelectionController::showTreeForThis() const
1306 {
1307     m_sel.showTreeForThis();
1308 }
1309 
1310 #endif
1311 
1312 }
1313 
1314 #ifndef NDEBUG
1315 
showTree(const WebCore::SelectionController & sel)1316 void showTree(const WebCore::SelectionController& sel)
1317 {
1318     sel.showTreeForThis();
1319 }
1320 
showTree(const WebCore::SelectionController * sel)1321 void showTree(const WebCore::SelectionController* sel)
1322 {
1323     if (sel)
1324         sel->showTreeForThis();
1325 }
1326 
1327 #endif
1328