| OLD | NEW |
| 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 , m_mouseDownWasSingleClickInSelection(false) | 57 , m_mouseDownWasSingleClickInSelection(false) |
| 58 , m_selectionState(SelectionState::HaveNotStartedSelection) | 58 , m_selectionState(SelectionState::HaveNotStartedSelection) |
| 59 { | 59 { |
| 60 } | 60 } |
| 61 | 61 |
| 62 DEFINE_TRACE(SelectionController) | 62 DEFINE_TRACE(SelectionController) |
| 63 { | 63 { |
| 64 visitor->trace(m_frame); | 64 visitor->trace(m_frame); |
| 65 } | 65 } |
| 66 | 66 |
| 67 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelecti
on& newSelection) | 67 namespace { |
| 68 |
| 69 void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& new
Selection) |
| 68 { | 70 { |
| 69 if (VisibleSelection::InDOMTree::equalSelections(selection.selection(), newS
election)) | 71 if (VisibleSelection::InDOMTree::equalSelections(selection.selection(), newS
election)) |
| 70 return; | 72 return; |
| 71 selection.setSelection(newSelection); | 73 selection.setSelection(newSelection); |
| 72 } | 74 } |
| 73 | 75 |
| 74 static inline bool dispatchSelectStart(Node* node) | 76 bool dispatchSelectStart(Node* node) |
| 75 { | 77 { |
| 76 if (!node || !node->layoutObject()) | 78 if (!node || !node->layoutObject()) |
| 77 return true; | 79 return true; |
| 78 | 80 |
| 79 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::sel
ectstart)); | 81 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::sel
ectstart)); |
| 80 } | 82 } |
| 81 | 83 |
| 82 template <typename Strategy> | 84 template <typename Strategy> |
| 83 VisibleSelection expandSelectionToRespectUserSelectAllAlgorithm(Node* targetNode
, const VisibleSelection& selection) | 85 VisibleSelection expandSelectionToRespectUserSelectAllAlgorithm(Node* targetNode
, const VisibleSelection& selection) |
| 84 { | 86 { |
| 85 using PositionType = typename Strategy::PositionType; | 87 using PositionType = typename Strategy::PositionType; |
| 86 | 88 |
| 87 Node* rootUserSelectAll = PositionType::rootUserSelectAllForNode(targetNode)
; | 89 Node* rootUserSelectAll = PositionType::rootUserSelectAllForNode(targetNode)
; |
| 88 if (!rootUserSelectAll) | 90 if (!rootUserSelectAll) |
| 89 return selection; | 91 return selection; |
| 90 | 92 |
| 91 VisibleSelection newSelection(selection); | 93 VisibleSelection newSelection(selection); |
| 92 newSelection.setBase(PositionType::beforeNode(rootUserSelectAll).upstream(Ca
nCrossEditingBoundary)); | 94 newSelection.setBase(PositionType::beforeNode(rootUserSelectAll).upstream(Ca
nCrossEditingBoundary)); |
| 93 newSelection.setExtent(PositionType::afterNode(rootUserSelectAll).downstream
(CanCrossEditingBoundary)); | 95 newSelection.setExtent(PositionType::afterNode(rootUserSelectAll).downstream
(CanCrossEditingBoundary)); |
| 94 | 96 |
| 95 return newSelection; | 97 return newSelection; |
| 96 } | 98 } |
| 97 | 99 |
| 98 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode,
const VisibleSelection& selection) | 100 VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const V
isibleSelection& selection) |
| 99 { | 101 { |
| 100 if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) | 102 if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
| 101 return expandSelectionToRespectUserSelectAllAlgorithm<VisibleSelection::
InComposedTree>(targetNode, selection); | 103 return expandSelectionToRespectUserSelectAllAlgorithm<VisibleSelection::
InComposedTree>(targetNode, selection); |
| 102 return expandSelectionToRespectUserSelectAllAlgorithm<VisibleSelection::InDO
MTree>(targetNode, selection); | 104 return expandSelectionToRespectUserSelectAllAlgorithm<VisibleSelection::InDO
MTree>(targetNode, selection); |
| 103 } | 105 } |
| 104 | 106 |
| 105 static bool expandSelectionUsingGranularity(VisibleSelection& selection, TextGra
nularity granularity) | 107 bool expandSelectionUsingGranularity(VisibleSelection& selection, TextGranularit
y granularity) |
| 106 { | 108 { |
| 107 if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) | 109 if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
| 108 return selection.expandUsingGranularityInComposedTree(granularity); | 110 return selection.expandUsingGranularityInComposedTree(granularity); |
| 109 return selection.expandUsingGranularity(granularity); | 111 return selection.expandUsingGranularity(granularity); |
| 110 } | 112 } |
| 111 | 113 |
| 114 template <typename PositionType> |
| 115 int textDistance(const PositionType& start, const PositionType& end) |
| 116 { |
| 117 return TextIteratorAlgorithm<typename PositionType::StrategyType>::rangeLeng
th(start, end, true); |
| 118 } |
| 119 |
| 120 bool canMouseDownStartSelect(Node* node) |
| 121 { |
| 122 if (!node || !node->layoutObject()) |
| 123 return true; |
| 124 |
| 125 if (!node->canStartSelection()) |
| 126 return false; |
| 127 |
| 128 return true; |
| 129 } |
| 130 |
| 131 } // namespace |
| 132 |
| 133 template <typename Strategy> |
| 134 bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE
ventWithHitTestResults& event) |
| 135 { |
| 136 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventSingleClick
"); |
| 137 using PositionType = typename Strategy::PositionType; |
| 138 |
| 139 m_frame->document()->updateLayoutIgnorePendingStylesheets(); |
| 140 Node* innerNode = event.innerNode(); |
| 141 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
| 142 return false; |
| 143 |
| 144 // Extend the selection if the Shift key is down, unless the click is in a l
ink. |
| 145 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); |
| 146 |
| 147 // Don't restart the selection when the mouse is pressed on an |
| 148 // existing selection so we can allow for text dragging. |
| 149 if (FrameView* view = m_frame->view()) { |
| 150 LayoutPoint vPoint = view->rootFrameToContents(event.event().position())
; |
| 151 if (!extendSelection && selection().contains(vPoint)) { |
| 152 m_mouseDownWasSingleClickInSelection = true; |
| 153 return false; |
| 154 } |
| 155 } |
| 156 |
| 157 PositionWithAffinity eventPos = innerNode->layoutObject()->positionForPoint(
event.localPoint()); |
| 158 VisiblePosition visiblePos(Strategy::toPositionType(eventPos.position()), ev
entPos.affinity()); |
| 159 if (visiblePos.isNull()) |
| 160 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOW
NSTREAM); |
| 161 PositionType pos = Strategy::toPositionType(visiblePos.deepEquivalent()); |
| 162 |
| 163 VisibleSelection newSelection = selection().selection(); |
| 164 TextGranularity granularity = CharacterGranularity; |
| 165 |
| 166 if (extendSelection && newSelection.isCaretOrRange()) { |
| 167 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSe
lectAll(innerNode, VisibleSelection(VisiblePosition(pos)))); |
| 168 if (selectionInUserSelectAll.isRange()) { |
| 169 if (Strategy::selectionStart(selectionInUserSelectAll).compareTo(Str
ategy::selectionStart(newSelection)) < 0) |
| 170 pos = Strategy::selectionStart(selectionInUserSelectAll); |
| 171 else if (Strategy::selectionEnd(newSelection).compareTo(Strategy::se
lectionEnd(selectionInUserSelectAll)) < 0) |
| 172 pos = Strategy::selectionEnd(selectionInUserSelectAll); |
| 173 } |
| 174 |
| 175 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()
) { |
| 176 if (pos.isNotNull()) { |
| 177 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click d
eselects when selection |
| 178 // was created right-to-left |
| 179 PositionType start = Strategy::selectionStart(newSelection); |
| 180 PositionType end = Strategy::selectionEnd(newSelection); |
| 181 int distanceToStart = textDistance(start, pos); |
| 182 int distanceToEnd = textDistance(pos, end); |
| 183 if (distanceToStart <= distanceToEnd) |
| 184 newSelection = VisibleSelection(end, pos); |
| 185 else |
| 186 newSelection = VisibleSelection(start, pos); |
| 187 } |
| 188 } else { |
| 189 newSelection.setExtent(pos); |
| 190 } |
| 191 |
| 192 if (selection().granularity() != CharacterGranularity) { |
| 193 granularity = selection().granularity(); |
| 194 expandSelectionUsingGranularity(newSelection, selection().granularit
y()); |
| 195 } |
| 196 } else { |
| 197 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleS
election(visiblePos)); |
| 198 } |
| 199 |
| 200 // Updating the selection is considered side-effect of the event and so it d
oesn't impact the handled state. |
| 201 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, g
ranularity); |
| 202 return false; |
| 203 } |
| 204 |
| 205 template <typename Strategy> |
| 206 void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResu
lt& hitTestResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const
IntPoint& lastKnownMousePosition) |
| 207 { |
| 208 using PositionType = typename Strategy::PositionType; |
| 209 |
| 210 if (!m_mouseDownMayStartSelect) |
| 211 return; |
| 212 |
| 213 Node* target = hitTestResult.innerNode(); |
| 214 if (!target) |
| 215 return; |
| 216 |
| 217 PositionWithAffinity rawTargetPosition = selection().selection().positionRes
pectingEditingBoundary(hitTestResult.localPoint(), target); |
| 218 VisiblePosition targetPosition = VisiblePosition(Strategy::toPositionType(ra
wTargetPosition.position()), rawTargetPosition.affinity()); |
| 219 // Don't modify the selection if we're not on a node. |
| 220 if (targetPosition.isNull()) |
| 221 return; |
| 222 |
| 223 // Restart the selection if this is the first mouse move. This work is usual
ly |
| 224 // done in handleMousePressEvent, but not if the mouse press was on an exist
ing selection. |
| 225 VisibleSelection newSelection = selection().selection(); |
| 226 |
| 227 // Special case to limit selection to the containing block for SVG text. |
| 228 // FIXME: Isn't there a better non-SVG-specific way to do this? |
| 229 if (Node* selectionBaseNode = Strategy::selectionBase(newSelection).deprecat
edNode()) { |
| 230 if (LayoutObject* selectionBaseLayoutObject = selectionBaseNode->layoutO
bject()) { |
| 231 if (selectionBaseLayoutObject->isSVGText()) { |
| 232 if (target->layoutObject()->containingBlock() != selectionBaseLa
youtObject->containingBlock()) |
| 233 return; |
| 234 } |
| 235 } |
| 236 } |
| 237 |
| 238 if (m_selectionState == SelectionState::HaveNotStartedSelection && !dispatch
SelectStart(target)) |
| 239 return; |
| 240 |
| 241 if (m_selectionState != SelectionState::ExtendedSelection) { |
| 242 // Always extend selection here because it's caused by a mouse drag |
| 243 m_selectionState = SelectionState::ExtendedSelection; |
| 244 newSelection = VisibleSelection(targetPosition); |
| 245 } |
| 246 |
| 247 if (RuntimeEnabledFeatures::userSelectAllEnabled()) { |
| 248 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllFo
rNode(mousePressNode); |
| 249 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePress
Node == Position::rootUserSelectAllForNode(target)) { |
| 250 newSelection.setBase(PositionType::beforeNode(rootUserSelectAllForMo
usePressNode).upstream(CanCrossEditingBoundary)); |
| 251 newSelection.setExtent(PositionType::afterNode(rootUserSelectAllForM
ousePressNode).downstream(CanCrossEditingBoundary)); |
| 252 } else { |
| 253 // Reset base for user select all when base is inside user-select-al
l area and extent < base. |
| 254 if (rootUserSelectAllForMousePressNode) { |
| 255 PositionType eventPosition = Strategy::toPositionType(target->la
youtObject()->positionForPoint(hitTestResult.localPoint()).position()); |
| 256 PositionType dragStartPosition = Strategy::toPositionType(mouseP
ressNode->layoutObject()->positionForPoint(dragStartPos).position()); |
| 257 if (eventPosition.compareTo(dragStartPosition) < 0) |
| 258 newSelection.setBase(PositionType::afterNode(rootUserSelectA
llForMousePressNode).downstream(CanCrossEditingBoundary)); |
| 259 } |
| 260 |
| 261 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNod
e(target); |
| 262 if (rootUserSelectAllForTarget && mousePressNode->layoutObject() &&
Strategy::toPositionType(target->layoutObject()->positionForPoint(hitTestResult.
localPoint()).position()).compareTo(Strategy::toPositionType(mousePressNode->lay
outObject()->positionForPoint(dragStartPos).position())) < 0) |
| 263 newSelection.setExtent(PositionType::beforeNode(rootUserSelectAl
lForTarget).upstream(CanCrossEditingBoundary)); |
| 264 else if (rootUserSelectAllForTarget && mousePressNode->layoutObject(
)) |
| 265 newSelection.setExtent(PositionType::afterNode(rootUserSelectAll
ForTarget).downstream(CanCrossEditingBoundary)); |
| 266 else |
| 267 newSelection.setExtent(targetPosition); |
| 268 } |
| 269 } else { |
| 270 newSelection.setExtent(targetPosition); |
| 271 } |
| 272 |
| 273 if (selection().granularity() != CharacterGranularity) |
| 274 expandSelectionUsingGranularity(newSelection, selection().granularity())
; |
| 275 |
| 276 selection().setNonDirectionalSelectionIfNeeded(newSelection, selection().gra
nularity(), |
| 277 FrameSelection::AdjustEndpointsAtBidiBoundary); |
| 278 } |
| 279 |
| 112 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node
* targetNode, const VisibleSelection& selection, TextGranularity granularity) | 280 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node
* targetNode, const VisibleSelection& selection, TextGranularity granularity) |
| 113 { | 281 { |
| 114 if (Position::nodeIsUserSelectNone(targetNode)) | 282 if (Position::nodeIsUserSelectNone(targetNode)) |
| 115 return false; | 283 return false; |
| 116 | 284 |
| 117 if (!dispatchSelectStart(targetNode)) | 285 if (!dispatchSelectStart(targetNode)) |
| 118 return false; | 286 return false; |
| 119 | 287 |
| 120 if (selection.isRange()) { | 288 if (selection.isRange()) { |
| 121 m_selectionState = SelectionState::ExtendedSelection; | 289 m_selectionState = SelectionState::ExtendedSelection; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 VisibleSelection newSelection; | 415 VisibleSelection newSelection; |
| 248 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localP
oint())); | 416 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localP
oint())); |
| 249 if (pos.isNotNull()) { | 417 if (pos.isNotNull()) { |
| 250 newSelection = VisibleSelection(pos); | 418 newSelection = VisibleSelection(pos); |
| 251 expandSelectionUsingGranularity(newSelection, ParagraphGranularity); | 419 expandSelectionUsingGranularity(newSelection, ParagraphGranularity); |
| 252 } | 420 } |
| 253 | 421 |
| 254 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe
lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); | 422 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe
lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); |
| 255 } | 423 } |
| 256 | 424 |
| 257 template <typename PositionType> | |
| 258 static int textDistance(const PositionType& start, const PositionType& end) | |
| 259 { | |
| 260 return TextIteratorAlgorithm<typename PositionType::StrategyType>::rangeLeng
th(start, end, true); | |
| 261 } | |
| 262 | |
| 263 bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithH
itTestResults& event) | 425 bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithH
itTestResults& event) |
| 264 { | 426 { |
| 265 if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) | 427 if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
| 266 return handleMousePressEventSingleClickAlgorithm<VisibleSelection::InCom
posedTree>(event); | 428 return handleMousePressEventSingleClickAlgorithm<VisibleSelection::InCom
posedTree>(event); |
| 267 return handleMousePressEventSingleClickAlgorithm<VisibleSelection::InDOMTree
>(event); | 429 return handleMousePressEventSingleClickAlgorithm<VisibleSelection::InDOMTree
>(event); |
| 268 } | 430 } |
| 269 | 431 |
| 270 template <typename Strategy> | |
| 271 bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE
ventWithHitTestResults& event) | |
| 272 { | |
| 273 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventSingleClick
"); | |
| 274 using PositionType = typename Strategy::PositionType; | |
| 275 | |
| 276 m_frame->document()->updateLayoutIgnorePendingStylesheets(); | |
| 277 Node* innerNode = event.innerNode(); | |
| 278 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | |
| 279 return false; | |
| 280 | |
| 281 // Extend the selection if the Shift key is down, unless the click is in a l
ink. | |
| 282 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); | |
| 283 | |
| 284 // Don't restart the selection when the mouse is pressed on an | |
| 285 // existing selection so we can allow for text dragging. | |
| 286 if (FrameView* view = m_frame->view()) { | |
| 287 LayoutPoint vPoint = view->rootFrameToContents(event.event().position())
; | |
| 288 if (!extendSelection && selection().contains(vPoint)) { | |
| 289 m_mouseDownWasSingleClickInSelection = true; | |
| 290 return false; | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 PositionWithAffinity eventPos = innerNode->layoutObject()->positionForPoint(
event.localPoint()); | |
| 295 VisiblePosition visiblePos(Strategy::toPositionType(eventPos.position()), ev
entPos.affinity()); | |
| 296 if (visiblePos.isNull()) | |
| 297 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOW
NSTREAM); | |
| 298 PositionType pos = Strategy::toPositionType(visiblePos.deepEquivalent()); | |
| 299 | |
| 300 VisibleSelection newSelection = selection().selection(); | |
| 301 TextGranularity granularity = CharacterGranularity; | |
| 302 | |
| 303 if (extendSelection && newSelection.isCaretOrRange()) { | |
| 304 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSe
lectAll(innerNode, VisibleSelection(VisiblePosition(pos)))); | |
| 305 if (selectionInUserSelectAll.isRange()) { | |
| 306 if (Strategy::selectionStart(selectionInUserSelectAll).compareTo(Str
ategy::selectionStart(newSelection)) < 0) | |
| 307 pos = Strategy::selectionStart(selectionInUserSelectAll); | |
| 308 else if (Strategy::selectionEnd(newSelection).compareTo(Strategy::se
lectionEnd(selectionInUserSelectAll)) < 0) | |
| 309 pos = Strategy::selectionEnd(selectionInUserSelectAll); | |
| 310 } | |
| 311 | |
| 312 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()
) { | |
| 313 if (pos.isNotNull()) { | |
| 314 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click d
eselects when selection | |
| 315 // was created right-to-left | |
| 316 PositionType start = Strategy::selectionStart(newSelection); | |
| 317 PositionType end = Strategy::selectionEnd(newSelection); | |
| 318 int distanceToStart = textDistance(start, pos); | |
| 319 int distanceToEnd = textDistance(pos, end); | |
| 320 if (distanceToStart <= distanceToEnd) | |
| 321 newSelection = VisibleSelection(end, pos); | |
| 322 else | |
| 323 newSelection = VisibleSelection(start, pos); | |
| 324 } | |
| 325 } else { | |
| 326 newSelection.setExtent(pos); | |
| 327 } | |
| 328 | |
| 329 if (selection().granularity() != CharacterGranularity) { | |
| 330 granularity = selection().granularity(); | |
| 331 expandSelectionUsingGranularity(newSelection, selection().granularit
y()); | |
| 332 } | |
| 333 } else { | |
| 334 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleS
election(visiblePos)); | |
| 335 } | |
| 336 | |
| 337 // Updating the selection is considered side-effect of the event and so it d
oesn't impact the handled state. | |
| 338 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, g
ranularity); | |
| 339 return false; | |
| 340 } | |
| 341 | |
| 342 static inline bool canMouseDownStartSelect(Node* node) | |
| 343 { | |
| 344 if (!node || !node->layoutObject()) | |
| 345 return true; | |
| 346 | |
| 347 if (!node->canStartSelection()) | |
| 348 return false; | |
| 349 | |
| 350 return true; | |
| 351 } | |
| 352 | |
| 353 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul
ts& event) | 432 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul
ts& event) |
| 354 { | 433 { |
| 355 // If we got the event back, that must mean it wasn't prevented, | 434 // If we got the event back, that must mean it wasn't prevented, |
| 356 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. | 435 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. |
| 357 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !e
vent.scrollbar(); | 436 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !e
vent.scrollbar(); |
| 358 m_mouseDownWasSingleClickInSelection = false; | 437 m_mouseDownWasSingleClickInSelection = false; |
| 359 } | 438 } |
| 360 | 439 |
| 361 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes
ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node
* mousePressNode, const IntPoint& lastKnownMousePosition) | 440 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes
ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node
* mousePressNode, const IntPoint& lastKnownMousePosition) |
| 362 { | 441 { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 385 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM
ousePosition); | 464 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM
ousePosition); |
| 386 } | 465 } |
| 387 | 466 |
| 388 void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTe
stResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint&
lastKnownMousePosition) | 467 void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTe
stResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint&
lastKnownMousePosition) |
| 389 { | 468 { |
| 390 if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) | 469 if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
| 391 return updateSelectionForMouseDragAlgorithm<VisibleSelection::InComposed
Tree>(hitTestResult, mousePressNode, dragStartPos, lastKnownMousePosition); | 470 return updateSelectionForMouseDragAlgorithm<VisibleSelection::InComposed
Tree>(hitTestResult, mousePressNode, dragStartPos, lastKnownMousePosition); |
| 392 updateSelectionForMouseDragAlgorithm<VisibleSelection::InDOMTree>(hitTestRes
ult, mousePressNode, dragStartPos, lastKnownMousePosition); | 471 updateSelectionForMouseDragAlgorithm<VisibleSelection::InDOMTree>(hitTestRes
ult, mousePressNode, dragStartPos, lastKnownMousePosition); |
| 393 } | 472 } |
| 394 | 473 |
| 395 template <typename Strategy> | |
| 396 void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResu
lt& hitTestResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const
IntPoint& lastKnownMousePosition) | |
| 397 { | |
| 398 using PositionType = typename Strategy::PositionType; | |
| 399 | |
| 400 if (!m_mouseDownMayStartSelect) | |
| 401 return; | |
| 402 | |
| 403 Node* target = hitTestResult.innerNode(); | |
| 404 if (!target) | |
| 405 return; | |
| 406 | |
| 407 PositionWithAffinity rawTargetPosition = selection().selection().positionRes
pectingEditingBoundary(hitTestResult.localPoint(), target); | |
| 408 VisiblePosition targetPosition = VisiblePosition(Strategy::toPositionType(ra
wTargetPosition.position()), rawTargetPosition.affinity()); | |
| 409 // Don't modify the selection if we're not on a node. | |
| 410 if (targetPosition.isNull()) | |
| 411 return; | |
| 412 | |
| 413 // Restart the selection if this is the first mouse move. This work is usual
ly | |
| 414 // done in handleMousePressEvent, but not if the mouse press was on an exist
ing selection. | |
| 415 VisibleSelection newSelection = selection().selection(); | |
| 416 | |
| 417 // Special case to limit selection to the containing block for SVG text. | |
| 418 // FIXME: Isn't there a better non-SVG-specific way to do this? | |
| 419 if (Node* selectionBaseNode = Strategy::selectionBase(newSelection).deprecat
edNode()) { | |
| 420 if (LayoutObject* selectionBaseLayoutObject = selectionBaseNode->layoutO
bject()) { | |
| 421 if (selectionBaseLayoutObject->isSVGText()) { | |
| 422 if (target->layoutObject()->containingBlock() != selectionBaseLa
youtObject->containingBlock()) | |
| 423 return; | |
| 424 } | |
| 425 } | |
| 426 } | |
| 427 | |
| 428 if (m_selectionState == SelectionState::HaveNotStartedSelection && !dispatch
SelectStart(target)) | |
| 429 return; | |
| 430 | |
| 431 if (m_selectionState != SelectionState::ExtendedSelection) { | |
| 432 // Always extend selection here because it's caused by a mouse drag | |
| 433 m_selectionState = SelectionState::ExtendedSelection; | |
| 434 newSelection = VisibleSelection(targetPosition); | |
| 435 } | |
| 436 | |
| 437 if (RuntimeEnabledFeatures::userSelectAllEnabled()) { | |
| 438 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllFo
rNode(mousePressNode); | |
| 439 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePress
Node == Position::rootUserSelectAllForNode(target)) { | |
| 440 newSelection.setBase(PositionType::beforeNode(rootUserSelectAllForMo
usePressNode).upstream(CanCrossEditingBoundary)); | |
| 441 newSelection.setExtent(PositionType::afterNode(rootUserSelectAllForM
ousePressNode).downstream(CanCrossEditingBoundary)); | |
| 442 } else { | |
| 443 // Reset base for user select all when base is inside user-select-al
l area and extent < base. | |
| 444 if (rootUserSelectAllForMousePressNode) { | |
| 445 PositionType eventPosition = Strategy::toPositionType(target->la
youtObject()->positionForPoint(hitTestResult.localPoint()).position()); | |
| 446 PositionType dragStartPosition = Strategy::toPositionType(mouseP
ressNode->layoutObject()->positionForPoint(dragStartPos).position()); | |
| 447 if (eventPosition.compareTo(dragStartPosition) < 0) | |
| 448 newSelection.setBase(PositionType::afterNode(rootUserSelectA
llForMousePressNode).downstream(CanCrossEditingBoundary)); | |
| 449 } | |
| 450 | |
| 451 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNod
e(target); | |
| 452 if (rootUserSelectAllForTarget && mousePressNode->layoutObject() &&
Strategy::toPositionType(target->layoutObject()->positionForPoint(hitTestResult.
localPoint()).position()).compareTo(Strategy::toPositionType(mousePressNode->lay
outObject()->positionForPoint(dragStartPos).position())) < 0) | |
| 453 newSelection.setExtent(PositionType::beforeNode(rootUserSelectAl
lForTarget).upstream(CanCrossEditingBoundary)); | |
| 454 else if (rootUserSelectAllForTarget && mousePressNode->layoutObject(
)) | |
| 455 newSelection.setExtent(PositionType::afterNode(rootUserSelectAll
ForTarget).downstream(CanCrossEditingBoundary)); | |
| 456 else | |
| 457 newSelection.setExtent(targetPosition); | |
| 458 } | |
| 459 } else { | |
| 460 newSelection.setExtent(targetPosition); | |
| 461 } | |
| 462 | |
| 463 if (selection().granularity() != CharacterGranularity) | |
| 464 expandSelectionUsingGranularity(newSelection, selection().granularity())
; | |
| 465 | |
| 466 selection().setNonDirectionalSelectionIfNeeded(newSelection, selection().gra
nularity(), | |
| 467 FrameSelection::AdjustEndpointsAtBidiBoundary); | |
| 468 } | |
| 469 | |
| 470 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes
ults& event, const LayoutPoint& dragStartPos) | 474 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes
ults& event, const LayoutPoint& dragStartPos) |
| 471 { | 475 { |
| 472 bool handled = false; | 476 bool handled = false; |
| 473 m_mouseDownMayStartSelect = false; | 477 m_mouseDownMayStartSelect = false; |
| 474 // Clear the selection if the mouse didn't move after the last mouse | 478 // Clear the selection if the mouse didn't move after the last mouse |
| 475 // press and it's not a context menu click. We do this so when clicking | 479 // press and it's not a context menu click. We do this so when clicking |
| 476 // on the selection, the selection goes away. However, if we are | 480 // on the selection, the selection goes away. However, if we are |
| 477 // editing, place the caret. | 481 // editing, place the caret. |
| 478 if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionSta
te::ExtendedSelection | 482 if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionSta
te::ExtendedSelection |
| 479 && dragStartPos == event.event().position() | 483 && dragStartPos == event.event().position() |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 613 { | 617 { |
| 614 return m_mouseDownWasSingleClickInSelection; | 618 return m_mouseDownWasSingleClickInSelection; |
| 615 } | 619 } |
| 616 | 620 |
| 617 FrameSelection& SelectionController::selection() const | 621 FrameSelection& SelectionController::selection() const |
| 618 { | 622 { |
| 619 return m_frame->selection(); | 623 return m_frame->selection(); |
| 620 } | 624 } |
| 621 | 625 |
| 622 } // namespace blink | 626 } // namespace blink |
| OLD | NEW |