Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2008 Google Inc. | 3 * Copyright (C) 2008 Google Inc. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 85 #include "wtf/CurrentTime.h" | 85 #include "wtf/CurrentTime.h" |
| 86 #include "wtf/RefPtr.h" | 86 #include "wtf/RefPtr.h" |
| 87 #include <memory> | 87 #include <memory> |
| 88 | 88 |
| 89 #if OS(WIN) | 89 #if OS(WIN) |
| 90 #include <windows.h> | 90 #include <windows.h> |
| 91 #endif | 91 #endif |
| 92 | 92 |
| 93 namespace blink { | 93 namespace blink { |
| 94 | 94 |
| 95 namespace { | |
| 96 | |
| 97 DataTransfer* createDraggingDataTransfer(DataTransferAccessPolicy policy, DragDa ta* dragData) | |
| 98 { | |
| 99 return DataTransfer::create(DataTransfer::DragAndDrop, policy, dragData->pla tformData()); | |
| 100 } | |
| 101 | |
| 102 DocumentFragment* documentFragmentFromDragData(DragData* dragData, LocalFrame* f rame, Range* context, bool allowPlainText, bool& chosePlainText) | |
| 103 { | |
| 104 DCHECK(dragData); | |
| 105 chosePlainText = false; | |
| 106 | |
| 107 Document& document = context->ownerDocument(); | |
| 108 if (dragData->containsCompatibleContent()) { | |
| 109 if (DocumentFragment* fragment = dragData->asFragment(frame)) | |
| 110 return fragment; | |
| 111 | |
| 112 if (dragData->containsURL(DragData::DoNotConvertFilenames)) { | |
| 113 String title; | |
| 114 String url = dragData->asURL(DragData::DoNotConvertFilenames, &title ); | |
| 115 if (!url.isEmpty()) { | |
| 116 HTMLAnchorElement* anchor = HTMLAnchorElement::create(document); | |
| 117 anchor->setHref(AtomicString(url)); | |
| 118 if (title.isEmpty()) { | |
| 119 // Try the plain text first because the url might be normali zed or escaped. | |
| 120 if (dragData->containsPlainText()) | |
| 121 title = dragData->asPlainText(); | |
| 122 if (title.isEmpty()) | |
| 123 title = url; | |
| 124 } | |
| 125 Node* anchorText = document.createTextNode(title); | |
| 126 anchor->appendChild(anchorText); | |
| 127 DocumentFragment* fragment = document.createDocumentFragment(); | |
| 128 fragment->appendChild(anchor); | |
| 129 return fragment; | |
| 130 } | |
| 131 } | |
| 132 } | |
| 133 if (allowPlainText && dragData->containsPlainText()) { | |
| 134 chosePlainText = true; | |
| 135 return createFragmentFromText(EphemeralRange(context), dragData->asPlain Text()); | |
| 136 } | |
| 137 | |
| 138 return nullptr; | |
| 139 } | |
| 140 | |
| 141 bool doDeleteByDragWithEvents(Element* dragTarget, bool smartDelete, const Posit ion& referenceMovePosition) | |
|
yosin_UTC9
2016/09/28 04:19:03
Please add comment about |bool| return value.
chongz
2016/09/29 02:36:22
Done.
| |
| 142 { | |
|
yosin_UTC9
2016/09/28 04:19:03
This function should be in Editor class and avoid
chongz
2016/09/29 02:36:22
Done.
| |
| 143 if (!dragTarget || !dragTarget->isConnected()) | |
| 144 return true; | |
| 145 | |
| 146 LocalFrame* dragFrame = dragTarget->document().frame(); | |
| 147 | |
| 148 // Dispatch 'beforeinput'. | |
| 149 const bool shouldDelete = dispatchBeforeInputEditorCommand(dragTarget, Input Event::InputType::DeleteByDrag, nullptr) == DispatchEventResult::NotCanceled; | |
|
yosin_UTC9
2016/09/28 04:19:03
I think we should dispatch event to drag source ra
chongz
2016/09/29 02:36:22
Sorry for the confusion, I've renamed it to |dragS
| |
| 150 | |
| 151 // 'beforeinput' event handler may destroy frame, return false to cancel rem aining actions; | |
| 152 if (dragFrame != dragTarget->document().frame()) | |
| 153 return false; | |
| 154 | |
| 155 if (shouldDelete && dragTarget->isConnected()) | |
| 156 dragFrame->editor().deleteSelectionWithSmartDelete(smartDelete, InputEve nt::InputType::DeleteByDrag, referenceMovePosition); | |
| 157 | |
| 158 return true; | |
| 159 } | |
| 160 | |
| 161 bool doInsertFromDropWithEvents(Element* dropTarget, DragData* dragData, Documen tFragment* fragment, Range* dropCaretRange, bool smartInsert, bool chosePlainTex t) | |
|
yosin_UTC9
2016/09/28 04:19:03
Please add comment about |bool| return value.
chongz
2016/09/29 02:36:22
Done.
| |
| 162 { | |
|
yosin_UTC9
2016/09/28 04:19:03
This function should be in Editor class and avoid
chongz
2016/09/29 02:36:22
Done.
| |
| 163 if (!dropTarget || !dropTarget->isConnected()) | |
| 164 return true; | |
| 165 | |
| 166 LocalFrame* dropFrame = dropTarget->document().frame(); | |
| 167 | |
| 168 // Dispatch 'beforeinput'. | |
| 169 DataTransfer* dataTransfer = createDraggingDataTransfer(DataTransferReadable , dragData); | |
| 170 dataTransfer->setSourceOperation(dragData->draggingSourceOperationMask()); | |
| 171 const bool shouldInsert = dispatchBeforeInputDataTransfer(dropTarget, InputE vent::InputType::InsertFromDrop, dataTransfer, nullptr) == DispatchEventResult:: NotCanceled; | |
| 172 | |
| 173 // 'beforeinput' event handler may destroy frame, return false to cancel rem aining actions; | |
| 174 if (dropFrame != dropTarget->document().frame()) | |
| 175 return false; | |
| 176 | |
| 177 if (shouldInsert && dropTarget->isConnected()) | |
| 178 dropFrame->editor().replaceSelectionAfterDragging(fragment, smartInsert, chosePlainText); | |
| 179 | |
| 180 return true; | |
| 181 } | |
| 182 | |
| 183 } // anonymous namespace | |
| 184 | |
| 95 const int DragController::DragIconRightInset = 7; | 185 const int DragController::DragIconRightInset = 7; |
| 96 const int DragController::DragIconBottomInset = 3; | 186 const int DragController::DragIconBottomInset = 3; |
| 97 | 187 |
| 98 static const int MaxOriginalImageArea = 1500 * 1500; | 188 static const int MaxOriginalImageArea = 1500 * 1500; |
| 99 static const int LinkDragBorderInset = 2; | 189 static const int LinkDragBorderInset = 2; |
| 100 static const float DragImageAlpha = 0.75f; | 190 static const float DragImageAlpha = 0.75f; |
| 101 | 191 |
| 102 #if ENABLE(ASSERT) | 192 #if ENABLE(ASSERT) |
| 103 static bool dragTypeIsValid(DragSourceAction action) | 193 static bool dragTypeIsValid(DragSourceAction action) |
| 104 { | 194 { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 117 #endif | 207 #endif |
| 118 | 208 |
| 119 static PlatformMouseEvent createMouseEvent(DragData* dragData) | 209 static PlatformMouseEvent createMouseEvent(DragData* dragData) |
| 120 { | 210 { |
| 121 return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPositi on(), | 211 return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPositi on(), |
| 122 WebPointerProperties::Button::Left, PlatformEvent::MouseMoved, 0, | 212 WebPointerProperties::Button::Left, PlatformEvent::MouseMoved, 0, |
| 123 static_cast<PlatformEvent::Modifiers>(dragData->modifiers()), | 213 static_cast<PlatformEvent::Modifiers>(dragData->modifiers()), |
| 124 PlatformMouseEvent::RealOrIndistinguishable, monotonicallyIncreasingTime ()); | 214 PlatformMouseEvent::RealOrIndistinguishable, monotonicallyIncreasingTime ()); |
| 125 } | 215 } |
| 126 | 216 |
| 127 static DataTransfer* createDraggingDataTransfer(DataTransferAccessPolicy policy, DragData* dragData) | |
| 128 { | |
| 129 return DataTransfer::create(DataTransfer::DragAndDrop, policy, dragData->pla tformData()); | |
| 130 } | |
| 131 | |
| 132 DragController::DragController(Page* page) | 217 DragController::DragController(Page* page) |
| 133 : m_page(page) | 218 : m_page(page) |
| 134 , m_documentUnderMouse(nullptr) | 219 , m_documentUnderMouse(nullptr) |
| 135 , m_dragInitiator(nullptr) | 220 , m_dragInitiator(nullptr) |
| 136 , m_fileInputElementUnderMouse(nullptr) | 221 , m_fileInputElementUnderMouse(nullptr) |
| 137 , m_documentIsHandlingDrag(false) | 222 , m_documentIsHandlingDrag(false) |
| 138 , m_dragDestinationAction(DragDestinationActionNone) | 223 , m_dragDestinationAction(DragDestinationActionNone) |
| 139 , m_didInitiateDrag(false) | 224 , m_didInitiateDrag(false) |
| 140 { | 225 { |
| 141 } | 226 } |
| 142 | 227 |
| 143 DragController* DragController::create(Page* page) | 228 DragController* DragController::create(Page* page) |
| 144 { | 229 { |
| 145 return new DragController(page); | 230 return new DragController(page); |
| 146 } | 231 } |
| 147 | 232 |
| 148 static DocumentFragment* documentFragmentFromDragData(DragData* dragData, LocalF rame* frame, Range* context, bool allowPlainText, bool& chosePlainText) | |
| 149 { | |
| 150 ASSERT(dragData); | |
| 151 chosePlainText = false; | |
| 152 | |
| 153 Document& document = context->ownerDocument(); | |
| 154 if (dragData->containsCompatibleContent()) { | |
| 155 if (DocumentFragment* fragment = dragData->asFragment(frame)) | |
| 156 return fragment; | |
| 157 | |
| 158 if (dragData->containsURL(DragData::DoNotConvertFilenames)) { | |
| 159 String title; | |
| 160 String url = dragData->asURL(DragData::DoNotConvertFilenames, &title ); | |
| 161 if (!url.isEmpty()) { | |
| 162 HTMLAnchorElement* anchor = HTMLAnchorElement::create(document); | |
| 163 anchor->setHref(AtomicString(url)); | |
| 164 if (title.isEmpty()) { | |
| 165 // Try the plain text first because the url might be normali zed or escaped. | |
| 166 if (dragData->containsPlainText()) | |
| 167 title = dragData->asPlainText(); | |
| 168 if (title.isEmpty()) | |
| 169 title = url; | |
| 170 } | |
| 171 Node* anchorText = document.createTextNode(title); | |
| 172 anchor->appendChild(anchorText); | |
| 173 DocumentFragment* fragment = document.createDocumentFragment(); | |
| 174 fragment->appendChild(anchor); | |
| 175 return fragment; | |
| 176 } | |
| 177 } | |
| 178 } | |
| 179 if (allowPlainText && dragData->containsPlainText()) { | |
| 180 chosePlainText = true; | |
| 181 return createFragmentFromText(EphemeralRange(context), dragData->asPlain Text()); | |
| 182 } | |
| 183 | |
| 184 return nullptr; | |
| 185 } | |
| 186 | |
| 187 bool DragController::dragIsMove(FrameSelection& selection, DragData* dragData) | 233 bool DragController::dragIsMove(FrameSelection& selection, DragData* dragData) |
| 188 { | 234 { |
| 189 return m_documentUnderMouse == m_dragInitiator && selection.isContentEditabl e() && selection.isRange() && !isCopyKeyDown(dragData); | 235 return m_documentUnderMouse == m_dragInitiator && selection.isContentEditabl e() && selection.isRange() && !isCopyKeyDown(dragData); |
| 190 } | 236 } |
| 191 | 237 |
| 192 // FIXME: This method is poorly named. We're just clearing the selection from t he document this drag is exiting. | 238 // FIXME: This method is poorly named. We're just clearing the selection from t he document this drag is exiting. |
| 193 void DragController::cancelDrag() | 239 void DragController::cancelDrag() |
| 194 { | 240 { |
| 195 m_page->dragCaretController().clear(); | 241 m_page->dragCaretController().clear(); |
| 196 } | 242 } |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 506 ResourceCacheValidationSuppressor validationSuppressor(fetcher); | 552 ResourceCacheValidationSuppressor validationSuppressor(fetcher); |
| 507 if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRich lyEditable()) { | 553 if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRich lyEditable()) { |
| 508 bool chosePlainText = false; | 554 bool chosePlainText = false; |
| 509 DocumentFragment* fragment = documentFragmentFromDragData(dragData, inne rFrame, range, true, chosePlainText); | 555 DocumentFragment* fragment = documentFragmentFromDragData(dragData, inne rFrame, range, true, chosePlainText); |
| 510 if (!fragment) | 556 if (!fragment) |
| 511 return false; | 557 return false; |
| 512 | 558 |
| 513 if (dragIsMove(innerFrame->selection(), dragData)) { | 559 if (dragIsMove(innerFrame->selection(), dragData)) { |
| 514 // NSTextView behavior is to always smart delete on moving a selecti on, | 560 // NSTextView behavior is to always smart delete on moving a selecti on, |
| 515 // but only to smart insert if the selection granularity is word gra nularity. | 561 // but only to smart insert if the selection granularity is word gra nularity. |
| 516 bool smartDelete = innerFrame->editor().smartInsertDeleteEnabled(); | 562 const bool smartDelete = innerFrame->editor().smartInsertDeleteEnabl ed(); |
| 517 bool smartInsert = smartDelete && innerFrame->selection().granularit y() == WordGranularity && dragData->canSmartReplace(); | 563 const bool smartInsert = smartDelete && innerFrame->selection().gran ularity() == WordGranularity && dragData->canSmartReplace(); |
| 518 innerFrame->editor().moveSelectionAfterDragging(fragment, dragCaret. base(), smartInsert, smartDelete); | 564 |
| 565 if (!doDeleteByDragWithEvents(innerFrame->editor().findEventTargetFr omSelection(), smartDelete, dragCaret.base())) | |
| 566 return false; | |
| 567 | |
| 568 innerFrame->selection().setSelection(VisibleSelection(range->startPo sition(), range->endPosition())); | |
| 569 if (innerFrame->selection().isAvailable()) { | |
| 570 DCHECK(m_documentUnderMouse); | |
| 571 if (!doInsertFromDropWithEvents(element, dragData, fragment, ran ge, smartInsert, chosePlainText)) | |
| 572 return false; | |
| 573 } | |
| 519 } else { | 574 } else { |
| 520 if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) { | 575 if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) { |
| 521 ASSERT(m_documentUnderMouse); | 576 DCHECK(m_documentUnderMouse); |
| 522 m_documentUnderMouse->frame()->editor().replaceSelectionAfterDra gging(fragment, dragData->canSmartReplace(), chosePlainText); | 577 if (!doInsertFromDropWithEvents(element, dragData, fragment, ran ge, dragData->canSmartReplace(), chosePlainText)) |
| 578 return false; | |
| 523 } | 579 } |
| 524 } | 580 } |
| 525 } else { | 581 } else { |
| 526 String text = dragData->asPlainText(); | 582 String text = dragData->asPlainText(); |
| 527 if (text.isEmpty()) | 583 if (text.isEmpty()) |
| 528 return false; | 584 return false; |
| 529 | 585 |
| 530 if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) { | 586 if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) { |
| 531 const bool canSmartReplace = false; | 587 const bool canSmartReplace = false; |
| 532 const bool chosePlainText = true; | 588 const bool chosePlainText = true; |
| 533 ASSERT(m_documentUnderMouse); | 589 DCHECK(m_documentUnderMouse); |
| 534 m_documentUnderMouse->frame()->editor().replaceSelectionAfterDraggin g(createFragmentFromText(EphemeralRange(range), text), canSmartReplace, chosePla inText); | 590 if (!doInsertFromDropWithEvents(element, dragData, createFragmentFro mText(EphemeralRange(range), text), range, canSmartReplace, chosePlainText)) |
| 591 return false; | |
| 535 } | 592 } |
| 536 } | 593 } |
| 537 | 594 |
| 538 if (rootEditableElement) { | 595 if (rootEditableElement) { |
| 539 if (LocalFrame* frame = rootEditableElement->document().frame()) | 596 if (LocalFrame* frame = rootEditableElement->document().frame()) |
| 540 frame->eventHandler().updateDragStateAfterEditDragIfNeeded(rootEdita bleElement); | 597 frame->eventHandler().updateDragStateAfterEditDragIfNeeded(rootEdita bleElement); |
| 541 } | 598 } |
| 542 | 599 |
| 543 return true; | 600 return true; |
| 544 } | 601 } |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 997 | 1054 |
| 998 DEFINE_TRACE(DragController) | 1055 DEFINE_TRACE(DragController) |
| 999 { | 1056 { |
| 1000 visitor->trace(m_page); | 1057 visitor->trace(m_page); |
| 1001 visitor->trace(m_documentUnderMouse); | 1058 visitor->trace(m_documentUnderMouse); |
| 1002 visitor->trace(m_dragInitiator); | 1059 visitor->trace(m_dragInitiator); |
| 1003 visitor->trace(m_fileInputElementUnderMouse); | 1060 visitor->trace(m_fileInputElementUnderMouse); |
| 1004 } | 1061 } |
| 1005 | 1062 |
| 1006 } // namespace blink | 1063 } // namespace blink |
| OLD | NEW |