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 |