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

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

Issue 2001083002: Explicit management of FrameSelection availability (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 2016-06-08T18:08:39 Created 4 years, 6 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
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed. 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) 4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
5 * Copyright (C) 2015 Google Inc. All rights reserved. 5 * Copyright (C) 2015 Google Inc. All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 } 266 }
267 267
268 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node * targetNode, const VisibleSelectionInFlatTree& selection, TextGranularity granu larity) 268 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node * targetNode, const VisibleSelectionInFlatTree& selection, TextGranularity granu larity)
269 { 269 {
270 if (targetNode && targetNode->layoutObject() && !targetNode->layoutObject()- >isSelectable()) 270 if (targetNode && targetNode->layoutObject() && !targetNode->layoutObject()- >isSelectable())
271 return false; 271 return false;
272 272
273 if (dispatchSelectStart(targetNode) != DispatchEventResult::NotCanceled) 273 if (dispatchSelectStart(targetNode) != DispatchEventResult::NotCanceled)
274 return false; 274 return false;
275 275
276 if (!selection.isValidFor(*m_frame->document())) 276 // |dispatchSelectStart()| can change document hosted by |m_frame|.
277 if (!this->selection().isAvailable())
278 return false;
279
280 if (!selection.isValidFor(this->selection().document()))
277 return false; 281 return false;
278 282
279 if (selection.isRange()) { 283 if (selection.isRange()) {
280 m_selectionState = SelectionState::ExtendedSelection; 284 m_selectionState = SelectionState::ExtendedSelection;
281 } else { 285 } else {
282 granularity = CharacterGranularity; 286 granularity = CharacterGranularity;
283 m_selectionState = SelectionState::PlacedCaret; 287 m_selectionState = SelectionState::PlacedCaret;
284 } 288 }
285 289
286 this->selection().setNonDirectionalSelectionIfNeeded(selection, granularity) ; 290 this->selection().setNonDirectionalSelectionIfNeeded(selection, granularity) ;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 if (pos.isNotNull() && pos.deepEquivalent().anchorNode()->isDescendantOf(URL Element)) 391 if (pos.isNotNull() && pos.deepEquivalent().anchorNode()->isDescendantOf(URL Element))
388 newSelection = VisibleSelectionInFlatTree::selectionFromContentsOfNode(U RLElement); 392 newSelection = VisibleSelectionInFlatTree::selectionFromContentsOfNode(U RLElement);
389 393
390 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelection ToRespectUserSelectAll(innerNode, newSelection), WordGranularity); 394 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelection ToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
391 } 395 }
392 396
393 bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH itTestResults& event) 397 bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH itTestResults& event)
394 { 398 {
395 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick "); 399 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick ");
396 400
401 if (!selection().isAvailable())
402 return false;
403
397 if (!m_mouseDownAllowsMultiClick) 404 if (!m_mouseDownAllowsMultiClick)
398 return handleMousePressEventSingleClick(event); 405 return handleMousePressEventSingleClick(event);
399 406
400 if (event.event().button() != LeftButton) 407 if (event.event().button() != LeftButton)
401 return false; 408 return false;
402 409
403 if (selection().isRange()) { 410 if (selection().isRange()) {
404 // A double-click when range is already selected 411 // A double-click when range is already selected
405 // should not change the selection. So, do not call 412 // should not change the selection. So, do not call
406 // selectClosestWordFromMouseEvent, but do set 413 // selectClosestWordFromMouseEvent, but do set
407 // m_beganSelectingText to prevent handleMouseReleaseEvent 414 // m_beganSelectingText to prevent handleMouseReleaseEvent
408 // from setting caret selection. 415 // from setting caret selection.
409 m_selectionState = SelectionState::ExtendedSelection; 416 m_selectionState = SelectionState::ExtendedSelection;
410 } else { 417 } else {
411 selectClosestWordFromMouseEvent(event); 418 selectClosestWordFromMouseEvent(event);
412 } 419 }
413 return true; 420 return true;
414 } 421 }
415 422
416 bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH itTestResults& event) 423 bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH itTestResults& event)
417 { 424 {
418 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick "); 425 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick ");
419 426
427 if (!selection().isAvailable()) {
428 // editing/shadow/doubleclick-on-meter-in-shadow-crash.html reach here.
429 return false;
430 }
431
420 if (!m_mouseDownAllowsMultiClick) 432 if (!m_mouseDownAllowsMultiClick)
421 return handleMousePressEventSingleClick(event); 433 return handleMousePressEventSingleClick(event);
422 434
423 if (event.event().button() != LeftButton) 435 if (event.event().button() != LeftButton)
424 return false; 436 return false;
425 437
426 Node* innerNode = event.innerNode(); 438 Node* innerNode = event.innerNode();
427 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) 439 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect))
428 return false; 440 return false;
429 441
430 VisibleSelectionInFlatTree newSelection; 442 VisibleSelectionInFlatTree newSelection;
431 const VisiblePositionInFlatTree& pos = visiblePositionOfHitTestResult(event. hitTestResult()); 443 const VisiblePositionInFlatTree& pos = visiblePositionOfHitTestResult(event. hitTestResult());
432 if (pos.isNotNull()) { 444 if (pos.isNotNull()) {
433 newSelection = VisibleSelectionInFlatTree(pos); 445 newSelection = VisibleSelectionInFlatTree(pos);
434 newSelection.expandUsingGranularity(ParagraphGranularity); 446 newSelection.expandUsingGranularity(ParagraphGranularity);
435 } 447 }
436 448
437 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); 449 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
438 } 450 }
439 451
440 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul ts& event) 452 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul ts& event)
441 { 453 {
442 // If we got the event back, that must mean it wasn't prevented, 454 // If we got the event back, that must mean it wasn't prevented,
443 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. 455 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
444 m_mouseDownMayStartSelect = (canMouseDownStartSelect(event.innerNode()) || i sLinkSelection(event)) 456 m_mouseDownMayStartSelect = (canMouseDownStartSelect(event.innerNode()) || i sLinkSelection(event))
445 && !event.scrollbar(); 457 && !event.scrollbar();
446 m_mouseDownWasSingleClickInSelection = false; 458 m_mouseDownWasSingleClickInSelection = false;
459 if (!selection().isAvailable()) {
460 // "gesture-tap-frame-removed.html" reaches here.
461 m_mouseDownAllowsMultiClick = !event.event().fromTouch();
462 return;
463 }
464
447 // Avoid double-tap touch gesture confusion by restricting multi-click side 465 // Avoid double-tap touch gesture confusion by restricting multi-click side
448 // effects, e.g., word selection, to editable regions. 466 // effects, e.g., word selection, to editable regions.
449 m_mouseDownAllowsMultiClick = !event.event().fromTouch() || selection().hasE ditableStyle(); 467 m_mouseDownAllowsMultiClick = !event.event().fromTouch() || selection().hasE ditableStyle();
450 } 468 }
451 469
452 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node * mousePressNode, const IntPoint& lastKnownMousePosition) 470 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node * mousePressNode, const IntPoint& lastKnownMousePosition)
453 { 471 {
472 if (!selection().isAvailable())
473 return;
454 if (m_selectionState != SelectionState::ExtendedSelection) { 474 if (m_selectionState != SelectionState::ExtendedSelection) {
455 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active ); 475 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active );
456 HitTestResult result(request, mouseDownPos); 476 HitTestResult result(request, mouseDownPos);
457 m_frame->document()->layoutViewItem().hitTest(result); 477 m_frame->document()->layoutViewItem().hitTest(result);
458 478
459 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKn ownMousePosition); 479 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKn ownMousePosition);
460 } 480 }
461 updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStart Pos, lastKnownMousePosition); 481 updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStart Pos, lastKnownMousePosition);
462 } 482 }
463 483
464 void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, cons t LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) 484 void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, cons t LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition)
465 { 485 {
466 FrameView* view = m_frame->view(); 486 FrameView* view = m_frame->view();
467 if (!view) 487 if (!view)
468 return; 488 return;
469 LayoutViewItem layoutItem = m_frame->contentLayoutItem(); 489 LayoutViewItem layoutItem = m_frame->contentLayoutItem();
470 if (layoutItem.isNull()) 490 if (layoutItem.isNull())
471 return; 491 return;
472 492
473 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move); 493 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move);
474 HitTestResult result(request, view->rootFrameToContents(lastKnownMousePositi on)); 494 HitTestResult result(request, view->rootFrameToContents(lastKnownMousePositi on));
475 layoutItem.hitTest(result); 495 layoutItem.hitTest(result);
476 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM ousePosition); 496 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM ousePosition);
477 } 497 }
478 498
479 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes ults& event, const LayoutPoint& dragStartPos) 499 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes ults& event, const LayoutPoint& dragStartPos)
480 { 500 {
501 if (!selection().isAvailable())
502 return false;
503
481 bool handled = false; 504 bool handled = false;
482 m_mouseDownMayStartSelect = false; 505 m_mouseDownMayStartSelect = false;
483 // Clear the selection if the mouse didn't move after the last mouse 506 // Clear the selection if the mouse didn't move after the last mouse
484 // press and it's not a context menu click. We do this so when clicking 507 // press and it's not a context menu click. We do this so when clicking
485 // on the selection, the selection goes away. However, if we are 508 // on the selection, the selection goes away. However, if we are
486 // editing, place the caret. 509 // editing, place the caret.
487 if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionSta te::ExtendedSelection 510 if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionSta te::ExtendedSelection
488 && dragStartPos == event.event().position() 511 && dragStartPos == event.event().position()
489 && selection().isRange() 512 && selection().isRange()
490 && event.event().button() != RightButton) { 513 && event.event().button() != RightButton) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame(); 562 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
540 // Do not paste here if the focus was moved somewhere else. 563 // Do not paste here if the focus was moved somewhere else.
541 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSele ction()) 564 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSele ction())
542 return m_frame->editor().createCommand("PasteGlobalSelection").execute() ; 565 return m_frame->editor().createCommand("PasteGlobalSelection").execute() ;
543 566
544 return false; 567 return false;
545 } 568 }
546 569
547 bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges tureEvent, const HitTestResult& hitTestResult) 570 bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges tureEvent, const HitTestResult& hitTestResult)
548 { 571 {
572 if (!selection().isAvailable())
573 return false;
549 if (hitTestResult.isLiveLink()) 574 if (hitTestResult.isLiveLink())
550 return false; 575 return false;
551 576
552 Node* innerNode = hitTestResult.innerNode(); 577 Node* innerNode = hitTestResult.innerNode();
553 bool innerNodeIsSelectable = innerNode && (innerNode->isContentEditable() || innerNode->isTextNode() || innerNode->canStartSelection()); 578 bool innerNodeIsSelectable = innerNode && (innerNode->isContentEditable() || innerNode->isTextNode() || innerNode->canStartSelection());
554 if (!innerNodeIsSelectable) 579 if (!innerNodeIsSelectable)
555 return false; 580 return false;
556 581
557 selectClosestWordFromHitTestResult(hitTestResult, AppendTrailingWhitespace:: DontAppend, SelectInputEventType::GestureLongPress); 582 selectClosestWordFromHitTestResult(hitTestResult, AppendTrailingWhitespace:: DontAppend, SelectInputEventType::GestureLongPress);
583 if (!selection().isAvailable()) {
584 // "editing/selection/longpress-selection-in-iframe-removed-crash.html"
585 // reach here.
586 return false;
587 }
558 return selection().isRange(); 588 return selection().isRange();
559 } 589 }
560 590
561 void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResult s& mev, const LayoutPoint& position) 591 void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResult s& mev, const LayoutPoint& position)
562 { 592 {
593 if (!selection().isAvailable())
594 return;
563 if (selection().contains(position) 595 if (selection().contains(position)
564 || mev.scrollbar() 596 || mev.scrollbar()
565 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. 597 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
566 // If the selection is non-editable, we do word selection to make it eas ier to use the contextual menu items 598 // If the selection is non-editable, we do word selection to make it eas ier to use the contextual menu items
567 // available for text selections. But only if we're above text. 599 // available for text selections. But only if we're above text.
568 || !(selection().isContentEditable() || (mev.innerNode() && mev.innerNod e()->isTextNode()))) 600 || !(selection().isContentEditable() || (mev.innerNode() && mev.innerNod e()->isTextNode())))
569 return; 601 return;
570 602
571 // Context menu events are always allowed to perform a selection. 603 // Context menu events are always allowed to perform a selection.
572 TemporaryChange<bool> mouseDownMayStartSelectChange(m_mouseDownMayStartSelec t, true); 604 TemporaryChange<bool> mouseDownMayStartSelectChange(m_mouseDownMayStartSelec t, true);
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 { 661 {
630 return m_frame->selection(); 662 return m_frame->selection();
631 } 663 }
632 664
633 bool isLinkSelection(const MouseEventWithHitTestResults& event) 665 bool isLinkSelection(const MouseEventWithHitTestResults& event)
634 { 666 {
635 return event.event().altKey() && event.isOverLink(); 667 return event.event().altKey() && event.isOverLink();
636 } 668 }
637 669
638 } // namespace blink 670 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698