Chromium Code Reviews| 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 28 matching lines...) Expand all Loading... | |
| 39 #include "core/events/Event.h" | 39 #include "core/events/Event.h" |
| 40 #include "core/frame/FrameView.h" | 40 #include "core/frame/FrameView.h" |
| 41 #include "core/frame/LocalFrame.h" | 41 #include "core/frame/LocalFrame.h" |
| 42 #include "core/frame/Settings.h" | 42 #include "core/frame/Settings.h" |
| 43 #include "core/layout/LayoutView.h" | 43 #include "core/layout/LayoutView.h" |
| 44 #include "core/page/FocusController.h" | 44 #include "core/page/FocusController.h" |
| 45 #include "core/page/Page.h" | 45 #include "core/page/Page.h" |
| 46 #include "platform/RuntimeEnabledFeatures.h" | 46 #include "platform/RuntimeEnabledFeatures.h" |
| 47 | 47 |
| 48 namespace blink { | 48 namespace blink { |
| 49 PassOwnPtrWillBeRawPtr<SelectionController> SelectionController::create(LocalFra me& frame) | 49 |
| 50 namespace { | |
| 51 | |
| 52 void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& new Selection) | |
| 50 { | 53 { |
| 51 return adoptPtrWillBeNoop(new SelectionController(frame)); | 54 if (selection.selection() == newSelection) |
| 55 return; | |
| 56 selection.setSelection(newSelection); | |
| 52 } | 57 } |
| 53 | 58 |
| 54 SelectionController::SelectionController(LocalFrame& frame) | 59 bool dispatchSelectStart(Node* node) |
| 55 : m_frame(&frame) | |
| 56 , m_mouseDownMayStartSelect(false) | |
| 57 , m_mouseDownWasSingleClickInSelection(false) | |
| 58 , m_selectionInitiationState(HaveNotStartedSelection) | |
| 59 { | |
| 60 } | |
| 61 | |
| 62 DEFINE_TRACE(SelectionController) | |
| 63 { | |
| 64 visitor->trace(m_frame); | |
| 65 } | |
| 66 | |
| 67 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelecti on& newSelection) | |
| 68 { | |
| 69 if (selection.selection() != newSelection) | |
| 70 selection.setSelection(newSelection); | |
| 71 } | |
| 72 | |
| 73 static inline bool dispatchSelectStart(Node* node) | |
| 74 { | 60 { |
| 75 if (!node || !node->layoutObject()) | 61 if (!node || !node->layoutObject()) |
| 76 return true; | 62 return true; |
| 77 | 63 |
| 78 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::sel ectstart)); | 64 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::sel ectstart)); |
| 79 } | 65 } |
| 80 | 66 |
| 81 template <typename Strategy> | 67 template <typename Strategy> |
| 82 VisibleSelection expandSelectionToRespectUserSelectAllAlgorithm(Node* targetNode , const VisibleSelection& selection) | 68 VisibleSelection expandSelectionToRespectUserSelectAllAlgorithm(Node* targetNode , const VisibleSelection& selection) |
| 83 { | 69 { |
| 84 using PositionType = typename Strategy::PositionType; | 70 using PositionType = typename Strategy::PositionType; |
| 85 | 71 |
| 86 Node* rootUserSelectAll = PositionType::rootUserSelectAllForNode(targetNode) ; | 72 Node* rootUserSelectAll = PositionType::rootUserSelectAllForNode(targetNode) ; |
| 87 if (!rootUserSelectAll) | 73 if (!rootUserSelectAll) |
| 88 return selection; | 74 return selection; |
| 89 | 75 |
| 90 VisibleSelection newSelection(selection); | 76 VisibleSelection newSelection(selection); |
| 91 newSelection.setBase(PositionType::beforeNode(rootUserSelectAll).upstream(Ca nCrossEditingBoundary)); | 77 newSelection.setBase(PositionType::beforeNode(rootUserSelectAll).upstream(Ca nCrossEditingBoundary)); |
| 92 newSelection.setExtent(PositionType::afterNode(rootUserSelectAll).downstream (CanCrossEditingBoundary)); | 78 newSelection.setExtent(PositionType::afterNode(rootUserSelectAll).downstream (CanCrossEditingBoundary)); |
| 93 | 79 |
| 94 return newSelection; | 80 return newSelection; |
| 95 } | 81 } |
| 96 | 82 |
| 97 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) | 83 VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const V isibleSelection& selection) |
| 98 { | 84 { |
| 99 return expandSelectionToRespectUserSelectAllAlgorithm<VisibleSelection::InDO MTree>(targetNode, selection); | 85 return expandSelectionToRespectUserSelectAllAlgorithm<VisibleSelection::InDO MTree>(targetNode, selection); |
| 100 } | 86 } |
| 101 | 87 |
| 102 static bool expandSelectionUsingGranularity(VisibleSelection& selection, TextGra nularity granularity) | 88 bool expandSelectionUsingGranularity(VisibleSelection& selection, TextGranularit y granularity) |
| 103 { | 89 { |
| 104 return selection.expandUsingGranularity(granularity); | 90 return selection.expandUsingGranularity(granularity); |
| 105 } | 91 } |
| 106 | 92 |
| 107 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node * targetNode, const VisibleSelection& selection, TextGranularity granularity) | 93 int textDistance(const Position& start, const Position& end) |
|
yosin_UTC9
2015/06/22 05:31:11
textDistance() is also templatized in ToT. Could y
Miyoung Shin(c)
2015/06/24 07:43:27
Ok.
| |
| 108 { | 94 { |
| 109 if (Position::nodeIsUserSelectNone(targetNode)) | 95 return TextIterator::rangeLength(start, end, true); |
| 96 } | |
| 97 | |
| 98 bool canMouseDownStartSelect(Node* node) | |
| 99 { | |
| 100 if (!node || !node->layoutObject()) | |
| 101 return true; | |
| 102 | |
| 103 if (!node->canStartSelection()) | |
| 110 return false; | 104 return false; |
| 111 | 105 |
| 112 if (!dispatchSelectStart(targetNode)) | |
| 113 return false; | |
| 114 | |
| 115 if (selection.isRange()) { | |
| 116 m_selectionInitiationState = ExtendedSelection; | |
| 117 } else { | |
| 118 granularity = CharacterGranularity; | |
| 119 m_selectionInitiationState = PlacedCaret; | |
| 120 } | |
| 121 | |
| 122 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granulari ty); | |
| 123 | |
| 124 return true; | 106 return true; |
| 125 } | 107 } |
| 126 | 108 |
| 127 void SelectionController::selectClosestWordFromHitTestResult(const HitTestResult & result, AppendTrailingWhitespace appendTrailingWhitespace) | 109 } // namespace |
| 128 { | |
| 129 Node* innerNode = result.innerNode(); | |
| 130 VisibleSelection newSelection; | |
| 131 | |
| 132 if (innerNode && innerNode->layoutObject()) { | |
| 133 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); | |
| 134 if (pos.isNotNull()) { | |
| 135 newSelection = VisibleSelection(pos); | |
| 136 expandSelectionUsingGranularity(newSelection, WordGranularity); | |
| 137 } | |
| 138 | |
| 139 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSel ection.isRange()) | |
| 140 newSelection.appendTrailingWhitespace(); | |
| 141 | |
| 142 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 void SelectionController::selectClosestMisspellingFromHitTestResult(const HitTes tResult& result, AppendTrailingWhitespace appendTrailingWhitespace) | |
| 147 { | |
| 148 Node* innerNode = result.innerNode(); | |
| 149 VisibleSelection newSelection; | |
| 150 | |
| 151 if (innerNode && innerNode->layoutObject()) { | |
| 152 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); | |
| 153 Position start = pos.deepEquivalent(); | |
| 154 Position end = pos.deepEquivalent(); | |
| 155 if (pos.isNotNull()) { | |
| 156 DocumentMarkerVector markers = innerNode->document().markers().marke rsInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers()); | |
| 157 if (markers.size() == 1) { | |
| 158 start.moveToOffset(markers[0]->startOffset()); | |
| 159 end.moveToOffset(markers[0]->endOffset()); | |
| 160 newSelection = VisibleSelection(start, end); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSel ection.isRange()) | |
| 165 newSelection.appendTrailingWhitespace(); | |
| 166 | |
| 167 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 void SelectionController::selectClosestWordFromMouseEvent(const MouseEventWithHi tTestResults& result) | |
| 172 { | |
| 173 if (m_mouseDownMayStartSelect) { | |
| 174 selectClosestWordFromHitTestResult(result.hitTestResult(), | |
| 175 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhi tespace); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 void SelectionController::selectClosestMisspellingFromMouseEvent(const MouseEven tWithHitTestResults& result) | |
| 180 { | |
| 181 if (m_mouseDownMayStartSelect) { | |
| 182 selectClosestMisspellingFromHitTestResult(result.hitTestResult(), | |
| 183 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhi tespace); | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 void SelectionController::selectClosestWordOrLinkFromMouseEvent(const MouseEvent WithHitTestResults& result) | |
| 188 { | |
| 189 if (!result.hitTestResult().isLiveLink()) | |
| 190 return selectClosestWordFromMouseEvent(result); | |
| 191 | |
| 192 Node* innerNode = result.innerNode(); | |
| 193 | |
| 194 if (innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect) { | |
| 195 VisibleSelection newSelection; | |
| 196 Element* URLElement = result.hitTestResult().URLElement(); | |
| 197 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); | |
| 198 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescenda ntOf(URLElement)) | |
| 199 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElem ent); | |
| 200 | |
| 201 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH itTestResults& event) | |
| 206 { | |
| 207 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick "); | |
| 208 | |
| 209 if (event.event().button() != LeftButton) | |
| 210 return false; | |
| 211 | |
| 212 if (m_frame->selection().isRange()) { | |
| 213 // A double-click when range is already selected | |
| 214 // should not change the selection. So, do not call | |
| 215 // selectClosestWordFromMouseEvent, but do set | |
| 216 // m_beganSelectingText to prevent handleMouseReleaseEvent | |
| 217 // from setting caret selection. | |
| 218 m_selectionInitiationState = ExtendedSelection; | |
| 219 } else { | |
| 220 selectClosestWordFromMouseEvent(event); | |
| 221 } | |
| 222 return true; | |
| 223 } | |
| 224 | |
| 225 bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH itTestResults& event) | |
| 226 { | |
| 227 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick "); | |
| 228 | |
| 229 if (event.event().button() != LeftButton) | |
| 230 return false; | |
| 231 | |
| 232 Node* innerNode = event.innerNode(); | |
| 233 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | |
| 234 return false; | |
| 235 | |
| 236 VisibleSelection newSelection; | |
| 237 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localP oint())); | |
| 238 if (pos.isNotNull()) { | |
| 239 newSelection = VisibleSelection(pos); | |
| 240 expandSelectionUsingGranularity(newSelection, ParagraphGranularity); | |
| 241 } | |
| 242 | |
| 243 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); | |
| 244 } | |
| 245 | |
| 246 static int textDistance(const Position& start, const Position& end) | |
| 247 { | |
| 248 return TextIterator::rangeLength(start, end, true); | |
| 249 } | |
| 250 | |
| 251 bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithH itTestResults& event) | |
| 252 { | |
| 253 return handleMousePressEventSingleClickAlgorithm<VisibleSelection::InDOMTree >(event); | |
| 254 } | |
| 255 | 110 |
| 256 template <typename Strategy> | 111 template <typename Strategy> |
| 257 bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE ventWithHitTestResults& event) | 112 bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE ventWithHitTestResults& event) |
| 258 { | 113 { |
| 259 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventSingleClick "); | 114 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventSingleClick "); |
| 260 using PositionType = typename Strategy::PositionType; | 115 using PositionType = typename Strategy::PositionType; |
| 261 | 116 |
| 262 m_frame->document()->updateLayoutIgnorePendingStylesheets(); | 117 m_frame->document()->updateLayoutIgnorePendingStylesheets(); |
| 263 Node* innerNode = event.innerNode(); | 118 Node* innerNode = event.innerNode(); |
| 264 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | 119 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
| 265 return false; | 120 return false; |
| 266 | 121 |
| 267 // Extend the selection if the Shift key is down, unless the click is in a l ink. | 122 // Extend the selection if the Shift key is down, unless the click is in a l ink. |
| 268 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); | 123 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); |
| 269 | 124 |
| 270 // Don't restart the selection when the mouse is pressed on an | 125 // Don't restart the selection when the mouse is pressed on an |
| 271 // existing selection so we can allow for text dragging. | 126 // existing selection so we can allow for text dragging. |
| 272 if (FrameView* view = m_frame->view()) { | 127 if (FrameView* view = m_frame->view()) { |
| 273 LayoutPoint vPoint = view->rootFrameToContents(event.event().position()) ; | 128 LayoutPoint vPoint = view->rootFrameToContents(event.event().position()) ; |
| 274 if (!extendSelection && m_frame->selection().contains(vPoint)) { | 129 if (!extendSelection && selection().contains(vPoint)) { |
| 275 m_mouseDownWasSingleClickInSelection = true; | 130 m_mouseDownWasSingleClickInSelection = true; |
| 276 return false; | 131 return false; |
| 277 } | 132 } |
| 278 } | 133 } |
| 279 | 134 |
| 280 VisiblePosition visiblePos(innerNode->layoutObject()->positionForPoint(event .localPoint())); | 135 VisiblePosition visiblePos(innerNode->layoutObject()->positionForPoint(event .localPoint())); |
| 281 if (visiblePos.isNull()) | 136 if (visiblePos.isNull()) |
| 282 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOW NSTREAM); | 137 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOW NSTREAM); |
| 283 PositionType pos = Strategy::toPositionType(visiblePos.deepEquivalent()); | 138 PositionType pos = Strategy::toPositionType(visiblePos.deepEquivalent()); |
| 284 | 139 |
| 285 VisibleSelection newSelection = m_frame->selection().selection(); | 140 VisibleSelection newSelection = selection().selection(); |
| 286 TextGranularity granularity = CharacterGranularity; | 141 TextGranularity granularity = CharacterGranularity; |
| 287 | 142 |
| 288 if (extendSelection && newSelection.isCaretOrRange()) { | 143 if (extendSelection && newSelection.isCaretOrRange()) { |
| 289 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSe lectAll(innerNode, VisibleSelection(VisiblePosition(pos)))); | 144 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSe lectAll(innerNode, VisibleSelection(VisiblePosition(pos)))); |
| 290 if (selectionInUserSelectAll.isRange()) { | 145 if (selectionInUserSelectAll.isRange()) { |
| 291 if (Strategy::selectionStart(selectionInUserSelectAll).compareTo(Str ategy::selectionStart(newSelection)) < 0) | 146 if (Strategy::selectionStart(selectionInUserSelectAll).compareTo(Str ategy::selectionStart(newSelection)) < 0) |
| 292 pos = Strategy::selectionStart(selectionInUserSelectAll); | 147 pos = Strategy::selectionStart(selectionInUserSelectAll); |
| 293 else if (Strategy::selectionEnd(newSelection).compareTo(Strategy::se lectionEnd(selectionInUserSelectAll)) < 0) | 148 else if (Strategy::selectionEnd(newSelection).compareTo(Strategy::se lectionEnd(selectionInUserSelectAll)) < 0) |
| 294 pos = Strategy::selectionEnd(selectionInUserSelectAll); | 149 pos = Strategy::selectionEnd(selectionInUserSelectAll); |
| 295 } | 150 } |
| 296 | 151 |
| 297 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional() ) { | 152 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional() ) { |
| 298 if (pos.isNotNull()) { | 153 if (pos.isNotNull()) { |
| 299 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click d eselects when selection | 154 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click d eselects when selection |
| 300 // was created right-to-left | 155 // was created right-to-left |
| 301 PositionType start = Strategy::selectionStart(newSelection); | 156 PositionType start = Strategy::selectionStart(newSelection); |
| 302 PositionType end = Strategy::selectionEnd(newSelection); | 157 PositionType end = Strategy::selectionEnd(newSelection); |
| 303 int distanceToStart = textDistance(start, pos); | 158 int distanceToStart = textDistance(start, pos); |
| 304 int distanceToEnd = textDistance(pos, end); | 159 int distanceToEnd = textDistance(pos, end); |
| 305 if (distanceToStart <= distanceToEnd) | 160 if (distanceToStart <= distanceToEnd) |
| 306 newSelection = VisibleSelection(end, pos); | 161 newSelection = VisibleSelection(end, pos); |
| 307 else | 162 else |
| 308 newSelection = VisibleSelection(start, pos); | 163 newSelection = VisibleSelection(start, pos); |
| 309 } | 164 } |
| 310 } else { | 165 } else { |
| 311 newSelection.setExtent(pos); | 166 newSelection.setExtent(pos); |
| 312 } | 167 } |
| 313 | 168 |
| 314 if (m_frame->selection().granularity() != CharacterGranularity) { | 169 if (selection().granularity() != CharacterGranularity) { |
| 315 granularity = m_frame->selection().granularity(); | 170 granularity = selection().granularity(); |
| 316 expandSelectionUsingGranularity(newSelection, m_frame->selection().g ranularity()); | 171 expandSelectionUsingGranularity(newSelection, selection().granularit y()); |
| 317 } | 172 } |
| 318 } else { | 173 } else { |
| 319 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleS election(visiblePos)); | 174 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleS election(visiblePos)); |
| 320 } | 175 } |
| 321 | 176 |
| 322 // Updating the selection is considered side-effect of the event and so it d oesn't impact the handled state. | 177 // Updating the selection is considered side-effect of the event and so it d oesn't impact the handled state. |
| 323 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, g ranularity); | 178 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, g ranularity); |
| 324 return false; | 179 return false; |
| 325 } | 180 } |
| 326 | 181 |
| 327 static inline bool canMouseDownStartSelect(Node* node) | |
| 328 { | |
| 329 if (!node || !node->layoutObject()) | |
| 330 return true; | |
| 331 | |
| 332 if (!node->canStartSelection()) | |
| 333 return false; | |
| 334 | |
| 335 return true; | |
| 336 } | |
| 337 | |
| 338 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul ts& event) | |
| 339 { | |
| 340 // If we got the event back, that must mean it wasn't prevented, | |
| 341 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. | |
| 342 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !e vent.scrollbar(); | |
| 343 m_mouseDownWasSingleClickInSelection = false; | |
| 344 } | |
| 345 | |
| 346 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node * mousePressNode, const IntPoint& lastKnownMousePosition) | |
| 347 { | |
| 348 if (m_selectionInitiationState != ExtendedSelection) { | |
| 349 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active ); | |
| 350 HitTestResult result(request, mouseDownPos); | |
| 351 m_frame->document()->layoutView()->hitTest(result); | |
| 352 | |
| 353 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKn ownMousePosition); | |
| 354 } | |
| 355 updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStart Pos, lastKnownMousePosition); | |
| 356 } | |
| 357 | |
| 358 void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, cons t LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) | |
| 359 { | |
| 360 FrameView* view = m_frame->view(); | |
| 361 if (!view) | |
| 362 return; | |
| 363 LayoutView* layoutObject = m_frame->contentLayoutObject(); | |
| 364 if (!layoutObject) | |
| 365 return; | |
| 366 | |
| 367 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move); | |
| 368 HitTestResult result(request, view->rootFrameToContents(lastKnownMousePositi on)); | |
| 369 layoutObject->hitTest(result); | |
| 370 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM ousePosition); | |
| 371 } | |
| 372 | |
| 373 void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTe stResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) | |
| 374 { | |
| 375 updateSelectionForMouseDragAlgorithm<VisibleSelection::InDOMTree>(hitTestRes ult, mousePressNode, dragStartPos, lastKnownMousePosition); | |
| 376 } | |
| 377 | |
| 378 template <typename Strategy> | 182 template <typename Strategy> |
| 379 void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResu lt& hitTestResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) | 183 void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResu lt& hitTestResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) |
| 380 { | 184 { |
| 381 using PositionType = typename Strategy::PositionType; | 185 using PositionType = typename Strategy::PositionType; |
| 382 | 186 |
| 383 if (!m_mouseDownMayStartSelect) | 187 if (!m_mouseDownMayStartSelect) |
| 384 return; | 188 return; |
| 385 | 189 |
| 386 Node* target = hitTestResult.innerNode(); | 190 Node* target = hitTestResult.innerNode(); |
| 387 if (!target) | 191 if (!target) |
| 388 return; | 192 return; |
| 389 | 193 |
| 390 VisiblePosition targetPosition = m_frame->selection().selection().visiblePos itionRespectingEditingBoundary(hitTestResult.localPoint(), target); | 194 VisiblePosition targetPosition = selection().selection().visiblePositionResp ectingEditingBoundary(hitTestResult.localPoint(), target); |
| 391 // Don't modify the selection if we're not on a node. | 195 // Don't modify the selection if we're not on a node. |
| 392 if (targetPosition.isNull()) | 196 if (targetPosition.isNull()) |
| 393 return; | 197 return; |
| 394 | 198 |
| 395 // Restart the selection if this is the first mouse move. This work is usual ly | 199 // Restart the selection if this is the first mouse move. This work is usual ly |
| 396 // done in handleMousePressEvent, but not if the mouse press was on an exist ing selection. | 200 // done in handleMousePressEvent, but not if the mouse press was on an exist ing selection. |
| 397 VisibleSelection newSelection = m_frame->selection().selection(); | 201 VisibleSelection newSelection = selection().selection(); |
| 398 | 202 |
| 399 // Special case to limit selection to the containing block for SVG text. | 203 // Special case to limit selection to the containing block for SVG text. |
| 400 // FIXME: Isn't there a better non-SVG-specific way to do this? | 204 // FIXME: Isn't there a better non-SVG-specific way to do this? |
| 401 if (Node* selectionBaseNode = Strategy::selectionBase(newSelection).deprecat edNode()) { | 205 if (Node* selectionBaseNode = Strategy::selectionBase(newSelection).deprecat edNode()) { |
| 402 if (LayoutObject* selectionBaseLayoutObject = selectionBaseNode->layoutO bject()) { | 206 if (LayoutObject* selectionBaseLayoutObject = selectionBaseNode->layoutO bject()) { |
| 403 if (selectionBaseLayoutObject->isSVGText()) { | 207 if (selectionBaseLayoutObject->isSVGText()) { |
| 404 if (target->layoutObject()->containingBlock() != selectionBaseLa youtObject->containingBlock()) | 208 if (target->layoutObject()->containingBlock() != selectionBaseLa youtObject->containingBlock()) |
| 405 return; | 209 return; |
| 406 } | 210 } |
| 407 } | 211 } |
| 408 } | 212 } |
| 409 | 213 |
| 410 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelect Start(target)) | 214 if (m_selectionState == SelectionState::HaveNotStartedSelection && !dispatch SelectStart(target)) |
| 411 return; | 215 return; |
| 412 | 216 |
| 413 if (m_selectionInitiationState != ExtendedSelection) { | 217 if (m_selectionState != SelectionState::ExtendedSelection) { |
| 414 // Always extend selection here because it's caused by a mouse drag | 218 // Always extend selection here because it's caused by a mouse drag |
| 415 m_selectionInitiationState = ExtendedSelection; | 219 m_selectionState = SelectionState::ExtendedSelection; |
| 416 newSelection = VisibleSelection(targetPosition); | 220 newSelection = VisibleSelection(targetPosition); |
| 417 } | 221 } |
| 418 | 222 |
| 419 if (RuntimeEnabledFeatures::userSelectAllEnabled()) { | 223 if (RuntimeEnabledFeatures::userSelectAllEnabled()) { |
| 420 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllFo rNode(mousePressNode); | 224 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllFo rNode(mousePressNode); |
| 421 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePress Node == Position::rootUserSelectAllForNode(target)) { | 225 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePress Node == Position::rootUserSelectAllForNode(target)) { |
| 422 newSelection.setBase(PositionType::beforeNode(rootUserSelectAllForMo usePressNode).upstream(CanCrossEditingBoundary)); | 226 newSelection.setBase(PositionType::beforeNode(rootUserSelectAllForMo usePressNode).upstream(CanCrossEditingBoundary)); |
| 423 newSelection.setExtent(PositionType::afterNode(rootUserSelectAllForM ousePressNode).downstream(CanCrossEditingBoundary)); | 227 newSelection.setExtent(PositionType::afterNode(rootUserSelectAllForM ousePressNode).downstream(CanCrossEditingBoundary)); |
| 424 } else { | 228 } else { |
| 425 // Reset base for user select all when base is inside user-select-al l area and extent < base. | 229 // Reset base for user select all when base is inside user-select-al l area and extent < base. |
| 426 if (rootUserSelectAllForMousePressNode) { | 230 if (rootUserSelectAllForMousePressNode) { |
| 427 PositionType eventPosition = Strategy::toPositionType(target->la youtObject()->positionForPoint(hitTestResult.localPoint()).position()); | 231 PositionType eventPosition = Strategy::toPositionType(target->la youtObject()->positionForPoint(hitTestResult.localPoint()).position()); |
| 428 PositionType dragStartPosition = Strategy::toPositionType(mouseP ressNode->layoutObject()->positionForPoint(dragStartPos).position()); | 232 PositionType dragStartPosition = Strategy::toPositionType(mouseP ressNode->layoutObject()->positionForPoint(dragStartPos).position()); |
| 429 if (eventPosition.compareTo(dragStartPosition) < 0) | 233 if (eventPosition.compareTo(dragStartPosition) < 0) |
| 430 newSelection.setBase(PositionType::afterNode(rootUserSelectA llForMousePressNode).downstream(CanCrossEditingBoundary)); | 234 newSelection.setBase(PositionType::afterNode(rootUserSelectA llForMousePressNode).downstream(CanCrossEditingBoundary)); |
| 431 } | 235 } |
| 432 | 236 |
| 433 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNod e(target); | 237 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNod e(target); |
| 434 if (rootUserSelectAllForTarget && mousePressNode->layoutObject() && Strategy::toPositionType(target->layoutObject()->positionForPoint(hitTestResult. localPoint()).position()).compareTo(Strategy::toPositionType(mousePressNode->lay outObject()->positionForPoint(dragStartPos).position())) < 0) | 238 if (rootUserSelectAllForTarget && mousePressNode->layoutObject() && Strategy::toPositionType(target->layoutObject()->positionForPoint(hitTestResult. localPoint()).position()).compareTo(Strategy::toPositionType(mousePressNode->lay outObject()->positionForPoint(dragStartPos).position())) < 0) |
| 435 newSelection.setExtent(PositionType::beforeNode(rootUserSelectAl lForTarget).upstream(CanCrossEditingBoundary)); | 239 newSelection.setExtent(PositionType::beforeNode(rootUserSelectAl lForTarget).upstream(CanCrossEditingBoundary)); |
| 436 else if (rootUserSelectAllForTarget && mousePressNode->layoutObject( )) | 240 else if (rootUserSelectAllForTarget && mousePressNode->layoutObject( )) |
| 437 newSelection.setExtent(PositionType::afterNode(rootUserSelectAll ForTarget).downstream(CanCrossEditingBoundary)); | 241 newSelection.setExtent(PositionType::afterNode(rootUserSelectAll ForTarget).downstream(CanCrossEditingBoundary)); |
| 438 else | 242 else |
| 439 newSelection.setExtent(targetPosition); | 243 newSelection.setExtent(targetPosition); |
| 440 } | 244 } |
| 441 } else { | 245 } else { |
| 442 newSelection.setExtent(targetPosition); | 246 newSelection.setExtent(targetPosition); |
| 443 } | 247 } |
| 444 | 248 |
| 445 if (m_frame->selection().granularity() != CharacterGranularity) | 249 if (selection().granularity() != CharacterGranularity) |
| 446 expandSelectionUsingGranularity(newSelection, m_frame->selection().granu larity()); | 250 expandSelectionUsingGranularity(newSelection, selection().granularity()) ; |
| 447 | 251 |
| 448 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_fram e->selection().granularity(), | 252 selection().setNonDirectionalSelectionIfNeeded(newSelection, selection().gra nularity(), |
| 449 FrameSelection::AdjustEndpointsAtBidiBoundary); | 253 FrameSelection::AdjustEndpointsAtBidiBoundary); |
| 450 } | 254 } |
| 451 | 255 |
| 256 PassOwnPtrWillBeRawPtr<SelectionController> SelectionController::create(LocalFra me& frame) | |
|
yosin_UTC9
2015/06/22 05:31:10
Let's keep original source code location for them
Miyoung Shin(c)
2015/06/24 07:43:27
when picking up template codes, it looks like thes
| |
| 257 { | |
| 258 return adoptPtrWillBeNoop(new SelectionController(frame)); | |
| 259 } | |
| 260 | |
| 261 SelectionController::SelectionController(LocalFrame& frame) | |
| 262 : m_frame(&frame) | |
| 263 , m_mouseDownMayStartSelect(false) | |
| 264 , m_mouseDownWasSingleClickInSelection(false) | |
| 265 , m_selectionState(SelectionState::HaveNotStartedSelection) | |
| 266 { | |
| 267 } | |
| 268 | |
| 269 DEFINE_TRACE(SelectionController) | |
| 270 { | |
| 271 visitor->trace(m_frame); | |
| 272 } | |
| 273 | |
| 274 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node * targetNode, const VisibleSelection& visibleSelection, TextGranularity granular ity) | |
| 275 { | |
| 276 if (Position::nodeIsUserSelectNone(targetNode)) | |
| 277 return false; | |
| 278 | |
| 279 if (!dispatchSelectStart(targetNode)) | |
| 280 return false; | |
| 281 | |
| 282 if (visibleSelection.isRange()) { | |
| 283 m_selectionState = SelectionState::ExtendedSelection; | |
| 284 } else { | |
| 285 granularity = CharacterGranularity; | |
| 286 m_selectionState = SelectionState::PlacedCaret; | |
| 287 } | |
| 288 | |
| 289 selection().setNonDirectionalSelectionIfNeeded(visibleSelection, granularity ); | |
| 290 | |
| 291 return true; | |
| 292 } | |
| 293 | |
| 294 void SelectionController::selectClosestWordFromHitTestResult(const HitTestResult & result, AppendTrailingWhitespace appendTrailingWhitespace) | |
| 295 { | |
| 296 Node* innerNode = result.innerNode(); | |
| 297 VisibleSelection newSelection; | |
| 298 | |
| 299 if (!innerNode || !innerNode->layoutObject()) | |
| 300 return; | |
| 301 | |
| 302 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.local Point())); | |
| 303 if (pos.isNotNull()) { | |
| 304 newSelection = VisibleSelection(pos); | |
| 305 expandSelectionUsingGranularity(newSelection, WordGranularity); | |
| 306 } | |
| 307 | |
| 308 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && ne wSelection.isRange()) | |
| 309 newSelection.appendTrailingWhitespace(); | |
| 310 | |
| 311 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelection ToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 312 } | |
| 313 | |
| 314 void SelectionController::selectClosestMisspellingFromHitTestResult(const HitTes tResult& result, AppendTrailingWhitespace appendTrailingWhitespace) | |
| 315 { | |
| 316 Node* innerNode = result.innerNode(); | |
| 317 VisibleSelection newSelection; | |
| 318 | |
| 319 if (!innerNode || !innerNode->layoutObject()) | |
| 320 return; | |
| 321 | |
| 322 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.local Point())); | |
| 323 Position start = pos.deepEquivalent(); | |
| 324 Position end = pos.deepEquivalent(); | |
| 325 if (pos.isNotNull()) { | |
| 326 DocumentMarkerVector markers = innerNode->document().markers().markersIn Range(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers()); | |
| 327 if (markers.size() == 1) { | |
| 328 start.moveToOffset(markers[0]->startOffset()); | |
| 329 end.moveToOffset(markers[0]->endOffset()); | |
| 330 newSelection = VisibleSelection(start, end); | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && ne wSelection.isRange()) | |
| 335 newSelection.appendTrailingWhitespace(); | |
| 336 | |
| 337 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelection ToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 338 } | |
| 339 | |
| 340 void SelectionController::selectClosestWordFromMouseEvent(const MouseEventWithHi tTestResults& result) | |
| 341 { | |
| 342 if (!m_mouseDownMayStartSelect) | |
| 343 return; | |
| 344 | |
| 345 selectClosestWordFromHitTestResult(result.hitTestResult(), | |
| 346 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingW hitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailingWhi tespace::DontAppend); | |
| 347 } | |
| 348 | |
| 349 void SelectionController::selectClosestMisspellingFromMouseEvent(const MouseEven tWithHitTestResults& result) | |
| 350 { | |
| 351 if (!m_mouseDownMayStartSelect) | |
| 352 return; | |
| 353 | |
| 354 selectClosestMisspellingFromHitTestResult(result.hitTestResult(), | |
| 355 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingW hitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailingWhi tespace::DontAppend); | |
| 356 } | |
| 357 | |
| 358 void SelectionController::selectClosestWordOrLinkFromMouseEvent(const MouseEvent WithHitTestResults& result) | |
| 359 { | |
| 360 if (!result.hitTestResult().isLiveLink()) | |
| 361 return selectClosestWordFromMouseEvent(result); | |
| 362 | |
| 363 Node* innerNode = result.innerNode(); | |
| 364 | |
| 365 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | |
| 366 return; | |
| 367 | |
| 368 VisibleSelection newSelection; | |
| 369 Element* URLElement = result.hitTestResult().URLElement(); | |
| 370 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.local Point())); | |
| 371 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf (URLElement)) | |
| 372 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement) ; | |
| 373 | |
| 374 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelection ToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 375 } | |
| 376 | |
| 377 bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithH itTestResults& event) | |
| 378 { | |
| 379 return handleMousePressEventSingleClickAlgorithm<VisibleSelection::InDOMTree >(event); | |
| 380 } | |
| 381 | |
| 382 bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH itTestResults& event) | |
| 383 { | |
| 384 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick "); | |
| 385 | |
| 386 if (event.event().button() != LeftButton) | |
| 387 return false; | |
| 388 | |
| 389 if (selection().isRange()) { | |
| 390 // A double-click when range is already selected | |
| 391 // should not change the selection. So, do not call | |
| 392 // selectClosestWordFromMouseEvent, but do set | |
| 393 // m_beganSelectingText to prevent handleMouseReleaseEvent | |
| 394 // from setting caret selection. | |
| 395 m_selectionState = SelectionState::ExtendedSelection; | |
| 396 } else { | |
| 397 selectClosestWordFromMouseEvent(event); | |
| 398 } | |
| 399 return true; | |
| 400 } | |
| 401 | |
| 402 bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH itTestResults& event) | |
| 403 { | |
| 404 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick "); | |
| 405 | |
| 406 if (event.event().button() != LeftButton) | |
| 407 return false; | |
| 408 | |
| 409 Node* innerNode = event.innerNode(); | |
| 410 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | |
| 411 return false; | |
| 412 | |
| 413 VisibleSelection newSelection; | |
| 414 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localP oint())); | |
| 415 if (pos.isNotNull()) { | |
| 416 newSelection = VisibleSelection(pos); | |
| 417 expandSelectionUsingGranularity(newSelection, ParagraphGranularity); | |
| 418 } | |
| 419 | |
| 420 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); | |
| 421 } | |
| 422 | |
| 423 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul ts& event) | |
| 424 { | |
| 425 // If we got the event back, that must mean it wasn't prevented, | |
| 426 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. | |
| 427 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !e vent.scrollbar(); | |
| 428 m_mouseDownWasSingleClickInSelection = false; | |
| 429 } | |
| 430 | |
| 431 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node * mousePressNode, const IntPoint& lastKnownMousePosition) | |
| 432 { | |
| 433 if (m_selectionState != SelectionState::ExtendedSelection) { | |
| 434 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active ); | |
| 435 HitTestResult result(request, mouseDownPos); | |
| 436 m_frame->document()->layoutView()->hitTest(result); | |
| 437 | |
| 438 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKn ownMousePosition); | |
| 439 } | |
| 440 updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStart Pos, lastKnownMousePosition); | |
| 441 } | |
| 442 | |
| 443 void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, cons t LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) | |
| 444 { | |
| 445 FrameView* view = m_frame->view(); | |
| 446 if (!view) | |
| 447 return; | |
| 448 LayoutView* layoutObject = m_frame->contentLayoutObject(); | |
| 449 if (!layoutObject) | |
| 450 return; | |
| 451 | |
| 452 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move); | |
| 453 HitTestResult result(request, view->rootFrameToContents(lastKnownMousePositi on)); | |
| 454 layoutObject->hitTest(result); | |
| 455 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM ousePosition); | |
| 456 } | |
| 457 | |
| 458 void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTe stResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) | |
| 459 { | |
| 460 updateSelectionForMouseDragAlgorithm<VisibleSelection::InDOMTree>(hitTestRes ult, mousePressNode, dragStartPos, lastKnownMousePosition); | |
| 461 } | |
| 462 | |
| 452 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes ults& event, const LayoutPoint& dragStartPos) | 463 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes ults& event, const LayoutPoint& dragStartPos) |
| 453 { | 464 { |
| 454 bool handled = false; | 465 bool handled = false; |
| 455 m_mouseDownMayStartSelect = false; | 466 m_mouseDownMayStartSelect = false; |
| 456 // Clear the selection if the mouse didn't move after the last mouse | 467 // Clear the selection if the mouse didn't move after the last mouse |
| 457 // press and it's not a context menu click. We do this so when clicking | 468 // press and it's not a context menu click. We do this so when clicking |
| 458 // on the selection, the selection goes away. However, if we are | 469 // on the selection, the selection goes away. However, if we are |
| 459 // editing, place the caret. | 470 // editing, place the caret. |
| 460 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != Ex tendedSelection | 471 if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionSta te::ExtendedSelection |
| 461 && dragStartPos == event.event().position() | 472 && dragStartPos == event.event().position() |
| 462 && m_frame->selection().isRange() | 473 && selection().isRange() |
| 463 && event.event().button() != RightButton) { | 474 && event.event().button() != RightButton) { |
| 464 VisibleSelection newSelection; | 475 VisibleSelection newSelection; |
| 465 Node* node = event.innerNode(); | 476 Node* node = event.innerNode(); |
| 466 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBr owsingEnabled(); | 477 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBr owsingEnabled(); |
| 467 if (node && node->layoutObject() && (caretBrowsing || node->hasEditableS tyle())) { | 478 if (node && node->layoutObject() && (caretBrowsing || node->hasEditableS tyle())) { |
| 468 VisiblePosition pos = VisiblePosition(node->layoutObject()->position ForPoint(event.localPoint())); | 479 VisiblePosition pos = VisiblePosition(node->layoutObject()->position ForPoint(event.localPoint())); |
| 469 newSelection = VisibleSelection(pos); | 480 newSelection = VisibleSelection(pos); |
| 470 } | 481 } |
| 471 | 482 |
| 472 setSelectionIfNeeded(m_frame->selection(), newSelection); | 483 setSelectionIfNeeded(selection(), newSelection); |
| 473 | 484 |
| 474 handled = true; | 485 handled = true; |
| 475 } | 486 } |
| 476 | 487 |
| 477 m_frame->selection().notifyLayoutObjectOfSelectionChange(UserTriggered); | 488 selection().notifyLayoutObjectOfSelectionChange(UserTriggered); |
| 478 | 489 |
| 479 m_frame->selection().selectFrameElementInParentIfFullySelected(); | 490 selection().selectFrameElementInParentIfFullySelected(); |
| 480 | 491 |
| 481 if (event.event().button() == MiddleButton && !event.isOverLink()) { | 492 if (event.event().button() == MiddleButton && !event.isOverLink()) { |
| 482 // Ignore handled, since we want to paste to where the caret was placed anyway. | 493 // Ignore handled, since we want to paste to where the caret was placed anyway. |
| 483 handled = handlePasteGlobalSelection(event.event()) || handled; | 494 handled = handlePasteGlobalSelection(event.event()) || handled; |
| 484 } | 495 } |
| 485 | 496 |
| 486 return handled; | 497 return handled; |
| 487 } | 498 } |
| 488 | 499 |
| 489 | |
| 490 bool SelectionController::handlePasteGlobalSelection(const PlatformMouseEvent& m ouseEvent) | 500 bool SelectionController::handlePasteGlobalSelection(const PlatformMouseEvent& m ouseEvent) |
| 491 { | 501 { |
| 492 // If the event was a middle click, attempt to copy global selection in afte r | 502 // If the event was a middle click, attempt to copy global selection in afte r |
| 493 // the newly set caret position. | 503 // the newly set caret position. |
| 494 // | 504 // |
| 495 // This code is called from either the mouse up or mouse down handling. Ther e | 505 // This code is called from either the mouse up or mouse down handling. Ther e |
| 496 // is some debate about when the global selection is pasted: | 506 // is some debate about when the global selection is pasted: |
| 497 // xterm: pastes on up. | 507 // xterm: pastes on up. |
| 498 // GTK: pastes on down. | 508 // GTK: pastes on down. |
| 499 // Qt: pastes on up. | 509 // Qt: pastes on up. |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 518 return false; | 528 return false; |
| 519 } | 529 } |
| 520 | 530 |
| 521 bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges tureEvent, const HitTestResult& hitTestResult) | 531 bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges tureEvent, const HitTestResult& hitTestResult) |
| 522 { | 532 { |
| 523 #if OS(ANDROID) | 533 #if OS(ANDROID) |
| 524 bool shouldLongPressSelectWord = true; | 534 bool shouldLongPressSelectWord = true; |
| 525 #else | 535 #else |
| 526 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()- >touchEditingEnabled(); | 536 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()- >touchEditingEnabled(); |
| 527 #endif | 537 #endif |
| 528 if (shouldLongPressSelectWord) { | 538 if (!shouldLongPressSelectWord) |
| 539 return false; | |
| 529 | 540 |
| 541 Node* innerNode = hitTestResult.innerNode(); | |
| 542 if (hitTestResult.isLiveLink() || !innerNode || !(innerNode->isContentEditab le() || innerNode->isTextNode() | |
| 543 #if OS(ANDROID) | |
| 544 || innerNode->canStartSelection() | |
| 545 #endif | |
| 546 )) | |
| 547 return false; | |
| 530 | 548 |
| 531 Node* innerNode = hitTestResult.innerNode(); | 549 selectClosestWordFromHitTestResult(hitTestResult, AppendTrailingWhitespace:: DontAppend); |
| 532 if (!hitTestResult.isLiveLink() && innerNode && (innerNode->isContentEdi table() || innerNode->isTextNode() | 550 if (!selection().isRange()) |
| 533 #if OS(ANDROID) | 551 return false; |
| 534 || innerNode->canStartSelection() | 552 |
| 535 #endif | 553 return true; |
| 536 )) { | |
| 537 selectClosestWordFromHitTestResult(hitTestResult, DontAppendTrailing Whitespace); | |
| 538 if (m_frame->selection().isRange()) | |
| 539 return true; | |
| 540 } | |
| 541 } | |
| 542 return false; | |
| 543 } | 554 } |
| 544 | 555 |
| 545 void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResult s& mev, const LayoutPoint& position) | 556 void SelectionController::prepareForContextMenu(const MouseEventWithHitTestResul ts& mev, const LayoutPoint& position) |
| 546 { | 557 { |
| 547 if (!m_frame->selection().contains(position) | 558 if (selection().contains(position) |
| 548 && !mev.scrollbar() | 559 || mev.scrollbar() |
| 549 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. | 560 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. |
| 550 // If the selection is non-editable, we do word selection to make it eas ier to use the contextual menu items | 561 // If the selection is non-editable, we do word selection to make it eas ier to use the contextual menu items |
| 551 // available for text selections. But only if we're above text. | 562 // available for text selections. But only if we're above text. |
| 552 && (m_frame->selection().isContentEditable() || (mev.innerNode() && mev. innerNode()->isTextNode()))) { | 563 || !(selection().isContentEditable() || (mev.innerNode() && mev.innerNod e()->isTextNode()))) |
| 553 m_mouseDownMayStartSelect = true; // context menu events are always allo wed to perform a selection | 564 return; |
| 554 | 565 |
| 555 if (mev.hitTestResult().isMisspelled()) | 566 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection |
| 556 selectClosestMisspellingFromMouseEvent(mev); | 567 |
| 557 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick( )) | 568 if (mev.hitTestResult().isMisspelled()) |
| 558 selectClosestWordOrLinkFromMouseEvent(mev); | 569 selectClosestMisspellingFromMouseEvent(mev); |
| 559 } | 570 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) |
| 571 selectClosestWordOrLinkFromMouseEvent(mev); | |
| 560 } | 572 } |
| 561 | 573 |
| 562 void SelectionController::passMousePressEventToSubframe(const MouseEventWithHitT estResults& mev) | 574 void SelectionController::preparePassMousePressEventToSubframe(const MouseEventW ithHitTestResults& mev) |
| 563 { | 575 { |
| 564 // If we're clicking into a frame that is selected, the frame will appear | 576 // If we're clicking into a frame that is selected, the frame will appear |
| 565 // greyed out even though we're clicking on the selection. This looks | 577 // greyed out even though we're clicking on the selection. This looks |
| 566 // really strange (having the whole frame be greyed out), so we deselect the | 578 // really strange (having the whole frame be greyed out), so we deselect the |
| 567 // selection. | 579 // selection. |
| 568 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); | 580 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); |
| 569 if (m_frame->selection().contains(p)) { | 581 if (!selection().contains(p)) |
| 570 VisiblePosition visiblePos( | 582 return; |
| 571 mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint())) ; | 583 |
| 572 VisibleSelection newSelection(visiblePos); | 584 VisiblePosition visiblePos( |
| 573 m_frame->selection().setSelection(newSelection); | 585 mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint())); |
| 574 } | 586 VisibleSelection newSelection(visiblePos); |
| 587 selection().setSelection(newSelection); | |
| 575 } | 588 } |
| 576 | 589 |
| 577 void SelectionController::initializeSelectionState() | 590 void SelectionController::initializeSelectionState() |
| 578 { | 591 { |
| 579 m_selectionInitiationState = HaveNotStartedSelection; | 592 m_selectionState = SelectionState::HaveNotStartedSelection; |
| 580 } | 593 } |
| 581 | 594 |
| 582 void SelectionController::setMouseDownMayStartSelect(bool mayStartSelect) | 595 void SelectionController::setMouseDownMayStartSelect(bool mayStartSelect) |
| 583 { | 596 { |
| 584 m_mouseDownMayStartSelect = mayStartSelect; | 597 m_mouseDownMayStartSelect = mayStartSelect; |
| 585 } | 598 } |
| 586 | 599 |
| 587 bool SelectionController::mouseDownMayStartSelect() const | 600 bool SelectionController::mouseDownMayStartSelect() const |
| 588 { | 601 { |
| 589 return m_mouseDownMayStartSelect; | 602 return m_mouseDownMayStartSelect; |
| 590 } | 603 } |
| 591 | 604 |
| 592 bool SelectionController::mouseDownWasSingleClickInSelection() const | 605 bool SelectionController::mouseDownWasSingleClickInSelection() const |
| 593 { | 606 { |
| 594 return m_mouseDownWasSingleClickInSelection; | 607 return m_mouseDownWasSingleClickInSelection; |
| 595 } | 608 } |
| 596 | 609 |
| 610 FrameSelection& SelectionController::selection() const | |
| 611 { | |
| 612 return m_frame->selection(); | |
| 613 } | |
| 614 | |
| 597 } // namespace blink | 615 } // namespace blink |
| OLD | NEW |