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 |