Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: Source/core/editing/SelectionController.cpp

Issue 1113323002: [Reland] Refactor the selection code in EventHandler (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "config.h"
29 #include "core/editing/SelectionController.h"
30
31 #include "core/HTMLNames.h"
32 #include "core/dom/Document.h"
33 #include "core/dom/DocumentMarkerController.h"
34 #include "core/editing/Editor.h"
35 #include "core/editing/FrameSelection.h"
36 #include "core/editing/htmlediting.h"
37 #include "core/editing/iterators/TextIterator.h"
38 #include "core/events/Event.h"
39 #include "core/frame/FrameView.h"
40 #include "core/frame/LocalFrame.h"
41 #include "core/frame/Settings.h"
42 #include "core/layout/LayoutView.h"
43 #include "core/page/FocusController.h"
44 #include "core/page/Page.h"
45 #include "platform/RuntimeEnabledFeatures.h"
46
47 namespace blink {
48
49 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelecti on& newSelection)
yosin_UTC9 2015/05/20 02:27:37 Could you move static functions into anonymous nam
Miyoung Shin(g) 2015/05/20 15:53:40 Done.
50 {
51 if (selection.selection() != newSelection)
yosin_UTC9 2015/05/20 02:27:37 nit: Could you use early return pattern?
Miyoung Shin(g) 2015/05/20 15:53:40 Done.
52 selection.setSelection(newSelection);
53 }
54
55 static inline bool dispatchSelectStart(Node* node)
yosin_UTC9 2015/05/20 02:27:37 Could you remove |inline| modifiers? Let's compile
Miyoung Shin(g) 2015/05/20 15:53:40 Done.
56 {
57 if (!node || !node->layoutObject())
58 return true;
59
60 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::sel ectstart));
61 }
62
63 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
64 {
65 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
66 if (!rootUserSelectAll)
67 return selection;
68
69 VisibleSelection newSelection(selection);
70 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCross EditingBoundary));
71 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCr ossEditingBoundary));
72
73 return newSelection;
74 }
75
76 static inline bool canMouseDownStartSelect(Node* node)
77 {
78 if (!node || !node->layoutObject())
79 return true;
80
81 if (!node->canStartSelection())
82 return false;
83
84 return true;
85 }
86
87 static int textDistance(const Position& start, const Position& end)
88 {
89 RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, en d);
90 return TextIterator::rangeLength(range->startPosition(), range->endPosition( ), true);
91 }
92
93 PassOwnPtr<SelectionController> SelectionController::create(LocalFrame* frame)
94 {
95 return adoptPtr(new SelectionController(frame));
96 }
97
98 SelectionController::SelectionController(LocalFrame* frame)
99 : m_frame(frame)
100 , m_selection(&frame->selection())
101 , m_mouseDownMayStartSelect(false)
102 , m_singleClickInSelection(false)
103 , m_selectionState(SelectionState::HaveNotStartedSelection)
104 {
105
106 }
107
108 SelectionController::~SelectionController()
109 {
110 }
111
112 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node * targetNode, const VisibleSelection& visibleSelection, TextGranularity granular ity)
113 {
114 if (Position::nodeIsUserSelectNone(targetNode))
115 return false;
116
117 if (!dispatchSelectStart(targetNode))
118 return false;
119
120 if (visibleSelection.isRange()) {
121 m_selectionState = SelectionState::ExtendedSelection;
122 } else {
123 granularity = CharacterGranularity;
124 m_selectionState = SelectionState::PlacedCaret;
125 }
126
127 selection().setNonDirectionalSelectionIfNeeded(visibleSelection, granularity );
128
129 return true;
130 }
131
132 void SelectionController::selectClosestWordFromHitTestResult(const HitTestResult & result, AppendTrailingWhitespace appendTrailingWhitespace)
133 {
134 Node* innerNode = result.innerNode();
135 VisibleSelection newSelection;
136
137 if (innerNode && innerNode->layoutObject()) {
138 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint()));
139 if (pos.isNotNull()) {
140 newSelection = VisibleSelection(pos);
141 newSelection.expandUsingGranularity(WordGranularity);
142 }
143
144 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend & & newSelection.isRange())
145 newSelection.appendTrailingWhitespace();
146
147 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
148 }
149 }
150
151 void SelectionController::selectClosestMisspellingFromHitTestResult(const HitTes tResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
152 {
153 Node* innerNode = result.innerNode();
154 VisibleSelection newSelection;
155
156 if (innerNode && innerNode->layoutObject()) {
157 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint()));
158 Position start = pos.deepEquivalent();
159 Position end = pos.deepEquivalent();
160 if (pos.isNotNull()) {
161 DocumentMarkerVector markers = innerNode->document().markers().marke rsInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers());
162 if (markers.size() == 1) {
163 start.moveToOffset(markers[0]->startOffset());
164 end.moveToOffset(markers[0]->endOffset());
165 newSelection = VisibleSelection(start, end);
166 }
167 }
168
169 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend & & newSelection.isRange())
170 newSelection.appendTrailingWhitespace();
171
172 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
173 }
174 }
175
176 void SelectionController::selectClosestWordFromMouseEvent(const MouseEventWithHi tTestResults& result)
177 {
178 if (m_mouseDownMayStartSelect) {
179 selectClosestWordFromHitTestResult(result.hitTestResult(),
180 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailin gWhitespace::DontAppend);
181 }
182 }
183
184 void SelectionController::selectClosestMisspellingFromMouseEvent(const MouseEven tWithHitTestResults& result)
185 {
186 if (m_mouseDownMayStartSelect) {
187 selectClosestMisspellingFromHitTestResult(result.hitTestResult(),
188 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailin gWhitespace::DontAppend);
189 }
190 }
191
192 void SelectionController::selectClosestWordOrLinkFromMouseEvent(const MouseEvent WithHitTestResults& result)
193 {
194 if (!result.hitTestResult().isLiveLink())
195 return selectClosestWordFromMouseEvent(result);
196
197 Node* innerNode = result.innerNode();
198
199 if (innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect) {
200 VisibleSelection newSelection;
201 Element* URLElement = result.hitTestResult().URLElement();
202 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint()));
203 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescenda ntOf(URLElement))
204 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElem ent);
205
206 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
207 }
208 }
209
210 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul ts& event)
211 {
212 // If we got the event back, that must mean it wasn't prevented,
213 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
214 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !e vent.scrollbar();
215 m_singleClickInSelection = false;
216 }
217
218 bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH itTestResults& event)
219 {
220 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick ");
221
222 if (event.event().button() != LeftButton)
223 return false;
224
225 if (selection().isRange()) {
226 // A double-click when range is already selected
227 // should not change the selection. So, do not call
228 // selectClosestWordFromMouseEvent, but do set
229 // m_beganSelectingText to prevent handleMouseReleaseEvent
230 // from setting caret selection.
231 m_selectionState = SelectionState::ExtendedSelection;
232 } else {
233 selectClosestWordFromMouseEvent(event);
234 }
235 return true;
236 }
237
238 bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH itTestResults& event)
239 {
240 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick ");
241
242 if (event.event().button() != LeftButton)
243 return false;
244
245 Node* innerNode = event.innerNode();
246 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect))
247 return false;
248
249 VisibleSelection newSelection;
250 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localP oint()));
251 if (pos.isNotNull()) {
252 newSelection = VisibleSelection(pos);
253 newSelection.expandUsingGranularity(ParagraphGranularity);
254 }
255
256 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
257 }
258
259 bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithH itTestResults& event)
260 {
261 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventSingleClick ");
262
263 m_frame->document()->updateLayoutIgnorePendingStylesheets();
264 Node* innerNode = event.innerNode();
265 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect))
266 return false;
267
268 // Extend the selection if the Shift key is down, unless the click is in a l ink.
269 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
270
271 // Don't restart the selection when the mouse is pressed on an
272 // existing selection so we can allow for text dragging.
273 if (FrameView* view = m_frame->view()) {
274 LayoutPoint vPoint = view->rootFrameToContents(event.event().position()) ;
275 if (!extendSelection && selection().contains(vPoint)) {
276 m_singleClickInSelection = true;
277 return false;
278 }
279 }
280
281 VisiblePosition visiblePos(innerNode->layoutObject()->positionForPoint(event .localPoint()));
282 if (visiblePos.isNull())
283 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOW NSTREAM);
284 Position pos = visiblePos.deepEquivalent();
285
286 VisibleSelection newSelection = selection().selection();
287 TextGranularity granularity = CharacterGranularity;
288
289 if (extendSelection && newSelection.isCaretOrRange()) {
290 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSe lectAll(innerNode, VisibleSelection(VisiblePosition(pos))));
291 if (selectionInUserSelectAll.isRange()) {
292 if (comparePositions(selectionInUserSelectAll.start(), newSelection. start()) < 0)
293 pos = selectionInUserSelectAll.start();
294 else if (comparePositions(newSelection.end(), selectionInUserSelectA ll.end()) < 0)
295 pos = selectionInUserSelectAll.end();
296 }
297
298 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional() ) {
299 if (pos.isNotNull()) {
300 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click d eselects when selection
301 // was created right-to-left
302 Position start = newSelection.start();
303 Position end = newSelection.end();
304 int distanceToStart = textDistance(start, pos);
305 int distanceToEnd = textDistance(pos, end);
306 if (distanceToStart <= distanceToEnd)
307 newSelection = VisibleSelection(end, pos);
308 else
309 newSelection = VisibleSelection(start, pos);
310 }
311 } else {
312 newSelection.setExtent(pos);
313 }
314
315 if (selection().granularity() != CharacterGranularity) {
316 granularity = selection().granularity();
317 newSelection.expandUsingGranularity(selection().granularity());
318 }
319 } else if (m_selectionState != SelectionState::ExtendedSelection) {
320 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleS election(visiblePos));
321 }
322
323 // Updating the selection is considered side-effect of the event and so it d oesn't impact the handled state.
324 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, g ranularity);
325 return false;
326 }
327
328 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node * mousePressNode, const IntPoint& lastKnownMousePosition)
329 {
330 if (m_selectionState != SelectionState::ExtendedSelection) {
331 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active );
332 HitTestResult result(request, mouseDownPos);
333 m_frame->document()->layoutView()->hitTest(result);
334
335 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKn ownMousePosition);
336 }
337 updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStart Pos, lastKnownMousePosition);
338 }
339
340 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes ults& event, const LayoutPoint& dragStartPos)
341 {
342 bool handled = false;
343 m_mouseDownMayStartSelect = false;
344 // Clear the selection if the mouse didn't move after the last mouse
345 // press and it's not a context menu click. We do this so when clicking
346 // on the selection, the selection goes away. However, if we are
347 // editing, place the caret.
348 if (m_singleClickInSelection && m_selectionState != SelectionState::Extended Selection
349 && dragStartPos == event.event().position()
350 && selection().isRange()
351 && event.event().button() != RightButton) {
352 VisibleSelection newSelection;
353 Node* node = event.innerNode();
354 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBr owsingEnabled();
355 if (node && node->layoutObject() && (caretBrowsing || node->hasEditableS tyle())) {
356 VisiblePosition pos = VisiblePosition(node->layoutObject()->position ForPoint(event.localPoint()));
357 newSelection = VisibleSelection(pos);
358 }
359
360 setSelectionIfNeeded(selection(), newSelection);
361
362 handled = true;
363 }
364
365 selection().notifyLayoutObjectOfSelectionChange(UserTriggered);
366
367 selection().selectFrameElementInParentIfFullySelected();
368
369 if (event.event().button() == MiddleButton && !event.isOverLink()) {
370 // Ignore handled, since we want to paste to where the caret was placed anyway.
371 handled = handlePasteGlobalSelection(event.event()) || handled;
372 }
373
374 return handled;
375 }
376
377 bool SelectionController::handlePasteGlobalSelection(const PlatformMouseEvent& m ouseEvent)
378 {
379 // If the event was a middle click, attempt to copy global selection in afte r
380 // the newly set caret position.
381 //
382 // This code is called from either the mouse up or mouse down handling. Ther e
383 // is some debate about when the global selection is pasted:
384 // xterm: pastes on up.
385 // GTK: pastes on down.
386 // Qt: pastes on up.
387 // Firefox: pastes on up.
388 // Chromium: pastes on up.
389 //
390 // There is something of a webcompat angle to this well, as highlighted by
391 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
392 // down then the text is pasted just before the onclick handler runs and
393 // clears the text box. So it's important this happens after the event
394 // handlers have been fired.
395 if (mouseEvent.type() != PlatformEvent::MouseReleased)
396 return false;
397
398 if (!m_frame->page())
399 return false;
400 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
401 // Do not paste here if the focus was moved somewhere else.
402 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSele ction())
403 return m_frame->editor().command("PasteGlobalSelection").execute();
404
405 return false;
406 }
407
408 bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges tureEvent, const HitTestResult& hitTestResult)
409 {
410 #if OS(ANDROID)
411 bool shouldLongPressSelectWord = true;
412 #else
413 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()- >touchEditingEnabled();
414 #endif
415 if (!shouldLongPressSelectWord)
416 return false;
417
418 Node* innerNode = hitTestResult.innerNode();
419 if (!hitTestResult.isLiveLink() && innerNode && (innerNode->isContentEditabl e() || innerNode->isTextNode()
420 #if OS(ANDROID)
421 || innerNode->canStartSelection()
422 #endif
423 )) {
424 selectClosestWordFromHitTestResult(hitTestResult, AppendTrailingWhitespa ce::DontAppend);
425 if (m_frame->selection().isRange()) {
426 Page* page = m_frame->page();
427 if (page)
428 page->focusController().focusDocumentView(m_frame);
429
430 return true;
431 }
432 }
433 return false;
434 }
435
436 void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, cons t LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition)
437 {
438 FrameView* view = m_frame->view();
439 if (!view)
440 return;
441 LayoutView* layoutObject = m_frame->contentLayoutObject();
442 if (!layoutObject)
443 return;
444
445 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move);
446 HitTestResult result(request, view->rootFrameToContents(lastKnownMousePositi on));
447 layoutObject->hitTest(result);
448 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM ousePosition);
449 }
450
451 void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTe stResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition)
452 {
453 if (!m_mouseDownMayStartSelect)
454 return;
455
456 Node* target = hitTestResult.innerNode();
457 if (!target)
458 return;
459
460 VisiblePosition targetPosition = selection().selection().visiblePositionResp ectingEditingBoundary(hitTestResult.localPoint(), target);
461 // Don't modify the selection if we're not on a node.
462 if (targetPosition.isNull())
463 return;
464
465 // Restart the selection if this is the first mouse move. This work is usual ly
466 // done in handleMousePressEvent, but not if the mouse press was on an exist ing selection.
467 VisibleSelection newSelection = selection().selection();
468
469 // Special case to limit selection to the containing block for SVG text.
470 // FIXME: Isn't there a better non-SVG-specific way to do this?
471 if (Node* selectionBaseNode = newSelection.base().deprecatedNode()) {
472 if (LayoutObject* selectionBaseLayoutObject = selectionBaseNode->layoutO bject()) {
473 if (selectionBaseLayoutObject->isSVGText()) {
474 if (target->layoutObject()->containingBlock() != selectionBaseLa youtObject->containingBlock())
475 return;
476 }
477 }
478 }
479
480 if (m_selectionState == SelectionState::HaveNotStartedSelection && !dispatch SelectStart(target))
481 return;
482
483 if (m_selectionState != SelectionState::ExtendedSelection) {
484 // Always extend selection here because it's caused by a mouse drag
485 m_selectionState = SelectionState::ExtendedSelection;
486 newSelection = VisibleSelection(targetPosition);
487 }
488
489 if (RuntimeEnabledFeatures::userSelectAllEnabled()) {
490 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllFo rNode(mousePressNode);
491 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePress Node == Position::rootUserSelectAllForNode(target)) {
492 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePre ssNode).upstream(CanCrossEditingBoundary));
493 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePr essNode).downstream(CanCrossEditingBoundary));
494 } else {
495 // Reset base for user select all when base is inside user-select-al l area and extent < base.
496 if (rootUserSelectAllForMousePressNode && comparePositions(target->l ayoutObject()->positionForPoint(hitTestResult.localPoint()), mousePressNode->lay outObject()->positionForPoint(dragStartPos)) < 0)
497 newSelection.setBase(positionAfterNode(rootUserSelectAllForMouse PressNode).downstream(CanCrossEditingBoundary));
498
499 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNod e(target);
500 if (rootUserSelectAllForTarget && mousePressNode->layoutObject() && comparePositions(target->layoutObject()->positionForPoint(hitTestResult.localPoi nt()), mousePressNode->layoutObject()->positionForPoint(dragStartPos)) < 0)
501 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTa rget).upstream(CanCrossEditingBoundary));
502 else if (rootUserSelectAllForTarget && mousePressNode->layoutObject( ))
503 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTar get).downstream(CanCrossEditingBoundary));
504 else
505 newSelection.setExtent(targetPosition);
506 }
507 } else {
508 newSelection.setExtent(targetPosition);
509 }
510
511 if (selection().granularity() != CharacterGranularity)
512 newSelection.expandUsingGranularity(selection().granularity());
513
514 selection().setNonDirectionalSelectionIfNeeded(newSelection, selection().gra nularity(),
515 FrameSelection::AdjustEndpointsAtBidiBoundary);
516 }
517
518
519 void SelectionController::prepareForContextMenu(const MouseEventWithHitTestResul ts& mev, const LayoutPoint& position)
520 {
521 if (selection().contains(position)
522 || mev.scrollbar()
523 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
524 // If the selection is non-editable, we do word selection to make it eas ier to use the contextual menu items
525 // available for text selections. But only if we're above text.
526 || !(selection().isContentEditable() || (mev.innerNode() && mev.innerNod e()->isTextNode())))
527 return;
528
529 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
530
531 if (mev.hitTestResult().isMisspelled()) {
532 selectClosestMisspellingFromMouseEvent(mev);
533 return;
534 }
535
536 if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick())
537 selectClosestWordOrLinkFromMouseEvent(mev);
538 }
539
540 void SelectionController::preparePassMousePressEventToSubframe(MouseEventWithHit TestResults& mev)
541 {
542 // If we're clicking into a frame that is selected, the frame will appear
543 // greyed out even though we're clicking on the selection. This looks
544 // really strange (having the whole frame be greyed out), so we deselect the
545 // selection.
546 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position());
547 if (!selection().contains(p))
548 return;
549
550 VisiblePosition visiblePos(
551 mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint()));
552 VisibleSelection newSelection(visiblePos);
553 selection().setSelection(newSelection);
554 }
555
556 void SelectionController::initializeSelectionState()
557 {
558 m_selectionState = SelectionState::HaveNotStartedSelection;
559 }
560
561 void SelectionController::setMouseDownMayStartSelect(bool mayStartSelect)
562 {
563 m_mouseDownMayStartSelect = mayStartSelect;
564 }
565
566 bool SelectionController::mouseDownMayStartSelect() const
567 {
568 return m_mouseDownMayStartSelect;
569 }
570
571 bool SelectionController::singleClickInSelection() const
572 {
573 return m_singleClickInSelection;
574 }
575
576 FrameSelection& SelectionController::selection() const
577 {
578 return *m_selection;
yosin_UTC9 2015/05/20 02:27:37 return m_frame->selection();
Miyoung Shin(g) 2015/05/20 15:53:40 Done.
579 }
580
581 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698