OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/tab_contents/web_drop_target_win.h" | |
6 | |
7 #include <windows.h> | |
8 #include <shlobj.h> | |
9 | |
10 #include "chrome/browser/tab_contents/web_drag_bookmark_handler_win.h" | |
11 #include "chrome/browser/tab_contents/web_drag_utils_win.h" | |
12 #include "content/browser/renderer_host/render_view_host.h" | |
13 #include "content/browser/tab_contents/web_drag_dest_delegate.h" | |
14 #include "content/public/browser/web_contents.h" | |
15 #include "googleurl/src/gurl.h" | |
16 #include "net/base/net_util.h" | |
17 #include "ui/base/clipboard/clipboard_util_win.h" | |
18 #include "ui/base/dragdrop/os_exchange_data.h" | |
19 #include "ui/base/dragdrop/os_exchange_data_provider_win.h" | |
20 #include "ui/gfx/point.h" | |
21 #include "webkit/glue/webdropdata.h" | |
22 #include "webkit/glue/window_open_disposition.h" | |
23 | |
24 using WebKit::WebDragOperationNone; | |
25 using WebKit::WebDragOperationCopy; | |
26 using WebKit::WebDragOperationLink; | |
27 using WebKit::WebDragOperationMove; | |
28 using WebKit::WebDragOperationGeneric; | |
29 using content::OpenURLParams; | |
30 using content::Referrer; | |
31 using content::WebContents; | |
32 | |
33 namespace { | |
34 | |
35 // A helper method for getting the preferred drop effect. | |
36 DWORD GetPreferredDropEffect(DWORD effect) { | |
37 if (effect & DROPEFFECT_COPY) | |
38 return DROPEFFECT_COPY; | |
39 if (effect & DROPEFFECT_LINK) | |
40 return DROPEFFECT_LINK; | |
41 if (effect & DROPEFFECT_MOVE) | |
42 return DROPEFFECT_MOVE; | |
43 return DROPEFFECT_NONE; | |
44 } | |
45 | |
46 } // namespace | |
47 | |
48 // InterstitialDropTarget is like a ui::DropTarget implementation that | |
49 // WebDropTarget passes through to if an interstitial is showing. Rather than | |
50 // passing messages on to the renderer, we just check to see if there's a link | |
51 // in the drop data and handle links as navigations. | |
52 class InterstitialDropTarget { | |
53 public: | |
54 explicit InterstitialDropTarget(WebContents* web_contents) | |
55 : web_contents_(web_contents) {} | |
56 | |
57 DWORD OnDragEnter(IDataObject* data_object, DWORD effect) { | |
58 return ui::ClipboardUtil::HasUrl(data_object) ? | |
59 GetPreferredDropEffect(effect) : DROPEFFECT_NONE; | |
60 } | |
61 | |
62 DWORD OnDragOver(IDataObject* data_object, DWORD effect) { | |
63 return ui::ClipboardUtil::HasUrl(data_object) ? | |
64 GetPreferredDropEffect(effect) : DROPEFFECT_NONE; | |
65 } | |
66 | |
67 void OnDragLeave(IDataObject* data_object) { | |
68 } | |
69 | |
70 DWORD OnDrop(IDataObject* data_object, DWORD effect) { | |
71 if (!ui::ClipboardUtil::HasUrl(data_object)) | |
72 return DROPEFFECT_NONE; | |
73 | |
74 std::wstring url; | |
75 std::wstring title; | |
76 ui::ClipboardUtil::GetUrl(data_object, &url, &title, true); | |
77 OpenURLParams params( | |
78 GURL(url), Referrer(), CURRENT_TAB, | |
79 content::PAGE_TRANSITION_AUTO_BOOKMARK, false); | |
80 web_contents_->OpenURL(params); | |
81 return GetPreferredDropEffect(effect); | |
82 } | |
83 | |
84 private: | |
85 WebContents* web_contents_; | |
86 | |
87 DISALLOW_COPY_AND_ASSIGN(InterstitialDropTarget); | |
88 }; | |
89 | |
90 WebDropTarget::WebDropTarget(HWND source_hwnd, WebContents* web_contents) | |
91 : ui::DropTarget(source_hwnd), | |
92 web_contents_(web_contents), | |
93 current_rvh_(NULL), | |
94 drag_cursor_(WebDragOperationNone), | |
95 interstitial_drop_target_(new InterstitialDropTarget(web_contents)), | |
96 delegate_(new WebDragBookmarkHandlerWin()) { | |
97 } | |
98 | |
99 WebDropTarget::~WebDropTarget() { | |
100 // TODO(jam): this will be owned by chrome when it moves, so no scoped | |
101 // pointer. | |
102 if (delegate_) | |
103 delete delegate_; | |
104 } | |
105 | |
106 DWORD WebDropTarget::OnDragEnter(IDataObject* data_object, | |
107 DWORD key_state, | |
108 POINT cursor_position, | |
109 DWORD effects) { | |
110 current_rvh_ = web_contents_->GetRenderViewHost(); | |
111 | |
112 if (delegate_) | |
113 delegate_->DragInitialize(web_contents_); | |
114 | |
115 // Don't pass messages to the renderer if an interstitial page is showing | |
116 // because we don't want the interstitial page to navigate. Instead, | |
117 // pass the messages on to a separate interstitial DropTarget handler. | |
118 if (web_contents_->ShowingInterstitialPage()) | |
119 return interstitial_drop_target_->OnDragEnter(data_object, effects); | |
120 | |
121 // TODO(tc): PopulateWebDropData can be slow depending on what is in the | |
122 // IDataObject. Maybe we can do this in a background thread. | |
123 WebDropData drop_data; | |
124 WebDropData::PopulateWebDropData(data_object, &drop_data); | |
125 | |
126 if (drop_data.url.is_empty()) | |
127 ui::OSExchangeDataProviderWin::GetPlainTextURL(data_object, &drop_data.url); | |
128 | |
129 drag_cursor_ = WebDragOperationNone; | |
130 | |
131 POINT client_pt = cursor_position; | |
132 ScreenToClient(GetHWND(), &client_pt); | |
133 web_contents_->GetRenderViewHost()->DragTargetDragEnter(drop_data, | |
134 gfx::Point(client_pt.x, client_pt.y), | |
135 gfx::Point(cursor_position.x, cursor_position.y), | |
136 web_drag_utils_win::WinDragOpMaskToWebDragOpMask(effects)); | |
137 | |
138 if (delegate_) | |
139 delegate_->OnDragEnter(data_object); | |
140 | |
141 // We lie here and always return a DROPEFFECT because we don't want to | |
142 // wait for the IPC call to return. | |
143 return web_drag_utils_win::WebDragOpToWinDragOp(drag_cursor_); | |
144 } | |
145 | |
146 DWORD WebDropTarget::OnDragOver(IDataObject* data_object, | |
147 DWORD key_state, | |
148 POINT cursor_position, | |
149 DWORD effects) { | |
150 DCHECK(current_rvh_); | |
151 if (current_rvh_ != web_contents_->GetRenderViewHost()) | |
152 OnDragEnter(data_object, key_state, cursor_position, effects); | |
153 | |
154 if (web_contents_->ShowingInterstitialPage()) | |
155 return interstitial_drop_target_->OnDragOver(data_object, effects); | |
156 | |
157 POINT client_pt = cursor_position; | |
158 ScreenToClient(GetHWND(), &client_pt); | |
159 web_contents_->GetRenderViewHost()->DragTargetDragOver( | |
160 gfx::Point(client_pt.x, client_pt.y), | |
161 gfx::Point(cursor_position.x, cursor_position.y), | |
162 web_drag_utils_win::WinDragOpMaskToWebDragOpMask(effects)); | |
163 | |
164 if (delegate_) | |
165 delegate_->OnDragOver(data_object); | |
166 | |
167 return web_drag_utils_win::WebDragOpToWinDragOp(drag_cursor_); | |
168 } | |
169 | |
170 void WebDropTarget::OnDragLeave(IDataObject* data_object) { | |
171 DCHECK(current_rvh_); | |
172 if (current_rvh_ != web_contents_->GetRenderViewHost()) | |
173 return; | |
174 | |
175 if (web_contents_->ShowingInterstitialPage()) { | |
176 interstitial_drop_target_->OnDragLeave(data_object); | |
177 } else { | |
178 web_contents_->GetRenderViewHost()->DragTargetDragLeave(); | |
179 } | |
180 | |
181 if (delegate_) | |
182 delegate_->OnDragLeave(data_object); | |
183 } | |
184 | |
185 DWORD WebDropTarget::OnDrop(IDataObject* data_object, | |
186 DWORD key_state, | |
187 POINT cursor_position, | |
188 DWORD effect) { | |
189 DCHECK(current_rvh_); | |
190 if (current_rvh_ != web_contents_->GetRenderViewHost()) | |
191 OnDragEnter(data_object, key_state, cursor_position, effect); | |
192 | |
193 if (web_contents_->ShowingInterstitialPage()) | |
194 interstitial_drop_target_->OnDragOver(data_object, effect); | |
195 | |
196 if (web_contents_->ShowingInterstitialPage()) | |
197 return interstitial_drop_target_->OnDrop(data_object, effect); | |
198 | |
199 POINT client_pt = cursor_position; | |
200 ScreenToClient(GetHWND(), &client_pt); | |
201 web_contents_->GetRenderViewHost()->DragTargetDrop( | |
202 gfx::Point(client_pt.x, client_pt.y), | |
203 gfx::Point(cursor_position.x, cursor_position.y)); | |
204 | |
205 if (delegate_) | |
206 delegate_->OnDrop(data_object); | |
207 | |
208 current_rvh_ = NULL; | |
209 | |
210 // This isn't always correct, but at least it's a close approximation. | |
211 // For now, we always map a move to a copy to prevent potential data loss. | |
212 DWORD drop_effect = web_drag_utils_win::WebDragOpToWinDragOp(drag_cursor_); | |
213 return drop_effect != DROPEFFECT_MOVE ? drop_effect : DROPEFFECT_COPY; | |
214 } | |
OLD | NEW |