| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights | 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights |
| 3 * reserved. | 3 * reserved. |
| 4 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) | 4 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) |
| 5 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) | 5 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) |
| 6 * Copyright (C) 2015 Google Inc. All rights reserved. | 6 * Copyright (C) 2015 Google Inc. All rights reserved. |
| 7 * | 7 * |
| 8 * Redistribution and use in source and binary forms, with or without | 8 * Redistribution and use in source and binary forms, with or without |
| 9 * modification, are permitted provided that the following conditions | 9 * modification, are permitted provided that the following conditions |
| 10 * are met: | 10 * are met: |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 | 130 |
| 131 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); | 131 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); |
| 132 Node* innerNode = event.innerNode(); | 132 Node* innerNode = event.innerNode(); |
| 133 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | 133 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
| 134 return false; | 134 return false; |
| 135 | 135 |
| 136 // Extend the selection if the Shift key is down, unless the click is in a | 136 // Extend the selection if the Shift key is down, unless the click is in a |
| 137 // link or image. | 137 // link or image. |
| 138 bool extendSelection = isExtendingSelection(event); | 138 bool extendSelection = isExtendingSelection(event); |
| 139 | 139 |
| 140 // Don't restart the selection when the mouse is pressed on an | |
| 141 // existing selection so we can allow for text dragging. | |
| 142 if (FrameView* view = m_frame->view()) { | |
| 143 LayoutPoint vPoint = view->rootFrameToContents(event.event().position()); | |
| 144 if (!extendSelection && selection().contains(vPoint)) { | |
| 145 m_mouseDownWasSingleClickInSelection = true; | |
| 146 return false; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 VisiblePositionInFlatTree visiblePos = | 140 VisiblePositionInFlatTree visiblePos = |
| 151 visiblePositionOfHitTestResult(event.hitTestResult()); | 141 visiblePositionOfHitTestResult(event.hitTestResult()); |
| 152 if (visiblePos.isNull()) | 142 if (visiblePos.isNull()) |
| 153 visiblePos = createVisiblePosition( | 143 visiblePos = createVisiblePosition( |
| 154 PositionInFlatTree::firstPositionInOrBeforeNode(innerNode)); | 144 PositionInFlatTree::firstPositionInOrBeforeNode(innerNode)); |
| 155 PositionInFlatTree pos = visiblePos.deepEquivalent(); | 145 PositionInFlatTree pos = visiblePos.deepEquivalent(); |
| 156 | 146 |
| 157 VisibleSelectionInFlatTree newSelection = | 147 VisibleSelectionInFlatTree newSelection = |
| 158 selection().visibleSelection<EditingInFlatTreeStrategy>(); | 148 selection().visibleSelection<EditingInFlatTreeStrategy>(); |
| 159 TextGranularity granularity = CharacterGranularity; | 149 TextGranularity granularity = CharacterGranularity; |
| 160 | 150 |
| 151 // Don't restart the selection when the mouse is pressed on an |
| 152 // existing selection so we can allow for text dragging. |
| 153 if (!extendSelection && selection().contains(event.hitTestResult())) { |
| 154 m_mouseDownWasSingleClickInSelection = true; |
| 155 if (!event.event().fromTouch()) |
| 156 return false; |
| 157 |
| 158 if (!selection().isHandleVisible()) { |
| 159 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, |
| 160 granularity, true); |
| 161 return false; |
| 162 } |
| 163 } |
| 164 |
| 161 if (extendSelection && !newSelection.isNone()) { | 165 if (extendSelection && !newSelection.isNone()) { |
| 162 const VisibleSelectionInFlatTree selectionInUserSelectAll( | 166 const VisibleSelectionInFlatTree selectionInUserSelectAll( |
| 163 expandSelectionToRespectUserSelectAll(innerNode, | 167 expandSelectionToRespectUserSelectAll(innerNode, |
| 164 createVisibleSelection(pos))); | 168 createVisibleSelection(pos))); |
| 165 if (selectionInUserSelectAll.isRange()) { | 169 if (selectionInUserSelectAll.isRange()) { |
| 166 if (selectionInUserSelectAll.start().compareTo(newSelection.start()) < 0) | 170 if (selectionInUserSelectAll.start().compareTo(newSelection.start()) < 0) |
| 167 pos = selectionInUserSelectAll.start(); | 171 pos = selectionInUserSelectAll.start(); |
| 168 else if (newSelection.end().compareTo(selectionInUserSelectAll.end()) < 0) | 172 else if (newSelection.end().compareTo(selectionInUserSelectAll.end()) < 0) |
| 169 pos = selectionInUserSelectAll.end(); | 173 pos = selectionInUserSelectAll.end(); |
| 170 } | 174 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 188 | 192 |
| 189 if (selection().granularity() != CharacterGranularity) { | 193 if (selection().granularity() != CharacterGranularity) { |
| 190 granularity = selection().granularity(); | 194 granularity = selection().granularity(); |
| 191 newSelection.expandUsingGranularity(selection().granularity()); | 195 newSelection.expandUsingGranularity(selection().granularity()); |
| 192 } | 196 } |
| 193 } else if (m_selectionState != SelectionState::ExtendedSelection) { | 197 } else if (m_selectionState != SelectionState::ExtendedSelection) { |
| 194 newSelection = expandSelectionToRespectUserSelectAll( | 198 newSelection = expandSelectionToRespectUserSelectAll( |
| 195 innerNode, createVisibleSelection(visiblePos)); | 199 innerNode, createVisibleSelection(visiblePos)); |
| 196 } | 200 } |
| 197 | 201 |
| 202 bool isHandleVisible = false; |
| 203 if (newSelection.isContentEditable()) { |
| 204 bool isTextBoxEmpty = |
| 205 VisibleSelection::selectionFromContentsOfNode(innerNode).isCaret(); |
| 206 bool notLeftClick = event.event().pointerProperties().button != |
| 207 WebPointerProperties::Button::Left; |
| 208 if (!isTextBoxEmpty || notLeftClick) |
| 209 isHandleVisible = event.event().fromTouch(); |
| 210 } |
| 211 |
| 198 // Updating the selection is considered side-effect of the event and so it | 212 // Updating the selection is considered side-effect of the event and so it |
| 199 // doesn't impact the handled state. | 213 // doesn't impact the handled state. |
| 200 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, | 214 updateSelectionForMouseDownDispatchingSelectStart( |
| 201 granularity); | 215 innerNode, newSelection, granularity, isHandleVisible); |
| 202 return false; | 216 return false; |
| 203 } | 217 } |
| 204 | 218 |
| 205 void SelectionController::updateSelectionForMouseDrag( | 219 void SelectionController::updateSelectionForMouseDrag( |
| 206 const HitTestResult& hitTestResult, | 220 const HitTestResult& hitTestResult, |
| 207 Node* mousePressNode, | 221 Node* mousePressNode, |
| 208 const LayoutPoint& dragStartPos, | 222 const LayoutPoint& dragStartPos, |
| 209 const IntPoint& lastKnownMousePosition) { | 223 const IntPoint& lastKnownMousePosition) { |
| 210 if (!m_mouseDownMayStartSelect) | 224 if (!m_mouseDownMayStartSelect) |
| 211 return; | 225 return; |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 newSelection.expandUsingGranularity(selection().granularity()); | 333 newSelection.expandUsingGranularity(selection().granularity()); |
| 320 | 334 |
| 321 selection().setNonDirectionalSelectionIfNeeded( | 335 selection().setNonDirectionalSelectionIfNeeded( |
| 322 newSelection, selection().granularity(), | 336 newSelection, selection().granularity(), |
| 323 FrameSelection::AdjustEndpointsAtBidiBoundary); | 337 FrameSelection::AdjustEndpointsAtBidiBoundary); |
| 324 } | 338 } |
| 325 | 339 |
| 326 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart( | 340 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart( |
| 327 Node* targetNode, | 341 Node* targetNode, |
| 328 const VisibleSelectionInFlatTree& selection, | 342 const VisibleSelectionInFlatTree& selection, |
| 329 TextGranularity granularity) { | 343 TextGranularity granularity, |
| 344 bool isHandleVisible) { |
| 330 if (targetNode && targetNode->layoutObject() && | 345 if (targetNode && targetNode->layoutObject() && |
| 331 !targetNode->layoutObject()->isSelectable()) | 346 !targetNode->layoutObject()->isSelectable()) |
| 332 return false; | 347 return false; |
| 333 | 348 |
| 334 if (dispatchSelectStart(targetNode) != DispatchEventResult::NotCanceled) | 349 if (dispatchSelectStart(targetNode) != DispatchEventResult::NotCanceled) |
| 335 return false; | 350 return false; |
| 336 | 351 |
| 337 // |dispatchSelectStart()| can change document hosted by |m_frame|. | 352 // |dispatchSelectStart()| can change document hosted by |m_frame|. |
| 338 if (!this->selection().isAvailable()) | 353 if (!this->selection().isAvailable()) |
| 339 return false; | 354 return false; |
| 340 | 355 |
| 341 if (!selection.isValidFor(this->selection().document())) | 356 if (!selection.isValidFor(this->selection().document())) |
| 342 return false; | 357 return false; |
| 343 | 358 |
| 344 if (selection.isRange()) { | 359 if (selection.isRange()) { |
| 345 m_selectionState = SelectionState::ExtendedSelection; | 360 m_selectionState = SelectionState::ExtendedSelection; |
| 346 } else { | 361 } else { |
| 347 granularity = CharacterGranularity; | 362 granularity = CharacterGranularity; |
| 348 m_selectionState = SelectionState::PlacedCaret; | 363 m_selectionState = SelectionState::PlacedCaret; |
| 349 } | 364 } |
| 350 | 365 |
| 351 this->selection().setNonDirectionalSelectionIfNeeded(selection, granularity); | 366 this->selection().setNonDirectionalSelectionIfNeeded( |
| 367 selection, granularity, FrameSelection::DoNotAdjustEndpoints, |
| 368 isHandleVisible); |
| 352 | 369 |
| 353 return true; | 370 return true; |
| 354 } | 371 } |
| 355 | 372 |
| 356 void SelectionController::selectClosestWordFromHitTestResult( | 373 void SelectionController::selectClosestWordFromHitTestResult( |
| 357 const HitTestResult& result, | 374 const HitTestResult& result, |
| 358 AppendTrailingWhitespace appendTrailingWhitespace, | 375 AppendTrailingWhitespace appendTrailingWhitespace, |
| 359 SelectInputEventType selectInputEventType) { | 376 SelectInputEventType selectInputEventType) { |
| 360 Node* innerNode = result.innerNode(); | 377 Node* innerNode = result.innerNode(); |
| 361 VisibleSelectionInFlatTree newSelection; | 378 VisibleSelectionInFlatTree newSelection; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 372 adjustedHitTestResult.setNodeAndPosition(result.innerNode(), | 389 adjustedHitTestResult.setNodeAndPosition(result.innerNode(), |
| 373 LayoutPoint(0, 0)); | 390 LayoutPoint(0, 0)); |
| 374 | 391 |
| 375 const VisiblePositionInFlatTree& pos = | 392 const VisiblePositionInFlatTree& pos = |
| 376 visiblePositionOfHitTestResult(adjustedHitTestResult); | 393 visiblePositionOfHitTestResult(adjustedHitTestResult); |
| 377 if (pos.isNotNull()) { | 394 if (pos.isNotNull()) { |
| 378 newSelection = createVisibleSelection(pos); | 395 newSelection = createVisibleSelection(pos); |
| 379 newSelection.expandUsingGranularity(WordGranularity); | 396 newSelection.expandUsingGranularity(WordGranularity); |
| 380 } | 397 } |
| 381 | 398 |
| 399 bool isHandleVisible = false; |
| 382 if (selectInputEventType == SelectInputEventType::Touch) { | 400 if (selectInputEventType == SelectInputEventType::Touch) { |
| 383 // If node doesn't have text except space, tab or line break, do not | 401 // If node doesn't have text except space, tab or line break, do not |
| 384 // select that 'empty' area. | 402 // select that 'empty' area. |
| 385 EphemeralRangeInFlatTree range(newSelection.start(), newSelection.end()); | 403 EphemeralRangeInFlatTree range(newSelection.start(), newSelection.end()); |
| 386 const String& str = | 404 const String& str = |
| 387 plainText(range, hasEditableStyle(*innerNode) | 405 plainText(range, hasEditableStyle(*innerNode) |
| 388 ? TextIteratorEmitsObjectReplacementCharacter | 406 ? TextIteratorEmitsObjectReplacementCharacter |
| 389 : TextIteratorDefaultBehavior); | 407 : TextIteratorDefaultBehavior); |
| 390 if (str.isEmpty() || str.simplifyWhiteSpace().containsOnlyWhitespace()) | 408 if (str.isEmpty() || str.simplifyWhiteSpace().containsOnlyWhitespace()) |
| 391 return; | 409 return; |
| 392 | 410 |
| 393 if (newSelection.rootEditableElement() && | 411 if (newSelection.rootEditableElement() && |
| 394 pos.deepEquivalent() == | 412 pos.deepEquivalent() == |
| 395 VisiblePositionInFlatTree::lastPositionInNode( | 413 VisiblePositionInFlatTree::lastPositionInNode( |
| 396 newSelection.rootEditableElement()) | 414 newSelection.rootEditableElement()) |
| 397 .deepEquivalent()) | 415 .deepEquivalent()) |
| 398 return; | 416 return; |
| 417 isHandleVisible = true; |
| 399 } | 418 } |
| 400 | 419 |
| 401 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && | 420 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && |
| 402 newSelection.isRange()) | 421 newSelection.isRange()) |
| 403 newSelection.appendTrailingWhitespace(); | 422 newSelection.appendTrailingWhitespace(); |
| 404 | 423 |
| 405 updateSelectionForMouseDownDispatchingSelectStart( | 424 updateSelectionForMouseDownDispatchingSelectStart( |
| 406 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), | 425 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), |
| 407 WordGranularity); | 426 WordGranularity, isHandleVisible); |
| 408 } | 427 } |
| 409 | 428 |
| 410 void SelectionController::selectClosestMisspellingFromHitTestResult( | 429 void SelectionController::selectClosestMisspellingFromHitTestResult( |
| 411 const HitTestResult& result, | 430 const HitTestResult& result, |
| 412 AppendTrailingWhitespace appendTrailingWhitespace) { | 431 AppendTrailingWhitespace appendTrailingWhitespace) { |
| 413 Node* innerNode = result.innerNode(); | 432 Node* innerNode = result.innerNode(); |
| 414 VisibleSelectionInFlatTree newSelection; | 433 VisibleSelectionInFlatTree newSelection; |
| 415 | 434 |
| 416 if (!innerNode || !innerNode->layoutObject()) | 435 if (!innerNode || !innerNode->layoutObject()) |
| 417 return; | 436 return; |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 return false; | 566 return false; |
| 548 | 567 |
| 549 VisibleSelectionInFlatTree newSelection; | 568 VisibleSelectionInFlatTree newSelection; |
| 550 const VisiblePositionInFlatTree& pos = | 569 const VisiblePositionInFlatTree& pos = |
| 551 visiblePositionOfHitTestResult(event.hitTestResult()); | 570 visiblePositionOfHitTestResult(event.hitTestResult()); |
| 552 if (pos.isNotNull()) { | 571 if (pos.isNotNull()) { |
| 553 newSelection = createVisibleSelection(pos); | 572 newSelection = createVisibleSelection(pos); |
| 554 newSelection.expandUsingGranularity(ParagraphGranularity); | 573 newSelection.expandUsingGranularity(ParagraphGranularity); |
| 555 } | 574 } |
| 556 | 575 |
| 576 bool isHandleVisible = event.event().fromTouch() && newSelection.isRange(); |
| 577 |
| 557 return updateSelectionForMouseDownDispatchingSelectStart( | 578 return updateSelectionForMouseDownDispatchingSelectStart( |
| 558 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), | 579 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), |
| 559 ParagraphGranularity); | 580 ParagraphGranularity, isHandleVisible); |
| 560 } | 581 } |
| 561 | 582 |
| 562 void SelectionController::handleMousePressEvent( | 583 void SelectionController::handleMousePressEvent( |
| 563 const MouseEventWithHitTestResults& event) { | 584 const MouseEventWithHitTestResults& event) { |
| 564 // If we got the event back, that must mean it wasn't prevented, | 585 // If we got the event back, that must mean it wasn't prevented, |
| 565 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. | 586 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. |
| 566 m_mouseDownMayStartSelect = | 587 m_mouseDownMayStartSelect = |
| 567 (canMouseDownStartSelect(event.innerNode()) || isLinkSelection(event)) && | 588 (canMouseDownStartSelect(event.innerNode()) || isLinkSelection(event)) && |
| 568 !event.scrollbar(); | 589 !event.scrollbar(); |
| 569 m_mouseDownWasSingleClickInSelection = false; | 590 m_mouseDownWasSingleClickInSelection = false; |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 pos.deepEquivalent().parentAnchoredEquivalent()), | 764 pos.deepEquivalent().parentAnchoredEquivalent()), |
| 744 DocumentMarker::MisspellingMarkers()) | 765 DocumentMarker::MisspellingMarkers()) |
| 745 .size() > 0; | 766 .size() > 0; |
| 746 } | 767 } |
| 747 | 768 |
| 748 void SelectionController::sendContextMenuEvent( | 769 void SelectionController::sendContextMenuEvent( |
| 749 const MouseEventWithHitTestResults& mev, | 770 const MouseEventWithHitTestResults& mev, |
| 750 const LayoutPoint& position) { | 771 const LayoutPoint& position) { |
| 751 if (!selection().isAvailable()) | 772 if (!selection().isAvailable()) |
| 752 return; | 773 return; |
| 753 if (selection().contains(position) || mev.scrollbar() || | 774 if (selection().contains(mev.hitTestResult()) || mev.scrollbar() || |
| 754 // FIXME: In the editable case, word selection sometimes selects content | 775 // FIXME: In the editable case, word selection sometimes selects content |
| 755 // that isn't underneath the mouse. | 776 // that isn't underneath the mouse. |
| 756 // If the selection is non-editable, we do word selection to make it | 777 // If the selection is non-editable, we do word selection to make it |
| 757 // easier to use the contextual menu items available for text selections. | 778 // easier to use the contextual menu items available for text selections. |
| 758 // But only if we're above text. | 779 // But only if we're above text. |
| 759 !(selection().isContentEditable() || | 780 !(selection().isContentEditable() || |
| 760 (mev.innerNode() && mev.innerNode()->isTextNode()))) | 781 (mev.innerNode() && mev.innerNode()->isTextNode()))) |
| 761 return; | 782 return; |
| 762 | 783 |
| 763 // Context menu events are always allowed to perform a selection. | 784 // Context menu events are always allowed to perform a selection. |
| 764 AutoReset<bool> mouseDownMayStartSelectChange(&m_mouseDownMayStartSelect, | 785 AutoReset<bool> mouseDownMayStartSelectChange(&m_mouseDownMayStartSelect, |
| 765 true); | 786 true); |
| 766 | 787 |
| 767 if (hitTestResultIsMisspelled(mev.hitTestResult())) | 788 if (hitTestResultIsMisspelled(mev.hitTestResult())) |
| 768 return selectClosestMisspellingFromMouseEvent(mev); | 789 return selectClosestMisspellingFromMouseEvent(mev); |
| 769 | 790 |
| 770 if (!m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) | 791 if (!m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) |
| 771 return; | 792 return; |
| 772 | 793 |
| 773 selectClosestWordOrLinkFromMouseEvent(mev); | 794 selectClosestWordOrLinkFromMouseEvent(mev); |
| 774 } | 795 } |
| 775 | 796 |
| 776 void SelectionController::passMousePressEventToSubframe( | 797 void SelectionController::passMousePressEventToSubframe( |
| 777 const MouseEventWithHitTestResults& mev) { | 798 const MouseEventWithHitTestResults& mev) { |
| 778 // If we're clicking into a frame that is selected, the frame will appear | 799 // If we're clicking into a frame that is selected, the frame will appear |
| 779 // greyed out even though we're clicking on the selection. This looks | 800 // greyed out even though we're clicking on the selection. This looks |
| 780 // really strange (having the whole frame be greyed out), so we deselect the | 801 // really strange (having the whole frame be greyed out), so we deselect the |
| 781 // selection. | 802 // selection. |
| 782 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); | 803 if (!selection().contains(mev.hitTestResult())) |
| 783 if (!selection().contains(p)) | |
| 784 return; | 804 return; |
| 785 | 805 |
| 786 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets | 806 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| 787 // needs to be audited. See http://crbug.com/590369 for more details. | 807 // needs to be audited. See http://crbug.com/590369 for more details. |
| 788 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 808 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 789 | 809 |
| 790 const VisiblePositionInFlatTree& visiblePos = | 810 const VisiblePositionInFlatTree& visiblePos = |
| 791 visiblePositionOfHitTestResult(mev.hitTestResult()); | 811 visiblePositionOfHitTestResult(mev.hitTestResult()); |
| 792 VisibleSelectionInFlatTree newSelection = createVisibleSelection(visiblePos); | 812 VisibleSelectionInFlatTree newSelection = createVisibleSelection(visiblePos); |
| 793 selection().setSelection(newSelection); | 813 selection().setSelection(newSelection); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 return event.event().altKey() && event.isOverLink(); | 846 return event.event().altKey() && event.isOverLink(); |
| 827 } | 847 } |
| 828 | 848 |
| 829 bool isExtendingSelection(const MouseEventWithHitTestResults& event) { | 849 bool isExtendingSelection(const MouseEventWithHitTestResults& event) { |
| 830 bool isMouseDownOnLinkOrImage = | 850 bool isMouseDownOnLinkOrImage = |
| 831 event.isOverLink() || event.hitTestResult().image(); | 851 event.isOverLink() || event.hitTestResult().image(); |
| 832 return event.event().shiftKey() && !isMouseDownOnLinkOrImage; | 852 return event.event().shiftKey() && !isMouseDownOnLinkOrImage; |
| 833 } | 853 } |
| 834 | 854 |
| 835 } // namespace blink | 855 } // namespace blink |
| OLD | NEW |