1 /*
2 * Copyright (C) 2004, 2008, 2009, 2010 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 "CharacterData.h"
30 #include "DeleteSelectionCommand.h"
31 #include "Document.h"
32 #include "Editor.h"
33 #include "EditorClient.h"
34 #include "Element.h"
35 #include "EventHandler.h"
36 #include "ExceptionCode.h"
37 #include "FloatQuad.h"
38 #include "FocusController.h"
39 #include "Frame.h"
40 #include "FrameTree.h"
41 #include "FrameView.h"
42 #include "GraphicsContext.h"
43 #include "HTMLFormElement.h"
44 #include "HTMLFrameElementBase.h"
45 #include "HTMLInputElement.h"
46 #include "HTMLNames.h"
47 #include "HitTestRequest.h"
48 #include "HitTestResult.h"
49 #include "Page.h"
50 #include "Range.h"
51 #include "RenderLayer.h"
52 #include "RenderTextControl.h"
53 #include "RenderTheme.h"
54 #include "RenderView.h"
55 #include "RenderWidget.h"
56 #include "SecureTextInput.h"
57 #include "Settings.h"
58 #include "TextIterator.h"
59 #include "TypingCommand.h"
60 #include "htmlediting.h"
61 #include "visible_units.h"
62 #include <stdio.h>
63 #include <wtf/text/CString.h>
64
65 #define EDIT_DEBUG 0
66
67 namespace WebCore {
68
69 using namespace HTMLNames;
70
71 const int NoXPosForVerticalArrowNavigation = INT_MIN;
72
SelectionController(Frame * frame,bool isDragCaretController)73 SelectionController::SelectionController(Frame* frame, bool isDragCaretController)
74 : m_frame(frame)
75 , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation)
76 , m_granularity(CharacterGranularity)
77 , m_caretBlinkTimer(this, &SelectionController::caretBlinkTimerFired)
78 , m_caretRectNeedsUpdate(true)
79 , m_absCaretBoundsDirty(true)
80 , m_isDragCaretController(isDragCaretController)
81 , m_isCaretBlinkingSuspended(false)
82 , m_focused(frame && frame->page() && frame->page()->focusController()->focusedFrame() == frame)
83 , m_caretVisible(isDragCaretController)
84 , m_caretPaint(true)
85 {
86 setIsDirectional(false);
87 }
88
moveTo(const VisiblePosition & pos,bool userTriggered,CursorAlignOnScroll align)89 void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered, CursorAlignOnScroll align)
90 {
91 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
92 if (userTriggered)
93 options |= UserTriggered;
94 setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), options, align);
95 }
96
moveTo(const VisiblePosition & base,const VisiblePosition & extent,bool userTriggered)97 void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered)
98 {
99 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
100 if (userTriggered)
101 options |= UserTriggered;
102 setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), options);
103 }
104
moveTo(const Position & pos,EAffinity affinity,bool userTriggered)105 void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered)
106 {
107 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
108 if (userTriggered)
109 options |= UserTriggered;
110 setSelection(VisibleSelection(pos, affinity), options);
111 }
112
moveTo(const Range * r,EAffinity affinity,bool userTriggered)113 void SelectionController::moveTo(const Range *r, EAffinity affinity, bool userTriggered)
114 {
115 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
116 if (userTriggered)
117 options |= UserTriggered;
118 VisibleSelection selection = r ? VisibleSelection(r->startPosition(), r->endPosition(), affinity) : VisibleSelection(Position(), Position(), affinity);
119 setSelection(selection, options);
120 }
121
moveTo(const Position & base,const Position & extent,EAffinity affinity,bool userTriggered)122 void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered)
123 {
124 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
125 if (userTriggered)
126 options |= UserTriggered;
127 setSelection(VisibleSelection(base, extent, affinity), options);
128 }
129
setSelection(const VisibleSelection & s,SetSelectionOptions options,CursorAlignOnScroll align,TextGranularity granularity,DirectionalityPolicy directionalityPolicy)130 void SelectionController::setSelection(const VisibleSelection& s, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity, DirectionalityPolicy directionalityPolicy)
131 {
132 m_granularity = granularity;
133
134 bool closeTyping = options & CloseTyping;
135 bool shouldClearTypingStyle = options & ClearTypingStyle;
136 bool userTriggered = options & UserTriggered;
137
138 setIsDirectional(directionalityPolicy == MakeDirectionalSelection);
139
140 if (m_isDragCaretController) {
141 invalidateCaretRect();
142 m_selection = s;
143 m_caretRectNeedsUpdate = true;
144 invalidateCaretRect();
145 updateCaretRect();
146 return;
147 }
148 if (!m_frame) {
149 m_selection = s;
150 return;
151 }
152
153 // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at SelectionController::setSelection
154 // if document->frame() == m_frame we can get into an infinite loop
155 if (s.base().anchorNode()) {
156 Document* document = s.base().anchorNode()->document();
157 if (document && document->frame() && document->frame() != m_frame && document != m_frame->document()) {
158 document->frame()->selection()->setSelection(s, options);
159 return;
160 }
161 }
162
163 if (closeTyping)
164 TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());
165
166 if (shouldClearTypingStyle)
167 clearTypingStyle();
168
169 if (m_selection == s) {
170 // Even if selection was not changed, selection offsets may have been changed.
171 notifyRendererOfSelectionChange(userTriggered);
172 return;
173 }
174
175 VisibleSelection oldSelection = m_selection;
176
177 m_selection = s;
178
179 m_caretRectNeedsUpdate = true;
180
181 if (!s.isNone())
182 setFocusedNodeIfNeeded();
183
184 updateAppearance();
185
186 // Always clear the x position used for vertical arrow navigation.
187 // It will be restored by the vertical arrow navigation code if necessary.
188 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
189 selectFrameElementInParentIfFullySelected();
190 notifyRendererOfSelectionChange(userTriggered);
191 m_frame->editor()->respondToChangedSelection(oldSelection, options);
192 if (userTriggered) {
193 ScrollAlignment alignment;
194
195 if (m_frame->editor()->behavior().shouldCenterAlignWhenSelectionIsRevealed())
196 alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
197 else
198 alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
199
200 revealSelection(alignment, true);
201 }
202
203 notifyAccessibilityForSelectionChange();
204 m_frame->document()->enqueueDocumentEvent(Event::create(eventNames().selectionchangeEvent, false, false));
205 }
206
removingNodeRemovesPosition(Node * node,const Position & position)207 static bool removingNodeRemovesPosition(Node* node, const Position& position)
208 {
209 if (!position.anchorNode())
210 return false;
211
212 if (position.anchorNode() == node)
213 return true;
214
215 if (!node->isElementNode())
216 return false;
217
218 Element* element = static_cast<Element*>(node);
219 return element->contains(position.anchorNode()) || element->contains(position.anchorNode()->shadowAncestorNode());
220 }
221
nodeWillBeRemoved(Node * node)222 void SelectionController::nodeWillBeRemoved(Node *node)
223 {
224 if (isNone())
225 return;
226
227 // There can't be a selection inside a fragment, so if a fragment's node is being removed,
228 // the selection in the document that created the fragment needs no adjustment.
229 if (node && highestAncestor(node)->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
230 return;
231
232 respondToNodeModification(node, removingNodeRemovesPosition(node, m_selection.base()), removingNodeRemovesPosition(node, m_selection.extent()),
233 removingNodeRemovesPosition(node, m_selection.start()), removingNodeRemovesPosition(node, m_selection.end()));
234 }
235
respondToNodeModification(Node * node,bool baseRemoved,bool extentRemoved,bool startRemoved,bool endRemoved)236 void SelectionController::respondToNodeModification(Node* node, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved)
237 {
238 bool clearRenderTreeSelection = false;
239 bool clearDOMTreeSelection = false;
240
241 if (startRemoved || endRemoved) {
242 // FIXME: When endpoints are removed, we should just alter the selection, instead of blowing it away.
243 clearRenderTreeSelection = true;
244 clearDOMTreeSelection = true;
245 } else if (baseRemoved || extentRemoved) {
246 // The base and/or extent are about to be removed, but the start and end aren't.
247 // Change the base and extent to the start and end, but don't re-validate the
248 // selection, since doing so could move the start and end into the node
249 // that is about to be removed.
250 if (m_selection.isBaseFirst())
251 m_selection.setWithoutValidation(m_selection.start(), m_selection.end());
252 else
253 m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
254 } else if (RefPtr<Range> range = m_selection.firstRange()) {
255 ExceptionCode ec = 0;
256 Range::CompareResults compareResult = range->compareNode(node, ec);
257 if (!ec && (compareResult == Range::NODE_BEFORE_AND_AFTER || compareResult == Range::NODE_INSIDE)) {
258 // If we did nothing here, when this node's renderer was destroyed, the rect that it
259 // occupied would be invalidated, but, selection gaps that change as a result of
260 // the removal wouldn't be invalidated.
261 // FIXME: Don't do so much unnecessary invalidation.
262 clearRenderTreeSelection = true;
263 }
264 }
265
266 if (clearRenderTreeSelection) {
267 RefPtr<Document> document = m_selection.start().anchorNode()->document();
268 document->updateStyleIfNeeded();
269 if (RenderView* view = toRenderView(document->renderer()))
270 view->clearSelection();
271 }
272
273 if (clearDOMTreeSelection)
274 setSelection(VisibleSelection(), 0);
275 }
276
277 enum EndPointType { EndPointIsStart, EndPointIsEnd };
278
shouldRemovePositionAfterAdoptingTextReplacement(Position & position,EndPointType type,CharacterData * node,unsigned offset,unsigned oldLength,unsigned newLength)279 static bool shouldRemovePositionAfterAdoptingTextReplacement(Position& position, EndPointType type, CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
280 {
281 if (!position.anchorNode() || position.anchorNode() != node || position.anchorType() != Position::PositionIsOffsetInAnchor)
282 return false;
283
284 ASSERT(position.offsetInContainerNode() >= 0);
285 unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
286 if (positionOffset > offset && positionOffset < offset + oldLength)
287 return true;
288
289 // Adjust the offset if the position is after or at the end of the deleted contents (positionOffset >= offset + oldLength)
290 // to avoid having a stale offset except when the position is the end of selection and nothing is deleted, in which case,
291 // adjusting offset results in incorrectly extending the selection until the end of newly inserted contents.
292 if ((positionOffset > offset + oldLength) || (positionOffset == offset + oldLength && (type == EndPointIsStart || oldLength)))
293 position.moveToOffset(positionOffset - oldLength + newLength);
294
295 return false;
296 }
297
textWillBeReplaced(CharacterData * node,unsigned offset,unsigned oldLength,unsigned newLength)298 void SelectionController::textWillBeReplaced(CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
299 {
300 // The fragment check is a performance optimization. See http://trac.webkit.org/changeset/30062.
301 if (isNone() || !node || highestAncestor(node)->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
302 return;
303
304 Position base = m_selection.base();
305 Position extent = m_selection.extent();
306 Position start = m_selection.start();
307 Position end = m_selection.end();
308 bool shouldRemoveBase = shouldRemovePositionAfterAdoptingTextReplacement(base, m_selection.isBaseFirst() ? EndPointIsStart : EndPointIsEnd, node, offset, oldLength, newLength);
309 bool shouldRemoveExtent = shouldRemovePositionAfterAdoptingTextReplacement(extent, m_selection.isBaseFirst() ? EndPointIsEnd : EndPointIsStart, node, offset, oldLength, newLength);
310 bool shouldRemoveStart = shouldRemovePositionAfterAdoptingTextReplacement(start, EndPointIsStart, node, offset, oldLength, newLength);
311 bool shouldRemoveEnd = shouldRemovePositionAfterAdoptingTextReplacement(end, EndPointIsEnd, node, offset, oldLength, newLength);
312
313 if ((base != m_selection.base() || extent != m_selection.extent() || start != m_selection.start() || end != m_selection.end())
314 && !shouldRemoveStart && !shouldRemoveEnd) {
315 VisibleSelection newSelection;
316 if (!shouldRemoveBase && !shouldRemoveExtent)
317 newSelection.setWithoutValidation(base, extent);
318 else {
319 if (newSelection.isBaseFirst())
320 newSelection.setWithoutValidation(start, end);
321 else
322 newSelection.setWithoutValidation(end, start);
323 }
324 m_frame->document()->updateLayout();
325 setSelection(newSelection, 0);
326 return;
327 }
328
329 respondToNodeModification(node, shouldRemoveBase, shouldRemoveExtent, shouldRemoveStart, shouldRemoveEnd);
330 }
331
setIsDirectional(bool isDirectional)332 void SelectionController::setIsDirectional(bool isDirectional)
333 {
334 m_isDirectional = !m_frame || m_frame->editor()->behavior().shouldConsiderSelectionAsDirectional() || isDirectional;
335 }
336
directionOfEnclosingBlock()337 TextDirection SelectionController::directionOfEnclosingBlock()
338 {
339 return WebCore::directionOfEnclosingBlock(m_selection.extent());
340 }
341
willBeModified(EAlteration alter,SelectionDirection direction)342 void SelectionController::willBeModified(EAlteration alter, SelectionDirection direction)
343 {
344 if (alter != AlterationExtend)
345 return;
346
347 Position start = m_selection.start();
348 Position end = m_selection.end();
349
350 bool baseIsStart = true;
351
352 if (m_isDirectional) {
353 // Make base and extent match start and end so we extend the user-visible selection.
354 // This only matters for cases where base and extend point to different positions than
355 // start and end (e.g. after a double-click to select a word).
356 if (m_selection.isBaseFirst())
357 baseIsStart = true;
358 else
359 baseIsStart = false;
360 } else {
361 switch (direction) {
362 case DirectionRight:
363 if (directionOfEnclosingBlock() == LTR)
364 baseIsStart = true;
365 else
366 baseIsStart = false;
367 break;
368 case DirectionForward:
369 baseIsStart = true;
370 break;
371 case DirectionLeft:
372 if (directionOfEnclosingBlock() == LTR)
373 baseIsStart = false;
374 else
375 baseIsStart = true;
376 break;
377 case DirectionBackward:
378 baseIsStart = false;
379 break;
380 }
381 }
382 if (baseIsStart) {
383 m_selection.setBase(start);
384 m_selection.setExtent(end);
385 } else {
386 m_selection.setBase(end);
387 m_selection.setExtent(start);
388 }
389 }
390
positionForPlatform(bool isGetStart) const391 VisiblePosition SelectionController::positionForPlatform(bool isGetStart) const
392 {
393 Settings* settings = m_frame ? m_frame->settings() : 0;
394 if (settings && settings->editingBehaviorType() == EditingMacBehavior)
395 return isGetStart ? m_selection.visibleStart() : m_selection.visibleEnd();
396 // Linux and Windows always extend selections from the extent endpoint.
397 // FIXME: VisibleSelection should be fixed to ensure as an invariant that
398 // base/extent always point to the same nodes as start/end, but which points
399 // to which depends on the value of isBaseFirst. Then this can be changed
400 // to just return m_sel.extent().
401 return m_selection.isBaseFirst() ? m_selection.visibleEnd() : m_selection.visibleStart();
402 }
403
startForPlatform() const404 VisiblePosition SelectionController::startForPlatform() const
405 {
406 return positionForPlatform(true);
407 }
408
endForPlatform() const409 VisiblePosition SelectionController::endForPlatform() const
410 {
411 return positionForPlatform(false);
412 }
413
modifyExtendingRight(TextGranularity granularity)414 VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granularity)
415 {
416 VisiblePosition pos(m_selection.extent(), m_selection.affinity());
417
418 // The difference between modifyExtendingRight and modifyExtendingForward is:
419 // modifyExtendingForward always extends forward logically.
420 // modifyExtendingRight behaves the same as modifyExtendingForward except for extending character or word,
421 // it extends forward logically if the enclosing block is LTR direction,
422 // but it extends backward logically if the enclosing block is RTL direction.
423 switch (granularity) {
424 case CharacterGranularity:
425 if (directionOfEnclosingBlock() == LTR)
426 pos = pos.next(CannotCrossEditingBoundary);
427 else
428 pos = pos.previous(CannotCrossEditingBoundary);
429 break;
430 case WordGranularity:
431 if (directionOfEnclosingBlock() == LTR)
432 pos = nextWordPosition(pos);
433 else
434 pos = previousWordPosition(pos);
435 break;
436 case LineBoundary:
437 if (directionOfEnclosingBlock() == LTR)
438 pos = modifyExtendingForward(granularity);
439 else
440 pos = modifyExtendingBackward(granularity);
441 break;
442 case SentenceGranularity:
443 case LineGranularity:
444 case ParagraphGranularity:
445 case SentenceBoundary:
446 case ParagraphBoundary:
447 case DocumentBoundary:
448 // FIXME: implement all of the above?
449 pos = modifyExtendingForward(granularity);
450 break;
451 case WebKitVisualWordGranularity:
452 break;
453 }
454 return pos;
455 }
456
modifyExtendingForward(TextGranularity granularity)457 VisiblePosition SelectionController::modifyExtendingForward(TextGranularity granularity)
458 {
459 VisiblePosition pos(m_selection.extent(), m_selection.affinity());
460 switch (granularity) {
461 case CharacterGranularity:
462 pos = pos.next(CannotCrossEditingBoundary);
463 break;
464 case WordGranularity:
465 pos = nextWordPosition(pos);
466 break;
467 case SentenceGranularity:
468 pos = nextSentencePosition(pos);
469 break;
470 case LineGranularity:
471 pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
472 break;
473 case ParagraphGranularity:
474 pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
475 break;
476 case SentenceBoundary:
477 pos = endOfSentence(endForPlatform());
478 break;
479 case LineBoundary:
480 pos = logicalEndOfLine(endForPlatform());
481 break;
482 case ParagraphBoundary:
483 pos = endOfParagraph(endForPlatform());
484 break;
485 case DocumentBoundary:
486 pos = endForPlatform();
487 if (isEditablePosition(pos.deepEquivalent()))
488 pos = endOfEditableContent(pos);
489 else
490 pos = endOfDocument(pos);
491 break;
492 case WebKitVisualWordGranularity:
493 break;
494 }
495
496 return pos;
497 }
498
modifyMovingRight(TextGranularity granularity)499 VisiblePosition SelectionController::modifyMovingRight(TextGranularity granularity)
500 {
501 VisiblePosition pos;
502 switch (granularity) {
503 case CharacterGranularity:
504 if (isRange()) {
505 if (directionOfEnclosingBlock() == LTR)
506 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
507 else
508 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
509 } else
510 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
511 break;
512 case WordGranularity:
513 case SentenceGranularity:
514 case LineGranularity:
515 case ParagraphGranularity:
516 case SentenceBoundary:
517 case ParagraphBoundary:
518 case DocumentBoundary:
519 // FIXME: Implement all of the above.
520 pos = modifyMovingForward(granularity);
521 break;
522 case LineBoundary:
523 pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
524 break;
525 case WebKitVisualWordGranularity:
526 pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
527 break;
528 }
529 return pos;
530 }
531
modifyMovingForward(TextGranularity granularity)532 VisiblePosition SelectionController::modifyMovingForward(TextGranularity granularity)
533 {
534 VisiblePosition pos;
535 // FIXME: Stay in editable content for the less common granularities.
536 switch (granularity) {
537 case CharacterGranularity:
538 if (isRange())
539 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
540 else
541 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
542 break;
543 case WordGranularity:
544 pos = nextWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
545 break;
546 case SentenceGranularity:
547 pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
548 break;
549 case LineGranularity: {
550 // down-arrowing from a range selection that ends at the start of a line needs
551 // to leave the selection at that line start (no need to call nextLinePosition!)
552 pos = endForPlatform();
553 if (!isRange() || !isStartOfLine(pos))
554 pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(START));
555 break;
556 }
557 case ParagraphGranularity:
558 pos = nextParagraphPosition(endForPlatform(), xPosForVerticalArrowNavigation(START));
559 break;
560 case SentenceBoundary:
561 pos = endOfSentence(endForPlatform());
562 break;
563 case LineBoundary:
564 pos = logicalEndOfLine(endForPlatform());
565 break;
566 case ParagraphBoundary:
567 pos = endOfParagraph(endForPlatform());
568 break;
569 case DocumentBoundary:
570 pos = endForPlatform();
571 if (isEditablePosition(pos.deepEquivalent()))
572 pos = endOfEditableContent(pos);
573 else
574 pos = endOfDocument(pos);
575 break;
576 case WebKitVisualWordGranularity:
577 break;
578 }
579 return pos;
580 }
581
modifyExtendingLeft(TextGranularity granularity)582 VisiblePosition SelectionController::modifyExtendingLeft(TextGranularity granularity)
583 {
584 VisiblePosition pos(m_selection.extent(), m_selection.affinity());
585
586 // The difference between modifyExtendingLeft and modifyExtendingBackward is:
587 // modifyExtendingBackward always extends backward logically.
588 // modifyExtendingLeft behaves the same as modifyExtendingBackward except for extending character or word,
589 // it extends backward logically if the enclosing block is LTR direction,
590 // but it extends forward logically if the enclosing block is RTL direction.
591 switch (granularity) {
592 case CharacterGranularity:
593 if (directionOfEnclosingBlock() == LTR)
594 pos = pos.previous(CannotCrossEditingBoundary);
595 else
596 pos = pos.next(CannotCrossEditingBoundary);
597 break;
598 case WordGranularity:
599 if (directionOfEnclosingBlock() == LTR)
600 pos = previousWordPosition(pos);
601 else
602 pos = nextWordPosition(pos);
603 break;
604 case LineBoundary:
605 if (directionOfEnclosingBlock() == LTR)
606 pos = modifyExtendingBackward(granularity);
607 else
608 pos = modifyExtendingForward(granularity);
609 break;
610 case SentenceGranularity:
611 case LineGranularity:
612 case ParagraphGranularity:
613 case SentenceBoundary:
614 case ParagraphBoundary:
615 case DocumentBoundary:
616 pos = modifyExtendingBackward(granularity);
617 break;
618 case WebKitVisualWordGranularity:
619 break;
620 }
621 return pos;
622 }
623
modifyExtendingBackward(TextGranularity granularity)624 VisiblePosition SelectionController::modifyExtendingBackward(TextGranularity granularity)
625 {
626 VisiblePosition pos(m_selection.extent(), m_selection.affinity());
627
628 // Extending a selection backward by word or character from just after a table selects
629 // the table. This "makes sense" from the user perspective, esp. when deleting.
630 // It was done here instead of in VisiblePosition because we want VPs to iterate
631 // over everything.
632 switch (granularity) {
633 case CharacterGranularity:
634 pos = pos.previous(CannotCrossEditingBoundary);
635 break;
636 case WordGranularity:
637 pos = previousWordPosition(pos);
638 break;
639 case SentenceGranularity:
640 pos = previousSentencePosition(pos);
641 break;
642 case LineGranularity:
643 pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
644 break;
645 case ParagraphGranularity:
646 pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
647 break;
648 case SentenceBoundary:
649 pos = startOfSentence(startForPlatform());
650 break;
651 case LineBoundary:
652 pos = logicalStartOfLine(startForPlatform());
653 break;
654 case ParagraphBoundary:
655 pos = startOfParagraph(startForPlatform());
656 break;
657 case DocumentBoundary:
658 pos = startForPlatform();
659 if (isEditablePosition(pos.deepEquivalent()))
660 pos = startOfEditableContent(pos);
661 else
662 pos = startOfDocument(pos);
663 break;
664 case WebKitVisualWordGranularity:
665 break;
666 }
667 return pos;
668 }
669
modifyMovingLeft(TextGranularity granularity)670 VisiblePosition SelectionController::modifyMovingLeft(TextGranularity granularity)
671 {
672 VisiblePosition pos;
673 switch (granularity) {
674 case CharacterGranularity:
675 if (isRange())
676 if (directionOfEnclosingBlock() == LTR)
677 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
678 else
679 pos = VisiblePosition(m_selection.end(), m_selection.affinity());
680 else
681 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
682 break;
683 case WordGranularity:
684 case SentenceGranularity:
685 case LineGranularity:
686 case ParagraphGranularity:
687 case SentenceBoundary:
688 case ParagraphBoundary:
689 case DocumentBoundary:
690 // FIXME: Implement all of the above.
691 pos = modifyMovingBackward(granularity);
692 break;
693 case LineBoundary:
694 pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
695 break;
696 case WebKitVisualWordGranularity:
697 pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
698 break;
699 }
700 return pos;
701 }
702
modifyMovingBackward(TextGranularity granularity)703 VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granularity)
704 {
705 VisiblePosition pos;
706 switch (granularity) {
707 case CharacterGranularity:
708 if (isRange())
709 pos = VisiblePosition(m_selection.start(), m_selection.affinity());
710 else
711 pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
712 break;
713 case WordGranularity:
714 pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
715 break;
716 case SentenceGranularity:
717 pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
718 break;
719 case LineGranularity:
720 pos = previousLinePosition(startForPlatform(), xPosForVerticalArrowNavigation(START));
721 break;
722 case ParagraphGranularity:
723 pos = previousParagraphPosition(startForPlatform(), xPosForVerticalArrowNavigation(START));
724 break;
725 case SentenceBoundary:
726 pos = startOfSentence(startForPlatform());
727 break;
728 case LineBoundary:
729 pos = logicalStartOfLine(startForPlatform());
730 break;
731 case ParagraphBoundary:
732 pos = startOfParagraph(startForPlatform());
733 break;
734 case DocumentBoundary:
735 pos = startForPlatform();
736 if (isEditablePosition(pos.deepEquivalent()))
737 pos = startOfEditableContent(pos);
738 else
739 pos = startOfDocument(pos);
740 break;
741 case WebKitVisualWordGranularity:
742 break;
743 }
744 return pos;
745 }
746
isBoundary(TextGranularity granularity)747 static bool isBoundary(TextGranularity granularity)
748 {
749 return granularity == LineBoundary || granularity == ParagraphBoundary || granularity == DocumentBoundary;
750 }
751
modify(EAlteration alter,SelectionDirection direction,TextGranularity granularity,bool userTriggered)752 bool SelectionController::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, bool userTriggered)
753 {
754 if (userTriggered) {
755 SelectionController trialSelectionController;
756 trialSelectionController.setSelection(m_selection);
757 trialSelectionController.setIsDirectional(m_isDirectional);
758 trialSelectionController.modify(alter, direction, granularity, false);
759
760 bool change = shouldChangeSelection(trialSelectionController.selection());
761 if (!change)
762 return false;
763 }
764
765 willBeModified(alter, direction);
766
767 bool wasRange = m_selection.isRange();
768 Position originalStartPosition = m_selection.start();
769 VisiblePosition position;
770 switch (direction) {
771 case DirectionRight:
772 if (alter == AlterationMove)
773 position = modifyMovingRight(granularity);
774 else
775 position = modifyExtendingRight(granularity);
776 break;
777 case DirectionForward:
778 if (alter == AlterationExtend)
779 position = modifyExtendingForward(granularity);
780 else
781 position = modifyMovingForward(granularity);
782 break;
783 case DirectionLeft:
784 if (alter == AlterationMove)
785 position = modifyMovingLeft(granularity);
786 else
787 position = modifyExtendingLeft(granularity);
788 break;
789 case DirectionBackward:
790 if (alter == AlterationExtend)
791 position = modifyExtendingBackward(granularity);
792 else
793 position = modifyMovingBackward(granularity);
794 break;
795 }
796
797 if (position.isNull())
798 return false;
799
800 if (isSpatialNavigationEnabled(m_frame))
801 if (!wasRange && alter == AlterationMove && position == originalStartPosition)
802 return false;
803
804 // Some of the above operations set an xPosForVerticalArrowNavigation.
805 // Setting a selection will clear it, so save it to possibly restore later.
806 // Note: the START position type is arbitrary because it is unused, it would be
807 // the requested position type if there were no xPosForVerticalArrowNavigation set.
808 int x = xPosForVerticalArrowNavigation(START);
809
810 switch (alter) {
811 case AlterationMove:
812 moveTo(position, userTriggered);
813 break;
814 case AlterationExtend:
815 // Standard Mac behavior when extending to a boundary is grow the selection rather than leaving the
816 // base in place and moving the extent. Matches NSTextView.
817 if (!m_frame || !m_frame->editor()->behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity))
818 setExtent(position, userTriggered);
819 else {
820 TextDirection textDirection = directionOfEnclosingBlock();
821 if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft))
822 setEnd(position, userTriggered);
823 else
824 setStart(position, userTriggered);
825 }
826 break;
827 }
828
829 if (granularity == LineGranularity || granularity == ParagraphGranularity)
830 m_xPosForVerticalArrowNavigation = x;
831
832 if (userTriggered)
833 m_granularity = CharacterGranularity;
834
835
836 setCaretRectNeedsUpdate();
837
838 setIsDirectional(alter == AlterationExtend);
839
840 return true;
841 }
842
843 // FIXME: Maybe baseline would be better?
absoluteCaretY(const VisiblePosition & c,int & y)844 static bool absoluteCaretY(const VisiblePosition &c, int &y)
845 {
846 IntRect rect = c.absoluteCaretBounds();
847 if (rect.isEmpty())
848 return false;
849 y = rect.y() + rect.height() / 2;
850 return true;
851 }
852
modify(EAlteration alter,int verticalDistance,bool userTriggered,CursorAlignOnScroll align)853 bool SelectionController::modify(EAlteration alter, int verticalDistance, bool userTriggered, CursorAlignOnScroll align)
854 {
855 if (!verticalDistance)
856 return false;
857
858 if (userTriggered) {
859 SelectionController trialSelectionController;
860 trialSelectionController.setSelection(m_selection);
861 trialSelectionController.setIsDirectional(m_isDirectional);
862 trialSelectionController.modify(alter, verticalDistance, false);
863
864 bool change = shouldChangeSelection(trialSelectionController.selection());
865 if (!change)
866 return false;
867 }
868
869 bool up = verticalDistance < 0;
870 if (up)
871 verticalDistance = -verticalDistance;
872
873 willBeModified(alter, up ? DirectionBackward : DirectionForward);
874
875 VisiblePosition pos;
876 int xPos = 0;
877 switch (alter) {
878 case AlterationMove:
879 pos = VisiblePosition(up ? m_selection.start() : m_selection.end(), m_selection.affinity());
880 xPos = xPosForVerticalArrowNavigation(up ? START : END);
881 m_selection.setAffinity(up ? UPSTREAM : DOWNSTREAM);
882 break;
883 case AlterationExtend:
884 pos = VisiblePosition(m_selection.extent(), m_selection.affinity());
885 xPos = xPosForVerticalArrowNavigation(EXTENT);
886 m_selection.setAffinity(DOWNSTREAM);
887 break;
888 }
889
890 int startY;
891 if (!absoluteCaretY(pos, startY))
892 return false;
893 if (up)
894 startY = -startY;
895 int lastY = startY;
896
897 VisiblePosition result;
898 VisiblePosition next;
899 for (VisiblePosition p = pos; ; p = next) {
900 next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
901 if (next.isNull() || next == p)
902 break;
903 int nextY;
904 if (!absoluteCaretY(next, nextY))
905 break;
906 if (up)
907 nextY = -nextY;
908 if (nextY - startY > verticalDistance)
909 break;
910 if (nextY >= lastY) {
911 lastY = nextY;
912 result = next;
913 }
914 }
915
916 if (result.isNull())
917 return false;
918
919 switch (alter) {
920 case AlterationMove:
921 moveTo(result, userTriggered, align);
922 break;
923 case AlterationExtend:
924 setExtent(result, userTriggered);
925 break;
926 }
927
928 if (userTriggered)
929 m_granularity = CharacterGranularity;
930
931 setIsDirectional(alter == AlterationExtend);
932
933 return true;
934 }
935
xPosForVerticalArrowNavigation(EPositionType type)936 int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
937 {
938 int x = 0;
939
940 if (isNone())
941 return x;
942
943 Position pos;
944 switch (type) {
945 case START:
946 pos = m_selection.start();
947 break;
948 case END:
949 pos = m_selection.end();
950 break;
951 case BASE:
952 pos = m_selection.base();
953 break;
954 case EXTENT:
955 pos = m_selection.extent();
956 break;
957 }
958
959 Frame* frame = pos.anchorNode()->document()->frame();
960 if (!frame)
961 return x;
962
963 if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation) {
964 VisiblePosition visiblePosition(pos, m_selection.affinity());
965 // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
966 // after the selection is created and before this function is called.
967 x = visiblePosition.isNotNull() ? visiblePosition.xOffsetForVerticalNavigation() : 0;
968 m_xPosForVerticalArrowNavigation = x;
969 } else
970 x = m_xPosForVerticalArrowNavigation;
971
972 return x;
973 }
974
clear()975 void SelectionController::clear()
976 {
977 m_granularity = CharacterGranularity;
978 setSelection(VisibleSelection());
979 }
980
setStart(const VisiblePosition & pos,bool userTriggered)981 void SelectionController::setStart(const VisiblePosition &pos, bool userTriggered)
982 {
983 if (m_selection.isBaseFirst())
984 setBase(pos, userTriggered);
985 else
986 setExtent(pos, userTriggered);
987 }
988
setEnd(const VisiblePosition & pos,bool userTriggered)989 void SelectionController::setEnd(const VisiblePosition &pos, bool userTriggered)
990 {
991 if (m_selection.isBaseFirst())
992 setExtent(pos, userTriggered);
993 else
994 setBase(pos, userTriggered);
995 }
996
setBase(const VisiblePosition & pos,bool userTriggered)997 void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
998 {
999 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
1000 if (userTriggered)
1001 options |= UserTriggered;
1002 setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity()), options);
1003 }
1004
setExtent(const VisiblePosition & pos,bool userTriggered)1005 void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered)
1006 {
1007 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
1008 if (userTriggered)
1009 options |= UserTriggered;
1010 setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity()), options);
1011 }
1012
setBase(const Position & pos,EAffinity affinity,bool userTriggered)1013 void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered)
1014 {
1015 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
1016 if (userTriggered)
1017 options |= UserTriggered;
1018 setSelection(VisibleSelection(pos, m_selection.extent(), affinity), options);
1019 }
1020
setExtent(const Position & pos,EAffinity affinity,bool userTriggered)1021 void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered)
1022 {
1023 SetSelectionOptions options = CloseTyping | ClearTypingStyle;
1024 if (userTriggered)
1025 options |= UserTriggered;
1026 setSelection(VisibleSelection(m_selection.base(), pos, affinity), options);
1027 }
1028
setCaretRectNeedsUpdate(bool flag)1029 void SelectionController::setCaretRectNeedsUpdate(bool flag)
1030 {
1031 m_caretRectNeedsUpdate = flag;
1032 }
1033
updateCaretRect()1034 void SelectionController::updateCaretRect()
1035 {
1036 if (isNone() || !m_selection.start().anchorNode()->inDocument() || !m_selection.end().anchorNode()->inDocument()) {
1037 m_caretRect = IntRect();
1038 return;
1039 }
1040
1041 m_selection.start().anchorNode()->document()->updateStyleIfNeeded();
1042
1043 m_caretRect = IntRect();
1044
1045 if (isCaret()) {
1046 VisiblePosition pos(m_selection.start(), m_selection.affinity());
1047 if (pos.isNotNull()) {
1048 ASSERT(pos.deepEquivalent().deprecatedNode()->renderer());
1049
1050 // First compute a rect local to the renderer at the selection start
1051 RenderObject* renderer;
1052 IntRect localRect = pos.localCaretRect(renderer);
1053
1054 // Get the renderer that will be responsible for painting the caret (which
1055 // is either the renderer we just found, or one of its containers)
1056 RenderObject* caretPainter = caretRenderer();
1057
1058 // Compute an offset between the renderer and the caretPainter
1059 bool unrooted = false;
1060 while (renderer != caretPainter) {
1061 RenderObject* containerObject = renderer->container();
1062 if (!containerObject) {
1063 unrooted = true;
1064 break;
1065 }
1066 localRect.move(renderer->offsetFromContainer(containerObject, localRect.location()));
1067 renderer = containerObject;
1068 }
1069
1070 if (!unrooted)
1071 m_caretRect = localRect;
1072
1073 m_absCaretBoundsDirty = true;
1074 }
1075 }
1076
1077 m_caretRectNeedsUpdate = false;
1078 }
1079
caretRenderer() const1080 RenderObject* SelectionController::caretRenderer() const
1081 {
1082 Node* node = m_selection.start().deprecatedNode();
1083 if (!node)
1084 return 0;
1085
1086 RenderObject* renderer = node->renderer();
1087 if (!renderer)
1088 return 0;
1089
1090 // if caretNode is a block and caret is inside it then caret should be painted by that block
1091 bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(node);
1092 return paintedByBlock ? renderer : renderer->containingBlock();
1093 }
1094
localCaretRect()1095 IntRect SelectionController::localCaretRect()
1096 {
1097 if (m_caretRectNeedsUpdate)
1098 updateCaretRect();
1099
1100 return m_caretRect;
1101 }
1102
absoluteBoundsForLocalRect(const IntRect & rect) const1103 IntRect SelectionController::absoluteBoundsForLocalRect(const IntRect& rect) const
1104 {
1105 RenderObject* caretPainter = caretRenderer();
1106 if (!caretPainter)
1107 return IntRect();
1108
1109 IntRect localRect(rect);
1110 if (caretPainter->isBox())
1111 toRenderBox(caretPainter)->flipForWritingMode(localRect);
1112 return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
1113 }
1114
absoluteCaretBounds()1115 IntRect SelectionController::absoluteCaretBounds()
1116 {
1117 recomputeCaretRect();
1118 return m_absCaretBounds;
1119 }
1120
repaintRectForCaret(IntRect caret)1121 static IntRect repaintRectForCaret(IntRect caret)
1122 {
1123 if (caret.isEmpty())
1124 return IntRect();
1125 // Ensure that the dirty rect intersects the block that paints the caret even in the case where
1126 // the caret itself is just outside the block. See <https://bugs.webkit.org/show_bug.cgi?id=19086>.
1127 caret.inflateX(1);
1128 return caret;
1129 }
1130
caretRepaintRect() const1131 IntRect SelectionController::caretRepaintRect() const
1132 {
1133 return absoluteBoundsForLocalRect(repaintRectForCaret(localCaretRectForPainting()));
1134 }
1135
recomputeCaretRect()1136 bool SelectionController::recomputeCaretRect()
1137 {
1138 if (!m_caretRectNeedsUpdate)
1139 return false;
1140
1141 if (!m_frame)
1142 return false;
1143
1144 FrameView* v = m_frame->document()->view();
1145 if (!v)
1146 return false;
1147
1148 IntRect oldRect = m_caretRect;
1149 IntRect newRect = localCaretRect();
1150 if (oldRect == newRect && !m_absCaretBoundsDirty)
1151 return false;
1152
1153 IntRect oldAbsCaretBounds = m_absCaretBounds;
1154 // FIXME: Rename m_caretRect to m_localCaretRect.
1155 m_absCaretBounds = absoluteBoundsForLocalRect(m_caretRect);
1156 m_absCaretBoundsDirty = false;
1157
1158 if (oldAbsCaretBounds == m_absCaretBounds)
1159 return false;
1160
1161 IntRect oldAbsoluteCaretRepaintBounds = m_absoluteCaretRepaintBounds;
1162 // We believe that we need to inflate the local rect before transforming it to obtain the repaint bounds.
1163 m_absoluteCaretRepaintBounds = caretRepaintRect();
1164
1165 #if ENABLE(TEXT_CARET)
1166 if (RenderView* view = toRenderView(m_frame->document()->renderer())) {
1167 // FIXME: make caret repainting container-aware.
1168 view->repaintRectangleInViewAndCompositedLayers(oldAbsoluteCaretRepaintBounds, false);
1169 if (shouldRepaintCaret(view))
1170 view->repaintRectangleInViewAndCompositedLayers(m_absoluteCaretRepaintBounds, false);
1171 }
1172 #endif
1173 return true;
1174 }
1175
shouldRepaintCaret(const RenderView * view) const1176 bool SelectionController::shouldRepaintCaret(const RenderView* view) const
1177 {
1178 ASSERT(view);
1179 Frame* frame = view->frameView() ? view->frameView()->frame() : 0; // The frame where the selection started.
1180 bool caretBrowsing = frame && frame->settings() && frame->settings()->caretBrowsingEnabled();
1181 return (caretBrowsing || isContentEditable());
1182 }
1183
invalidateCaretRect()1184 void SelectionController::invalidateCaretRect()
1185 {
1186 if (!isCaret())
1187 return;
1188
1189 Document* d = m_selection.start().anchorNode()->document();
1190
1191 // recomputeCaretRect will always return false for the drag caret,
1192 // because its m_frame is always 0.
1193 bool caretRectChanged = recomputeCaretRect();
1194
1195 // EDIT FIXME: This is an unfortunate hack.
1196 // Basically, we can't trust this layout position since we
1197 // can't guarantee that the check to see if we are in unrendered
1198 // content will work at this point. We may have to wait for
1199 // a layout and re-render of the document to happen. So, resetting this
1200 // flag will cause another caret layout to happen the first time
1201 // that we try to paint the caret after this call. That one will work since
1202 // it happens after the document has accounted for any editing
1203 // changes which may have been done.
1204 // And, we need to leave this layout here so the caret moves right
1205 // away after clicking.
1206 m_caretRectNeedsUpdate = true;
1207
1208 if (!caretRectChanged) {
1209 RenderView* view = toRenderView(d->renderer());
1210 if (view && shouldRepaintCaret(view))
1211 view->repaintRectangleInViewAndCompositedLayers(caretRepaintRect(), false);
1212 }
1213 }
1214
paintCaret(GraphicsContext * context,int tx,int ty,const IntRect & clipRect)1215 void SelectionController::paintCaret(GraphicsContext* context, int tx, int ty, const IntRect& clipRect)
1216 {
1217 #if ENABLE(TEXT_CARET)
1218 if (!m_caretVisible)
1219 return;
1220 if (!m_caretPaint)
1221 return;
1222 if (!m_selection.isCaret())
1223 return;
1224
1225 IntRect drawingRect = localCaretRectForPainting();
1226 if (caretRenderer() && caretRenderer()->isBox())
1227 toRenderBox(caretRenderer())->flipForWritingMode(drawingRect);
1228 drawingRect.move(tx, ty);
1229 IntRect caret = intersection(drawingRect, clipRect);
1230 if (caret.isEmpty())
1231 return;
1232
1233 Color caretColor = Color::black;
1234 ColorSpace colorSpace = ColorSpaceDeviceRGB;
1235 Element* element = rootEditableElement();
1236 if (element && element->renderer()) {
1237 caretColor = element->renderer()->style()->visitedDependentColor(CSSPropertyColor);
1238 colorSpace = element->renderer()->style()->colorSpace();
1239 }
1240
1241 context->fillRect(caret, caretColor, colorSpace);
1242 #else
1243 UNUSED_PARAM(context);
1244 UNUSED_PARAM(tx);
1245 UNUSED_PARAM(ty);
1246 UNUSED_PARAM(clipRect);
1247 #endif
1248 }
1249
debugRenderer(RenderObject * r,bool selected) const1250 void SelectionController::debugRenderer(RenderObject *r, bool selected) const
1251 {
1252 if (r->node()->isElementNode()) {
1253 Element* element = static_cast<Element *>(r->node());
1254 fprintf(stderr, "%s%s\n", selected ? "==> " : " ", element->localName().string().utf8().data());
1255 } else if (r->isText()) {
1256 RenderText* textRenderer = toRenderText(r);
1257 if (!textRenderer->textLength() || !textRenderer->firstTextBox()) {
1258 fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : " ");
1259 return;
1260 }
1261
1262 static const int max = 36;
1263 String text = textRenderer->text();
1264 int textLength = text.length();
1265 if (selected) {
1266 int offset = 0;
1267 if (r->node() == m_selection.start().containerNode())
1268 offset = m_selection.start().computeOffsetInContainerNode();
1269 else if (r->node() == m_selection.end().containerNode())
1270 offset = m_selection.end().computeOffsetInContainerNode();
1271
1272 int pos;
1273 InlineTextBox* box = textRenderer->findNextInlineTextBox(offset, pos);
1274 text = text.substring(box->start(), box->len());
1275
1276 String show;
1277 int mid = max / 2;
1278 int caret = 0;
1279
1280 // text is shorter than max
1281 if (textLength < max) {
1282 show = text;
1283 caret = pos;
1284 } else if (pos - mid < 0) {
1285 // too few characters to left
1286 show = text.left(max - 3) + "...";
1287 caret = pos;
1288 } else if (pos - mid >= 0 && pos + mid <= textLength) {
1289 // enough characters on each side
1290 show = "..." + text.substring(pos - mid + 3, max - 6) + "...";
1291 caret = mid;
1292 } else {
1293 // too few characters on right
1294 show = "..." + text.right(max - 3);
1295 caret = pos - (textLength - show.length());
1296 }
1297
1298 show.replace('\n', ' ');
1299 show.replace('\r', ' ');
1300 fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.utf8().data(), pos);
1301 fprintf(stderr, " ");
1302 for (int i = 0; i < caret; i++)
1303 fprintf(stderr, " ");
1304 fprintf(stderr, "^\n");
1305 } else {
1306 if ((int)text.length() > max)
1307 text = text.left(max - 3) + "...";
1308 else
1309 text = text.left(max);
1310 fprintf(stderr, " #text : \"%s\"\n", text.utf8().data());
1311 }
1312 }
1313 }
1314
contains(const IntPoint & point)1315 bool SelectionController::contains(const IntPoint& point)
1316 {
1317 Document* document = m_frame->document();
1318
1319 // Treat a collapsed selection like no selection.
1320 if (!isRange())
1321 return false;
1322 if (!document->renderer())
1323 return false;
1324
1325 HitTestRequest request(HitTestRequest::ReadOnly |
1326 HitTestRequest::Active);
1327 HitTestResult result(point);
1328 document->renderView()->layer()->hitTest(request, result);
1329 Node* innerNode = result.innerNode();
1330 if (!innerNode || !innerNode->renderer())
1331 return false;
1332
1333 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint()));
1334 if (visiblePos.isNull())
1335 return false;
1336
1337 if (m_selection.visibleStart().isNull() || m_selection.visibleEnd().isNull())
1338 return false;
1339
1340 Position start(m_selection.visibleStart().deepEquivalent());
1341 Position end(m_selection.visibleEnd().deepEquivalent());
1342 Position p(visiblePos.deepEquivalent());
1343
1344 return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;
1345 }
1346
1347 // Workaround for the fact that it's hard to delete a frame.
1348 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
1349 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
1350 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
1351 // mouse or the keyboard after setting the selection.
selectFrameElementInParentIfFullySelected()1352 void SelectionController::selectFrameElementInParentIfFullySelected()
1353 {
1354 // Find the parent frame; if there is none, then we have nothing to do.
1355 Frame* parent = m_frame->tree()->parent();
1356 if (!parent)
1357 return;
1358 Page* page = m_frame->page();
1359 if (!page)
1360 return;
1361
1362 // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
1363 if (!isRange())
1364 return;
1365 if (!isStartOfDocument(selection().visibleStart()))
1366 return;
1367 if (!isEndOfDocument(selection().visibleEnd()))
1368 return;
1369
1370 // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
1371 Element* ownerElement = m_frame->ownerElement();
1372 if (!ownerElement)
1373 return;
1374 ContainerNode* ownerElementParent = ownerElement->parentNode();
1375 if (!ownerElementParent)
1376 return;
1377
1378 // 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.
1379 if (!ownerElementParent->rendererIsEditable())
1380 return;
1381
1382 // Create compute positions before and after the element.
1383 unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
1384 VisiblePosition beforeOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex, Position::PositionIsOffsetInAnchor)));
1385 VisiblePosition afterOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex + 1, Position::PositionIsOffsetInAnchor), VP_UPSTREAM_IF_POSSIBLE));
1386
1387 // Focus on the parent frame, and then select from before this element to after.
1388 VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
1389 if (parent->selection()->shouldChangeSelection(newSelection)) {
1390 page->focusController()->setFocusedFrame(parent);
1391 parent->selection()->setSelection(newSelection);
1392 }
1393 }
1394
selectAll()1395 void SelectionController::selectAll()
1396 {
1397 Document* document = m_frame->document();
1398
1399 if (document->focusedNode() && document->focusedNode()->canSelectAll()) {
1400 document->focusedNode()->selectAll();
1401 return;
1402 }
1403
1404 RefPtr<Node> root = 0;
1405 if (isContentEditable())
1406 root = highestEditableRoot(m_selection.start());
1407 else {
1408 root = shadowTreeRootNode();
1409 if (!root)
1410 root = document->documentElement();
1411 }
1412 if (!root)
1413 return;
1414 VisibleSelection newSelection(VisibleSelection::selectionFromContentsOfNode(root.get()));
1415 if (shouldChangeSelection(newSelection))
1416 setSelection(newSelection);
1417 selectFrameElementInParentIfFullySelected();
1418 notifyRendererOfSelectionChange(true);
1419 }
1420
setSelectedRange(Range * range,EAffinity affinity,bool closeTyping)1421 bool SelectionController::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
1422 {
1423 if (!range)
1424 return false;
1425
1426 ExceptionCode ec = 0;
1427 Node* startContainer = range->startContainer(ec);
1428 if (ec)
1429 return false;
1430
1431 Node* endContainer = range->endContainer(ec);
1432 if (ec)
1433 return false;
1434
1435 ASSERT(startContainer);
1436 ASSERT(endContainer);
1437 ASSERT(startContainer->document() == endContainer->document());
1438
1439 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1440
1441 // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
1442 // they start at the beginning of the next line instead
1443 bool collapsed = range->collapsed(ec);
1444 if (ec)
1445 return false;
1446
1447 int startOffset = range->startOffset(ec);
1448 if (ec)
1449 return false;
1450
1451 int endOffset = range->endOffset(ec);
1452 if (ec)
1453 return false;
1454
1455 // FIXME: Can we provide extentAffinity?
1456 VisiblePosition visibleStart(Position(startContainer, startOffset, Position::PositionIsOffsetInAnchor), collapsed ? affinity : DOWNSTREAM);
1457 VisiblePosition visibleEnd(Position(endContainer, endOffset, Position::PositionIsOffsetInAnchor), SEL_DEFAULT_AFFINITY);
1458 SetSelectionOptions options = ClearTypingStyle;
1459 if (closeTyping)
1460 options |= CloseTyping;
1461 setSelection(VisibleSelection(visibleStart, visibleEnd), options);
1462 return true;
1463 }
1464
isInPasswordField() const1465 bool SelectionController::isInPasswordField() const
1466 {
1467 ASSERT(start().isNull() || start().anchorType() == Position::PositionIsOffsetInAnchor
1468 || start().containerNode() || !start().anchorNode()->shadowAncestorNode());
1469 Node* startNode = start().containerNode();
1470 if (!startNode)
1471 return false;
1472
1473 startNode = startNode->shadowAncestorNode();
1474 if (!startNode)
1475 return false;
1476
1477 if (!startNode->hasTagName(inputTag))
1478 return false;
1479
1480 return static_cast<HTMLInputElement*>(startNode)->isPasswordField();
1481 }
1482
caretRendersInsideNode(Node * node) const1483 bool SelectionController::caretRendersInsideNode(Node* node) const
1484 {
1485 if (!node)
1486 return false;
1487 return !isTableElement(node) && !editingIgnoresContent(node);
1488 }
1489
focusedOrActiveStateChanged()1490 void SelectionController::focusedOrActiveStateChanged()
1491 {
1492 bool activeAndFocused = isFocusedAndActive();
1493
1494 // Because RenderObject::selectionBackgroundColor() and
1495 // RenderObject::selectionForegroundColor() check if the frame is active,
1496 // we have to update places those colors were painted.
1497 if (RenderView* view = toRenderView(m_frame->document()->renderer()))
1498 view->repaintRectangleInViewAndCompositedLayers(enclosingIntRect(bounds()));
1499
1500 // Caret appears in the active frame.
1501 if (activeAndFocused)
1502 setSelectionFromNone();
1503 setCaretVisible(activeAndFocused);
1504
1505 // Update for caps lock state
1506 m_frame->eventHandler()->capsLockStateMayHaveChanged();
1507
1508 // Because CSSStyleSelector::checkOneSelector() and
1509 // RenderTheme::isFocused() check if the frame is active, we have to
1510 // update style and theme state that depended on those.
1511 if (Node* node = m_frame->document()->focusedNode()) {
1512 node->setNeedsStyleRecalc();
1513 if (RenderObject* renderer = node->renderer())
1514 if (renderer && renderer->style()->hasAppearance())
1515 renderer->theme()->stateChanged(renderer, FocusState);
1516 }
1517
1518 // Secure keyboard entry is set by the active frame.
1519 if (m_frame->document()->useSecureKeyboardEntryWhenActive())
1520 setUseSecureKeyboardEntry(activeAndFocused);
1521 }
1522
pageActivationChanged()1523 void SelectionController::pageActivationChanged()
1524 {
1525 focusedOrActiveStateChanged();
1526 }
1527
updateSecureKeyboardEntryIfActive()1528 void SelectionController::updateSecureKeyboardEntryIfActive()
1529 {
1530 if (m_frame->document() && isFocusedAndActive())
1531 setUseSecureKeyboardEntry(m_frame->document()->useSecureKeyboardEntryWhenActive());
1532 }
1533
setUseSecureKeyboardEntry(bool enable)1534 void SelectionController::setUseSecureKeyboardEntry(bool enable)
1535 {
1536 if (enable)
1537 enableSecureTextInput();
1538 else
1539 disableSecureTextInput();
1540 }
1541
setFocused(bool flag)1542 void SelectionController::setFocused(bool flag)
1543 {
1544 if (m_focused == flag)
1545 return;
1546 m_focused = flag;
1547
1548 focusedOrActiveStateChanged();
1549 }
1550
isFocusedAndActive() const1551 bool SelectionController::isFocusedAndActive() const
1552 {
1553 return m_focused && m_frame->page() && m_frame->page()->focusController()->isActive();
1554 }
1555
updateAppearance()1556 void SelectionController::updateAppearance()
1557 {
1558 ASSERT(!m_isDragCaretController);
1559
1560 #if ENABLE(TEXT_CARET)
1561 bool caretRectChanged = recomputeCaretRect();
1562
1563 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
1564 bool shouldBlink = m_caretVisible
1565 && isCaret() && (isContentEditable() || caretBrowsing);
1566
1567 // If the caret moved, stop the blink timer so we can restart with a
1568 // black caret in the new location.
1569 if (caretRectChanged || !shouldBlink)
1570 m_caretBlinkTimer.stop();
1571
1572 // Start blinking with a black caret. Be sure not to restart if we're
1573 // already blinking in the right location.
1574 if (shouldBlink && !m_caretBlinkTimer.isActive()) {
1575 if (double blinkInterval = m_frame->page()->theme()->caretBlinkInterval())
1576 m_caretBlinkTimer.startRepeating(blinkInterval);
1577
1578 if (!m_caretPaint) {
1579 m_caretPaint = true;
1580 invalidateCaretRect();
1581 }
1582 }
1583 #endif
1584
1585 // We need to update style in case the node containing the selection is made display:none.
1586 m_frame->document()->updateStyleIfNeeded();
1587
1588 RenderView* view = m_frame->contentRenderer();
1589 if (!view)
1590 return;
1591
1592 VisibleSelection selection = this->selection();
1593
1594 if (!selection.isRange()) {
1595 view->clearSelection();
1596 return;
1597 }
1598
1599 // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
1600 // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. If we pass [foo, 3]
1601 // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
1602 // and will fill the gap before 'bar'.
1603 Position startPos = selection.start();
1604 Position candidate = startPos.downstream();
1605 if (candidate.isCandidate())
1606 startPos = candidate;
1607 Position endPos = selection.end();
1608 candidate = endPos.upstream();
1609 if (candidate.isCandidate())
1610 endPos = candidate;
1611
1612 // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
1613 // because we don't yet notify the SelectionController of text removal.
1614 if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
1615 RenderObject* startRenderer = startPos.deprecatedNode()->renderer();
1616 RenderObject* endRenderer = endPos.deprecatedNode()->renderer();
1617 view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
1618 }
1619 }
1620
setCaretVisible(bool flag)1621 void SelectionController::setCaretVisible(bool flag)
1622 {
1623 if (m_caretVisible == flag)
1624 return;
1625 clearCaretRectIfNeeded();
1626 m_caretVisible = flag;
1627 updateAppearance();
1628 }
1629
clearCaretRectIfNeeded()1630 void SelectionController::clearCaretRectIfNeeded()
1631 {
1632 #if ENABLE(TEXT_CARET)
1633 if (!m_caretPaint)
1634 return;
1635 m_caretPaint = false;
1636 invalidateCaretRect();
1637 #endif
1638 }
1639
caretBlinkTimerFired(Timer<SelectionController> *)1640 void SelectionController::caretBlinkTimerFired(Timer<SelectionController>*)
1641 {
1642 #if ENABLE(TEXT_CARET)
1643 ASSERT(m_caretVisible);
1644 ASSERT(isCaret());
1645 bool caretPaint = m_caretPaint;
1646 if (isCaretBlinkingSuspended() && caretPaint)
1647 return;
1648 m_caretPaint = !caretPaint;
1649 invalidateCaretRect();
1650 #endif
1651 }
1652
notifyRendererOfSelectionChange(bool userTriggered)1653 void SelectionController::notifyRendererOfSelectionChange(bool userTriggered)
1654 {
1655 m_frame->document()->updateStyleIfNeeded();
1656
1657 if (!rootEditableElement())
1658 return;
1659
1660 RenderObject* renderer = rootEditableElement()->shadowAncestorNode()->renderer();
1661 if (!renderer || !renderer->isTextControl())
1662 return;
1663
1664 toRenderTextControl(renderer)->selectionChanged(userTriggered);
1665 }
1666
1667 // Helper function that tells whether a particular node is an element that has an entire
1668 // Frame and FrameView, a <frame>, <iframe>, or <object>.
isFrameElement(const Node * n)1669 static bool isFrameElement(const Node* n)
1670 {
1671 if (!n)
1672 return false;
1673 RenderObject* renderer = n->renderer();
1674 if (!renderer || !renderer->isWidget())
1675 return false;
1676 Widget* widget = toRenderWidget(renderer)->widget();
1677 return widget && widget->isFrameView();
1678 }
1679
setFocusedNodeIfNeeded()1680 void SelectionController::setFocusedNodeIfNeeded()
1681 {
1682 if (isNone() || !isFocused())
1683 return;
1684
1685 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
1686 if (caretBrowsing) {
1687 if (Node* anchor = enclosingAnchorElement(base())) {
1688 m_frame->page()->focusController()->setFocusedNode(anchor, m_frame);
1689 return;
1690 }
1691 }
1692
1693 if (Node* target = rootEditableElement()) {
1694 // Walk up the DOM tree to search for a node to focus.
1695 while (target) {
1696 // We don't want to set focus on a subframe when selecting in a parent frame,
1697 // so add the !isFrameElement check here. There's probably a better way to make this
1698 // work in the long term, but this is the safest fix at this time.
1699 if (target && target->isMouseFocusable() && !isFrameElement(target)) {
1700 m_frame->page()->focusController()->setFocusedNode(target, m_frame);
1701 return;
1702 }
1703 target = target->parentOrHostNode();
1704 }
1705 m_frame->document()->setFocusedNode(0);
1706 }
1707
1708 if (caretBrowsing)
1709 m_frame->page()->focusController()->setFocusedNode(0, m_frame);
1710 }
1711
paintDragCaret(GraphicsContext * p,int tx,int ty,const IntRect & clipRect) const1712 void SelectionController::paintDragCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const
1713 {
1714 #if ENABLE(TEXT_CARET)
1715 SelectionController* dragCaretController = m_frame->page()->dragCaretController();
1716 ASSERT(dragCaretController->selection().isCaret());
1717 if (dragCaretController->selection().start().anchorNode()->document()->frame() == m_frame)
1718 dragCaretController->paintCaret(p, tx, ty, clipRect);
1719 #else
1720 UNUSED_PARAM(p);
1721 UNUSED_PARAM(tx);
1722 UNUSED_PARAM(ty);
1723 UNUSED_PARAM(clipRect);
1724 #endif
1725 }
1726
copyTypingStyle() const1727 PassRefPtr<CSSMutableStyleDeclaration> SelectionController::copyTypingStyle() const
1728 {
1729 if (!m_typingStyle || !m_typingStyle->style())
1730 return 0;
1731 return m_typingStyle->style()->copy();
1732 }
1733
shouldDeleteSelection(const VisibleSelection & selection) const1734 bool SelectionController::shouldDeleteSelection(const VisibleSelection& selection) const
1735 {
1736 return m_frame->editor()->client()->shouldDeleteRange(selection.toNormalizedRange().get());
1737 }
1738
bounds(bool clipToVisibleContent) const1739 FloatRect SelectionController::bounds(bool clipToVisibleContent) const
1740 {
1741 RenderView* root = m_frame->contentRenderer();
1742 FrameView* view = m_frame->view();
1743 if (!root || !view)
1744 return IntRect();
1745
1746 IntRect selectionRect = root->selectionBounds(clipToVisibleContent);
1747 return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect;
1748 }
1749
getClippedVisibleTextRectangles(Vector<FloatRect> & rectangles) const1750 void SelectionController::getClippedVisibleTextRectangles(Vector<FloatRect>& rectangles) const
1751 {
1752 RenderView* root = m_frame->contentRenderer();
1753 if (!root)
1754 return;
1755
1756 FloatRect visibleContentRect = m_frame->view()->visibleContentRect();
1757
1758 Vector<FloatQuad> quads;
1759 toNormalizedRange()->textQuads(quads, true);
1760
1761 // FIXME: We are appending empty rectangles to the list for those that fall outside visibleContentRect.
1762 // It might be better to omit those rectangles entirely.
1763 size_t size = quads.size();
1764 for (size_t i = 0; i < size; ++i)
1765 rectangles.append(intersection(quads[i].enclosingBoundingBox(), visibleContentRect));
1766 }
1767
1768 // Scans logically forward from "start", including any child frames.
scanForForm(Node * start)1769 static HTMLFormElement* scanForForm(Node* start)
1770 {
1771 for (Node* node = start; node; node = node->traverseNextNode()) {
1772 if (node->hasTagName(formTag))
1773 return static_cast<HTMLFormElement*>(node);
1774 if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
1775 return static_cast<HTMLFormControlElement*>(node)->form();
1776 if (node->hasTagName(frameTag) || node->hasTagName(iframeTag)) {
1777 Node* childDocument = static_cast<HTMLFrameElementBase*>(node)->contentDocument();
1778 if (HTMLFormElement* frameResult = scanForForm(childDocument))
1779 return frameResult;
1780 }
1781 }
1782 return 0;
1783 }
1784
1785 // We look for either the form containing the current focus, or for one immediately after it
currentForm() const1786 HTMLFormElement* SelectionController::currentForm() const
1787 {
1788 // Start looking either at the active (first responder) node, or where the selection is.
1789 Node* start = m_frame->document()->focusedNode();
1790 if (!start)
1791 start = this->start().deprecatedNode();
1792
1793 // Try walking up the node tree to find a form element.
1794 Node* node;
1795 for (node = start; node; node = node->parentNode()) {
1796 if (node->hasTagName(formTag))
1797 return static_cast<HTMLFormElement*>(node);
1798 if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
1799 return static_cast<HTMLFormControlElement*>(node)->form();
1800 }
1801
1802 // Try walking forward in the node tree to find a form element.
1803 return scanForForm(start);
1804 }
1805
revealSelection(const ScrollAlignment & alignment,bool revealExtent)1806 void SelectionController::revealSelection(const ScrollAlignment& alignment, bool revealExtent)
1807 {
1808 IntRect rect;
1809
1810 switch (selectionType()) {
1811 case VisibleSelection::NoSelection:
1812 return;
1813 case VisibleSelection::CaretSelection:
1814 rect = absoluteCaretBounds();
1815 break;
1816 case VisibleSelection::RangeSelection:
1817 rect = revealExtent ? VisiblePosition(extent()).absoluteCaretBounds() : enclosingIntRect(bounds(false));
1818 break;
1819 }
1820
1821 Position start = this->start();
1822 ASSERT(start.deprecatedNode());
1823 if (start.deprecatedNode() && start.deprecatedNode()->renderer()) {
1824 // FIXME: This code only handles scrolling the startContainer's layer, but
1825 // the selection rect could intersect more than just that.
1826 // See <rdar://problem/4799899>.
1827 if (RenderLayer* layer = start.deprecatedNode()->renderer()->enclosingLayer()) {
1828 layer->scrollRectToVisible(rect, false, alignment, alignment);
1829 updateAppearance();
1830 }
1831 }
1832 }
1833
setSelectionFromNone()1834 void SelectionController::setSelectionFromNone()
1835 {
1836 // Put a caret inside the body if the entire frame is editable (either the
1837 // entire WebView is editable or designMode is on for this document).
1838
1839 Document* document = m_frame->document();
1840 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
1841 if (!isNone() || !(document->rendererIsEditable() || caretBrowsing))
1842 return;
1843
1844 Node* node = document->documentElement();
1845 while (node && !node->hasTagName(bodyTag))
1846 node = node->traverseNextNode();
1847 if (node)
1848 setSelection(VisibleSelection(firstPositionInOrBeforeNode(node), DOWNSTREAM));
1849 }
1850
shouldChangeSelection(const VisibleSelection & newSelection) const1851 bool SelectionController::shouldChangeSelection(const VisibleSelection& newSelection) const
1852 {
1853 return m_frame->editor()->shouldChangeSelection(selection(), newSelection, newSelection.affinity(), false);
1854 }
1855
1856 #ifndef NDEBUG
1857
formatForDebugger(char * buffer,unsigned length) const1858 void SelectionController::formatForDebugger(char* buffer, unsigned length) const
1859 {
1860 m_selection.formatForDebugger(buffer, length);
1861 }
1862
showTreeForThis() const1863 void SelectionController::showTreeForThis() const
1864 {
1865 m_selection.showTreeForThis();
1866 }
1867
1868 #endif
1869
1870 }
1871
1872 #ifndef NDEBUG
1873
showTree(const WebCore::SelectionController & sel)1874 void showTree(const WebCore::SelectionController& sel)
1875 {
1876 sel.showTreeForThis();
1877 }
1878
showTree(const WebCore::SelectionController * sel)1879 void showTree(const WebCore::SelectionController* sel)
1880 {
1881 if (sel)
1882 sel->showTreeForThis();
1883 }
1884
1885 #endif
1886