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