OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h" | 5 #include "components/renderer_context_menu/render_view_context_menu_base.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <set> | |
9 #include <utility> | 8 #include <utility> |
10 | 9 |
11 #include "apps/app_load_service.h" | |
12 #include "base/command_line.h" | 10 #include "base/command_line.h" |
13 #include "base/logging.h" | 11 #include "base/logging.h" |
14 #include "base/metrics/histogram.h" | |
15 #include "base/prefs/pref_member.h" | |
16 #include "base/prefs/pref_service.h" | |
17 #include "base/stl_util.h" | |
18 #include "base/strings/string_util.h" | |
19 #include "base/strings/stringprintf.h" | |
20 #include "base/strings/utf_string_conversions.h" | |
21 #include "base/time/time.h" | |
22 #include "chrome/app/chrome_command_ids.h" | |
23 #include "chrome/browser/app_mode/app_mode_utils.h" | |
24 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | |
25 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" | |
26 #include "chrome/browser/browser_process.h" | |
27 #include "chrome/browser/chrome_notification_types.h" | |
28 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" | |
29 #include "chrome/browser/devtools/devtools_window.h" | |
30 #include "chrome/browser/download/download_service.h" | |
31 #include "chrome/browser/download/download_service_factory.h" | |
32 #include "chrome/browser/download/download_stats.h" | |
33 #include "chrome/browser/extensions/devtools_util.h" | |
34 #include "chrome/browser/extensions/extension_service.h" | |
35 #include "chrome/browser/guest_view/web_view/web_view_guest.h" | |
36 #include "chrome/browser/plugins/chrome_plugin_service_filter.h" | |
37 #include "chrome/browser/prefs/incognito_mode_prefs.h" | |
38 #include "chrome/browser/profiles/profile.h" | |
39 #include "chrome/browser/profiles/profile_io_data.h" | |
40 #include "chrome/browser/renderer_context_menu/context_menu_content_type_factory
.h" | |
41 #include "chrome/browser/renderer_context_menu/spellchecker_submenu_observer.h" | |
42 #include "chrome/browser/renderer_context_menu/spelling_menu_observer.h" | |
43 #include "chrome/browser/search/search.h" | |
44 #include "chrome/browser/search_engines/template_url_service_factory.h" | |
45 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" | |
46 #include "chrome/browser/spellchecker/spellcheck_service.h" | |
47 #include "chrome/browser/tab_contents/retargeting_details.h" | |
48 #include "chrome/browser/translate/chrome_translate_client.h" | |
49 #include "chrome/browser/translate/translate_service.h" | |
50 #include "chrome/browser/ui/browser.h" | |
51 #include "chrome/browser/ui/browser_commands.h" | |
52 #include "chrome/browser/ui/browser_finder.h" | |
53 #include "chrome/browser/ui/chrome_pages.h" | |
54 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h" | |
55 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" | |
56 #include "chrome/common/chrome_constants.h" | |
57 #include "chrome/common/chrome_switches.h" | |
58 #include "chrome/common/content_restriction.h" | |
59 #include "chrome/common/net/url_util.h" | |
60 #include "chrome/common/pref_names.h" | |
61 #include "chrome/common/render_messages.h" | |
62 #include "chrome/common/spellcheck_messages.h" | |
63 #include "chrome/common/url_constants.h" | |
64 #include "components/autocomplete/autocomplete_match.h" | |
65 #include "components/google/core/browser/google_util.h" | |
66 #include "components/metrics/proto/omnibox_input_type.pb.h" | |
67 #include "components/search_engines/template_url.h" | |
68 #include "components/search_engines/template_url_service.h" | |
69 #include "components/translate/core/browser/translate_download_manager.h" | |
70 #include "components/translate/core/browser/translate_manager.h" | |
71 #include "components/translate/core/browser/translate_prefs.h" | |
72 #include "components/user_prefs/user_prefs.h" | |
73 #include "content/public/browser/child_process_security_policy.h" | |
74 #include "content/public/browser/download_manager.h" | |
75 #include "content/public/browser/download_save_info.h" | |
76 #include "content/public/browser/download_url_parameters.h" | |
77 #include "content/public/browser/navigation_details.h" | |
78 #include "content/public/browser/navigation_entry.h" | |
79 #include "content/public/browser/notification_service.h" | |
80 #include "content/public/browser/render_frame_host.h" | 12 #include "content/public/browser/render_frame_host.h" |
81 #include "content/public/browser/render_process_host.h" | 13 #include "content/public/browser/render_process_host.h" |
82 #include "content/public/browser/render_view_host.h" | 14 #include "content/public/browser/render_view_host.h" |
83 #include "content/public/browser/render_widget_host_view.h" | 15 #include "content/public/browser/render_widget_host_view.h" |
84 #include "content/public/browser/user_metrics.h" | |
85 #include "content/public/browser/web_contents.h" | 16 #include "content/public/browser/web_contents.h" |
86 #include "content/public/common/menu_item.h" | 17 #include "content/public/common/menu_item.h" |
87 #include "content/public/common/ssl_status.h" | |
88 #include "content/public/common/url_utils.h" | |
89 #include "extensions/browser/extension_host.h" | 18 #include "extensions/browser/extension_host.h" |
90 #include "extensions/browser/extension_system.h" | 19 #include "extensions/browser/extension_system.h" |
91 #include "extensions/browser/view_type_utils.h" | 20 #include "extensions/browser/view_type_utils.h" |
92 #include "extensions/common/extension.h" | 21 #include "extensions/common/extension.h" |
93 #include "grit/generated_resources.h" | |
94 #include "net/base/escape.h" | |
95 #include "third_party/WebKit/public/web/WebContextMenuData.h" | 22 #include "third_party/WebKit/public/web/WebContextMenuData.h" |
96 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h" | |
97 #include "third_party/WebKit/public/web/WebPluginAction.h" | |
98 #include "ui/base/clipboard/clipboard.h" | |
99 #include "ui/base/l10n/l10n_util.h" | |
100 #include "ui/gfx/favicon_size.h" | |
101 #include "ui/gfx/point.h" | |
102 #include "ui/gfx/size.h" | |
103 #include "ui/gfx/text_elider.h" | |
104 | 23 |
105 #if defined(ENABLE_PRINTING) | |
106 #include "chrome/common/print_messages.h" | |
107 | |
108 #if defined(ENABLE_FULL_PRINTING) | |
109 #include "chrome/browser/printing/print_preview_context_menu_observer.h" | |
110 #include "chrome/browser/printing/print_preview_dialog_controller.h" | |
111 #include "chrome/browser/printing/print_view_manager.h" | |
112 #else | |
113 #include "chrome/browser/printing/print_view_manager_basic.h" | |
114 #endif // defined(ENABLE_FULL_PRINTING) | |
115 #endif // defined(ENABLE_PRINTING) | |
116 | |
117 using base::UserMetricsAction; | |
118 using blink::WebContextMenuData; | 24 using blink::WebContextMenuData; |
119 using blink::WebMediaPlayerAction; | |
120 using blink::WebPluginAction; | |
121 using blink::WebString; | 25 using blink::WebString; |
122 using blink::WebURL; | 26 using blink::WebURL; |
123 using content::BrowserContext; | 27 using content::BrowserContext; |
124 using content::ChildProcessSecurityPolicy; | |
125 using content::DownloadManager; | |
126 using content::DownloadUrlParameters; | |
127 using content::NavigationController; | |
128 using content::NavigationEntry; | |
129 using content::OpenURLParams; | 28 using content::OpenURLParams; |
130 using content::RenderFrameHost; | 29 using content::RenderFrameHost; |
131 using content::RenderViewHost; | 30 using content::RenderViewHost; |
132 using content::SSLStatus; | |
133 using content::WebContents; | 31 using content::WebContents; |
134 using extensions::ContextMenuMatcher; | |
135 using extensions::Extension; | |
136 using extensions::MenuItem; | |
137 using extensions::MenuManager; | |
138 | 32 |
139 namespace { | 33 namespace { |
140 | 34 |
141 const int kImageSearchThumbnailMinSize = 300 * 300; | 35 // The (inclusive) range of command IDs reserved for content's custom menus. |
142 const int kImageSearchThumbnailMaxWidth = 600; | 36 int content_context_custom_first = -1; |
143 const int kImageSearchThumbnailMaxHeight = 600; | 37 int content_context_custom_last = -1; |
144 | 38 |
145 // The range of command IDs reserved for content's custom menus. | 39 bool IsCustomItemEnabledInternal(const std::vector<content::MenuItem>& items, |
146 // TODO(oshima): These values will be injected by embedders. | 40 int id) { |
147 const int content_context_custom_first = IDC_CONTENT_CONTEXT_CUSTOM_FIRST; | 41 DCHECK(RenderViewContextMenuBase::IsContentCustomCommandId(id)); |
148 const int content_context_custom_last = IDC_CONTENT_CONTEXT_CUSTOM_LAST; | |
149 | |
150 // Maps UMA enumeration to IDC. IDC could be changed so we can't use | |
151 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|. | |
152 // Never change mapping or reuse |enum_id|. Always push back new items. | |
153 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand| | |
154 // could be deleted, but don't change the rest of |kUmaEnumToControlId|. | |
155 const struct UmaEnumCommandIdPair { | |
156 int enum_id; | |
157 int control_id; | |
158 } kUmaEnumToControlId[] = { | |
159 /* | |
160 enum id for 0, 1 are detected using | |
161 RenderViewContextMenu::IsContentCustomCommandId and | |
162 ContextMenuMatcher::IsExtensionsCustomCommandId | |
163 */ | |
164 {2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST}, | |
165 {3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB}, | |
166 {4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW}, | |
167 {5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD}, | |
168 {6, IDC_CONTENT_CONTEXT_SAVELINKAS}, | |
169 {7, IDC_CONTENT_CONTEXT_SAVEAVAS}, | |
170 {8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS}, | |
171 {9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION}, | |
172 {10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION}, | |
173 {11, IDC_CONTENT_CONTEXT_COPYAVLOCATION}, | |
174 {12, IDC_CONTENT_CONTEXT_COPYIMAGE}, | |
175 {13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB}, | |
176 {14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB}, | |
177 {15, IDC_CONTENT_CONTEXT_PLAYPAUSE}, | |
178 {16, IDC_CONTENT_CONTEXT_MUTE}, | |
179 {17, IDC_CONTENT_CONTEXT_LOOP}, | |
180 {18, IDC_CONTENT_CONTEXT_CONTROLS}, | |
181 {19, IDC_CONTENT_CONTEXT_ROTATECW}, | |
182 {20, IDC_CONTENT_CONTEXT_ROTATECCW}, | |
183 {21, IDC_BACK}, | |
184 {22, IDC_FORWARD}, | |
185 {23, IDC_SAVE_PAGE}, | |
186 {24, IDC_RELOAD}, | |
187 {25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP}, | |
188 {26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP}, | |
189 {27, IDC_PRINT}, | |
190 {28, IDC_VIEW_SOURCE}, | |
191 {29, IDC_CONTENT_CONTEXT_INSPECTELEMENT}, | |
192 {30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE}, | |
193 {31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO}, | |
194 {32, IDC_CONTENT_CONTEXT_TRANSLATE}, | |
195 {33, IDC_CONTENT_CONTEXT_RELOADFRAME}, | |
196 {34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE}, | |
197 {35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO}, | |
198 {36, IDC_CONTENT_CONTEXT_UNDO}, | |
199 {37, IDC_CONTENT_CONTEXT_REDO}, | |
200 {38, IDC_CONTENT_CONTEXT_CUT}, | |
201 {39, IDC_CONTENT_CONTEXT_COPY}, | |
202 {40, IDC_CONTENT_CONTEXT_PASTE}, | |
203 {41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE}, | |
204 {42, IDC_CONTENT_CONTEXT_DELETE}, | |
205 {43, IDC_CONTENT_CONTEXT_SELECTALL}, | |
206 {44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR}, | |
207 {45, IDC_CONTENT_CONTEXT_GOTOURL}, | |
208 {46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS}, | |
209 {47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS}, | |
210 {48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE}, | |
211 {52, IDC_CONTENT_CONTEXT_OPENLINKWITH}, | |
212 {53, IDC_CHECK_SPELLING_WHILE_TYPING}, | |
213 {54, IDC_SPELLCHECK_MENU}, | |
214 {55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE}, | |
215 {56, IDC_SPELLCHECK_LANGUAGES_FIRST}, | |
216 {57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE}, | |
217 {58, IDC_SPELLCHECK_SUGGESTION_0}, | |
218 {59, IDC_SPELLCHECK_ADD_TO_DICTIONARY}, | |
219 {60, IDC_SPELLPANEL_TOGGLE}, | |
220 // Add new items here and use |enum_id| from the next line. | |
221 {61, 0}, // Must be the last. Increment |enum_id| when new IDC was added. | |
222 }; | |
223 | |
224 // Collapses large ranges of ids before looking for UMA enum. | |
225 int CollapseCommandsForUMA(int id) { | |
226 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id)); | |
227 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id)); | |
228 | |
229 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST && | |
230 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) { | |
231 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST; | |
232 } | |
233 | |
234 if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST && | |
235 id <= IDC_SPELLCHECK_LANGUAGES_LAST) { | |
236 return IDC_SPELLCHECK_LANGUAGES_FIRST; | |
237 } | |
238 | |
239 if (id >= IDC_SPELLCHECK_SUGGESTION_0 && | |
240 id <= IDC_SPELLCHECK_SUGGESTION_LAST) { | |
241 return IDC_SPELLCHECK_SUGGESTION_0; | |
242 } | |
243 | |
244 return id; | |
245 } | |
246 | |
247 // Returns UMA enum value for command specified by |id| or -1 if not found. | |
248 int FindUMAEnumValueForCommand(int id) { | |
249 if (RenderViewContextMenu::IsContentCustomCommandId(id)) | |
250 return 0; | |
251 | |
252 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) | |
253 return 1; | |
254 | |
255 id = CollapseCommandsForUMA(id); | |
256 const size_t kMappingSize = arraysize(kUmaEnumToControlId); | |
257 for (size_t i = 0; i < kMappingSize; ++i) { | |
258 if (kUmaEnumToControlId[i].control_id == id) { | |
259 return kUmaEnumToControlId[i].enum_id; | |
260 } | |
261 } | |
262 return -1; | |
263 } | |
264 | |
265 // Increments histogram value for used items specified by |id|. | |
266 void RecordUsedItem(int id) { | |
267 int enum_id = FindUMAEnumValueForCommand(id); | |
268 if (enum_id != -1) { | |
269 const size_t kMappingSize = arraysize(kUmaEnumToControlId); | |
270 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id, | |
271 kUmaEnumToControlId[kMappingSize - 1].enum_id); | |
272 } else { | |
273 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id; | |
274 } | |
275 } | |
276 | |
277 // Increments histogram value for visible context menu item specified by |id|. | |
278 void RecordShownItem(int id) { | |
279 int enum_id = FindUMAEnumValueForCommand(id); | |
280 if (enum_id != -1) { | |
281 const size_t kMappingSize = arraysize(kUmaEnumToControlId); | |
282 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id, | |
283 kUmaEnumToControlId[kMappingSize - 1].enum_id); | |
284 } else { | |
285 // Just warning here. It's harder to maintain list of all possibly | |
286 // visible items than executable items. | |
287 DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id; | |
288 } | |
289 } | |
290 | |
291 // Usually a new tab is expected where this function is used, | |
292 // however users should be able to open a tab in background | |
293 // or in a new window. | |
294 WindowOpenDisposition ForceNewTabDispositionFromEventFlags( | |
295 int event_flags) { | |
296 WindowOpenDisposition disposition = | |
297 ui::DispositionFromEventFlags(event_flags); | |
298 return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition; | |
299 } | |
300 | |
301 bool IsCustomItemEnabled(const std::vector<content::MenuItem>& items, int id) { | |
302 DCHECK(RenderViewContextMenu::IsContentCustomCommandId(id)); | |
303 for (size_t i = 0; i < items.size(); ++i) { | 42 for (size_t i = 0; i < items.size(); ++i) { |
304 int action_id = | 43 int action_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId( |
305 RenderViewContextMenu::ConvertToContentCustomCommandId(items[i].action); | 44 items[i].action); |
306 if (action_id == id) | 45 if (action_id == id) |
307 return items[i].enabled; | 46 return items[i].enabled; |
308 if (items[i].type == content::MenuItem::SUBMENU) { | 47 if (items[i].type == content::MenuItem::SUBMENU) { |
309 if (IsCustomItemEnabled(items[i].submenu, id)) | 48 if (IsCustomItemEnabledInternal(items[i].submenu, id)) |
310 return true; | 49 return true; |
311 } | 50 } |
312 } | 51 } |
313 return false; | 52 return false; |
314 } | 53 } |
315 | 54 |
316 bool IsCustomItemChecked(const std::vector<content::MenuItem>& items, int id) { | 55 bool IsCustomItemCheckedInternal(const std::vector<content::MenuItem>& items, |
317 DCHECK(RenderViewContextMenu::IsContentCustomCommandId(id)); | 56 int id) { |
| 57 DCHECK(RenderViewContextMenuBase::IsContentCustomCommandId(id)); |
318 for (size_t i = 0; i < items.size(); ++i) { | 58 for (size_t i = 0; i < items.size(); ++i) { |
319 int action_id = | 59 int action_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId( |
320 RenderViewContextMenu::ConvertToContentCustomCommandId(items[i].action); | 60 items[i].action); |
321 if (action_id == id) | 61 if (action_id == id) |
322 return items[i].checked; | 62 return items[i].checked; |
323 if (items[i].type == content::MenuItem::SUBMENU) { | 63 if (items[i].type == content::MenuItem::SUBMENU) { |
324 if (IsCustomItemChecked(items[i].submenu, id)) | 64 if (IsCustomItemCheckedInternal(items[i].submenu, id)) |
325 return true; | 65 return true; |
326 } | 66 } |
327 } | 67 } |
328 return false; | 68 return false; |
329 } | 69 } |
330 | 70 |
331 const size_t kMaxCustomMenuDepth = 5; | 71 const size_t kMaxCustomMenuDepth = 5; |
332 const size_t kMaxCustomMenuTotalItems = 1000; | 72 const size_t kMaxCustomMenuTotalItems = 1000; |
333 | 73 |
334 void AddCustomItemsToMenu(const std::vector<content::MenuItem>& items, | 74 void AddCustomItemsToMenu(const std::vector<content::MenuItem>& items, |
335 size_t depth, | 75 size_t depth, |
336 size_t* total_items, | 76 size_t* total_items, |
337 ui::SimpleMenuModel::Delegate* delegate, | 77 ui::SimpleMenuModel::Delegate* delegate, |
338 ui::SimpleMenuModel* menu_model) { | 78 ui::SimpleMenuModel* menu_model) { |
339 if (depth > kMaxCustomMenuDepth) { | 79 if (depth > kMaxCustomMenuDepth) { |
340 LOG(ERROR) << "Custom menu too deeply nested."; | 80 LOG(ERROR) << "Custom menu too deeply nested."; |
341 return; | 81 return; |
342 } | 82 } |
343 for (size_t i = 0; i < items.size(); ++i) { | 83 for (size_t i = 0; i < items.size(); ++i) { |
344 int command_id = | 84 int command_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId( |
345 RenderViewContextMenu::ConvertToContentCustomCommandId(items[i].action); | 85 items[i].action); |
346 if (!RenderViewContextMenu::IsContentCustomCommandId(command_id)) { | 86 if (!RenderViewContextMenuBase::IsContentCustomCommandId(command_id)) { |
347 LOG(ERROR) << "Custom menu action value out of range."; | 87 LOG(ERROR) << "Custom menu action value out of range."; |
348 return; | 88 return; |
349 } | 89 } |
350 if (*total_items >= kMaxCustomMenuTotalItems) { | 90 if (*total_items >= kMaxCustomMenuTotalItems) { |
351 LOG(ERROR) << "Custom menu too large (too many items)."; | 91 LOG(ERROR) << "Custom menu too large (too many items)."; |
352 return; | 92 return; |
353 } | 93 } |
354 (*total_items)++; | 94 (*total_items)++; |
355 switch (items[i].type) { | 95 switch (items[i].type) { |
356 case content::MenuItem::OPTION: | 96 case content::MenuItem::OPTION: |
357 menu_model->AddItem( | 97 menu_model->AddItem( |
358 RenderViewContextMenu::ConvertToContentCustomCommandId( | 98 RenderViewContextMenuBase::ConvertToContentCustomCommandId( |
359 items[i].action), | 99 items[i].action), |
360 items[i].label); | 100 items[i].label); |
361 break; | 101 break; |
362 case content::MenuItem::CHECKABLE_OPTION: | 102 case content::MenuItem::CHECKABLE_OPTION: |
363 menu_model->AddCheckItem( | 103 menu_model->AddCheckItem( |
364 RenderViewContextMenu::ConvertToContentCustomCommandId( | 104 RenderViewContextMenuBase::ConvertToContentCustomCommandId( |
365 items[i].action), | 105 items[i].action), |
366 items[i].label); | 106 items[i].label); |
367 break; | 107 break; |
368 case content::MenuItem::GROUP: | 108 case content::MenuItem::GROUP: |
369 // TODO(viettrungluu): I don't know what this is supposed to do. | 109 // TODO(viettrungluu): I don't know what this is supposed to do. |
370 NOTREACHED(); | 110 NOTREACHED(); |
371 break; | 111 break; |
372 case content::MenuItem::SEPARATOR: | 112 case content::MenuItem::SEPARATOR: |
373 menu_model->AddSeparator(ui::NORMAL_SEPARATOR); | 113 menu_model->AddSeparator(ui::NORMAL_SEPARATOR); |
374 break; | 114 break; |
375 case content::MenuItem::SUBMENU: { | 115 case content::MenuItem::SUBMENU: { |
376 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate); | 116 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate); |
377 AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate, | 117 AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate, |
378 submenu); | 118 submenu); |
379 menu_model->AddSubMenu( | 119 menu_model->AddSubMenu( |
380 RenderViewContextMenu::ConvertToContentCustomCommandId( | 120 RenderViewContextMenuBase::ConvertToContentCustomCommandId( |
381 items[i].action), | 121 items[i].action), |
382 items[i].label, | 122 items[i].label, |
383 submenu); | 123 submenu); |
384 break; | 124 break; |
385 } | 125 } |
386 default: | 126 default: |
387 NOTREACHED(); | 127 NOTREACHED(); |
388 break; | 128 break; |
389 } | 129 } |
390 } | 130 } |
391 } | 131 } |
392 | 132 |
393 // Helper function to escape "&" as "&&". | |
394 void EscapeAmpersands(base::string16* text) { | |
395 base::ReplaceChars(*text, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"), | |
396 text); | |
397 } | |
398 | |
399 // Returns the preference of the profile represented by the |context|. | |
400 PrefService* GetPrefs(content::BrowserContext* context) { | |
401 return user_prefs::UserPrefs::Get(context); | |
402 } | |
403 | |
404 } // namespace | 133 } // namespace |
405 | 134 |
406 // static | 135 // static |
407 const size_t RenderViewContextMenu::kMaxSelectionTextLength = 50; | 136 void RenderViewContextMenuBase::SetContentCustomCommandIdRange( |
| 137 int first, int last) { |
| 138 // The range is inclusive. |
| 139 content_context_custom_first = first; |
| 140 content_context_custom_last = last; |
| 141 } |
408 | 142 |
409 // static | 143 // static |
410 int RenderViewContextMenu::ConvertToContentCustomCommandId(int id) { | 144 const size_t RenderViewContextMenuBase::kMaxSelectionTextLength = 50; |
| 145 |
| 146 // static |
| 147 int RenderViewContextMenuBase::ConvertToContentCustomCommandId(int id) { |
411 return content_context_custom_first + id; | 148 return content_context_custom_first + id; |
412 } | 149 } |
413 | 150 |
414 // static | 151 // static |
415 bool RenderViewContextMenu::IsContentCustomCommandId(int id) { | 152 bool RenderViewContextMenuBase::IsContentCustomCommandId(int id) { |
416 return id >= content_context_custom_first && | 153 return id >= content_context_custom_first && |
417 id <= content_context_custom_last; | 154 id <= content_context_custom_last; |
418 } | 155 } |
419 | 156 |
420 // static | 157 RenderViewContextMenuBase::RenderViewContextMenuBase( |
421 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) { | |
422 return url.SchemeIs(content::kChromeDevToolsScheme); | |
423 } | |
424 | |
425 // static | |
426 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) { | |
427 if (!url.SchemeIs(content::kChromeUIScheme)) | |
428 return false; | |
429 return url.host() == chrome::kChromeUISyncResourcesHost; | |
430 } | |
431 | |
432 static const int kSpellcheckRadioGroup = 1; | |
433 | |
434 RenderViewContextMenu::RenderViewContextMenu( | |
435 content::RenderFrameHost* render_frame_host, | 158 content::RenderFrameHost* render_frame_host, |
436 const content::ContextMenuParams& params) | 159 const content::ContextMenuParams& params) |
437 : params_(params), | 160 : params_(params), |
438 source_web_contents_(WebContents::FromRenderFrameHost(render_frame_host)), | 161 source_web_contents_(WebContents::FromRenderFrameHost(render_frame_host)), |
439 render_process_id_(render_frame_host->GetProcess()->GetID()), | |
440 render_frame_id_(render_frame_host->GetRoutingID()), | |
441 browser_context_(source_web_contents_->GetBrowserContext()), | 162 browser_context_(source_web_contents_->GetBrowserContext()), |
442 menu_model_(this), | 163 menu_model_(this), |
443 extension_items_(browser_context_, | 164 command_executed_(false), |
444 this, | 165 render_process_id_(render_frame_host->GetProcess()->GetID()), |
445 &menu_model_, | 166 render_frame_id_(render_frame_host->GetRoutingID()) { |
446 base::Bind(MenuItemMatchesParams, params_)), | |
447 protocol_handler_submenu_model_(this), | |
448 protocol_handler_registry_( | |
449 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())), | |
450 command_executed_(false) { | |
451 content_type_.reset(ContextMenuContentTypeFactory::Create( | |
452 source_web_contents_, params)); | |
453 } | 167 } |
454 | 168 |
455 RenderViewContextMenu::~RenderViewContextMenu() { | 169 RenderViewContextMenuBase::~RenderViewContextMenuBase() { |
456 } | 170 } |
457 | 171 |
458 // Menu construction functions ------------------------------------------------- | 172 // Menu construction functions ------------------------------------------------- |
459 | 173 |
460 void RenderViewContextMenu::Init() { | 174 void RenderViewContextMenuBase::Init() { |
| 175 // Command id range must have been already initializerd. |
| 176 DCHECK_NE(-1, content_context_custom_first); |
| 177 DCHECK_NE(-1, content_context_custom_last); |
| 178 |
461 InitMenu(); | 179 InitMenu(); |
462 if (toolkit_delegate_) | 180 if (toolkit_delegate_) |
463 toolkit_delegate_->Init(&menu_model_); | 181 toolkit_delegate_->Init(&menu_model_); |
464 } | 182 } |
465 | 183 |
466 void RenderViewContextMenu::Cancel() { | 184 void RenderViewContextMenuBase::Cancel() { |
467 if (toolkit_delegate_) | 185 if (toolkit_delegate_) |
468 toolkit_delegate_->Cancel(); | 186 toolkit_delegate_->Cancel(); |
469 } | 187 } |
470 | 188 |
471 static bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns, | 189 void RenderViewContextMenuBase::InitMenu() { |
472 const GURL& url) { | |
473 // No patterns means no restriction, so that implicitly matches. | |
474 if (patterns.is_empty()) | |
475 return true; | |
476 return patterns.MatchesURL(url); | |
477 } | |
478 | |
479 // static | |
480 bool RenderViewContextMenu::ExtensionContextAndPatternMatch( | |
481 const content::ContextMenuParams& params, | |
482 MenuItem::ContextList contexts, | |
483 const extensions::URLPatternSet& target_url_patterns) { | |
484 const bool has_link = !params.link_url.is_empty(); | |
485 const bool has_selection = !params.selection_text.empty(); | |
486 const bool in_frame = !params.frame_url.is_empty(); | |
487 | |
488 if (contexts.Contains(MenuItem::ALL) || | |
489 (has_selection && contexts.Contains(MenuItem::SELECTION)) || | |
490 (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) || | |
491 (in_frame && contexts.Contains(MenuItem::FRAME))) | |
492 return true; | |
493 | |
494 if (has_link && contexts.Contains(MenuItem::LINK) && | |
495 ExtensionPatternMatch(target_url_patterns, params.link_url)) | |
496 return true; | |
497 | |
498 switch (params.media_type) { | |
499 case WebContextMenuData::MediaTypeImage: | |
500 if (contexts.Contains(MenuItem::IMAGE) && | |
501 ExtensionPatternMatch(target_url_patterns, params.src_url)) | |
502 return true; | |
503 break; | |
504 | |
505 case WebContextMenuData::MediaTypeVideo: | |
506 if (contexts.Contains(MenuItem::VIDEO) && | |
507 ExtensionPatternMatch(target_url_patterns, params.src_url)) | |
508 return true; | |
509 break; | |
510 | |
511 case WebContextMenuData::MediaTypeAudio: | |
512 if (contexts.Contains(MenuItem::AUDIO) && | |
513 ExtensionPatternMatch(target_url_patterns, params.src_url)) | |
514 return true; | |
515 break; | |
516 | |
517 default: | |
518 break; | |
519 } | |
520 | |
521 // PAGE is the least specific context, so we only examine that if none of the | |
522 // other contexts apply (except for FRAME, which is included in PAGE for | |
523 // backwards compatibility). | |
524 if (!has_link && !has_selection && !params.is_editable && | |
525 params.media_type == WebContextMenuData::MediaTypeNone && | |
526 contexts.Contains(MenuItem::PAGE)) | |
527 return true; | |
528 | |
529 return false; | |
530 } | |
531 | |
532 static const GURL& GetDocumentURL(const content::ContextMenuParams& params) { | |
533 return params.frame_url.is_empty() ? params.page_url : params.frame_url; | |
534 } | |
535 | |
536 // static | |
537 bool RenderViewContextMenu::MenuItemMatchesParams( | |
538 const content::ContextMenuParams& params, | |
539 const extensions::MenuItem* item) { | |
540 bool match = ExtensionContextAndPatternMatch(params, item->contexts(), | |
541 item->target_url_patterns()); | |
542 if (!match) | |
543 return false; | |
544 | |
545 const GURL& document_url = GetDocumentURL(params); | |
546 return ExtensionPatternMatch(item->document_url_patterns(), document_url); | |
547 } | |
548 | |
549 void RenderViewContextMenu::AppendAllExtensionItems() { | |
550 extension_items_.Clear(); | |
551 ExtensionService* service = | |
552 extensions::ExtensionSystem::Get(browser_context_)->extension_service(); | |
553 if (!service) | |
554 return; // In unit-tests, we may not have an ExtensionService. | |
555 | |
556 MenuManager* menu_manager = MenuManager::Get(browser_context_); | |
557 if (!menu_manager) | |
558 return; | |
559 | |
560 base::string16 printable_selection_text = PrintableSelectionText(); | |
561 EscapeAmpersands(&printable_selection_text); | |
562 | |
563 // Get a list of extension id's that have context menu items, and sort by the | |
564 // top level context menu title of the extension. | |
565 std::set<MenuItem::ExtensionKey> ids = menu_manager->ExtensionIds(); | |
566 std::vector<base::string16> sorted_menu_titles; | |
567 std::map<base::string16, std::string> map_ids; | |
568 for (std::set<MenuItem::ExtensionKey>::iterator i = ids.begin(); | |
569 i != ids.end(); | |
570 ++i) { | |
571 const Extension* extension = | |
572 service->GetExtensionById(i->extension_id, false); | |
573 // Platform apps have their context menus created directly in | |
574 // AppendPlatformAppItems. | |
575 if (extension && !extension->is_platform_app()) { | |
576 base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle( | |
577 *i, printable_selection_text); | |
578 map_ids[menu_title] = i->extension_id; | |
579 sorted_menu_titles.push_back(menu_title); | |
580 } | |
581 } | |
582 if (sorted_menu_titles.empty()) | |
583 return; | |
584 | |
585 const std::string app_locale = g_browser_process->GetApplicationLocale(); | |
586 l10n_util::SortStrings16(app_locale, &sorted_menu_titles); | |
587 | |
588 int index = 0; | |
589 base::TimeTicks begin = base::TimeTicks::Now(); | |
590 for (size_t i = 0; i < sorted_menu_titles.size(); ++i) { | |
591 const std::string& id = map_ids[sorted_menu_titles[i]]; | |
592 const MenuItem::ExtensionKey extension_key(id); | |
593 extension_items_.AppendExtensionItems( | |
594 extension_key, printable_selection_text, &index); | |
595 } | |
596 | |
597 UMA_HISTOGRAM_TIMES("Extensions.ContextMenus_BuildTime", | |
598 base::TimeTicks::Now() - begin); | |
599 UMA_HISTOGRAM_COUNTS("Extensions.ContextMenus_ItemCount", index); | |
600 } | |
601 | |
602 void RenderViewContextMenu::AppendCurrentExtensionItems() { | |
603 // Avoid appending extension related items when |extension| is null. | |
604 // For Panel, this happens when the panel is navigated to a url outside of the | |
605 // extension's package. | |
606 const Extension* extension = GetExtension(); | |
607 if (extension) { | |
608 // Only add extension items from this extension. | |
609 int index = 0; | |
610 const MenuItem::ExtensionKey key( | |
611 extension->id(), WebViewGuest::GetViewInstanceId(source_web_contents_)); | |
612 extension_items_.AppendExtensionItems( | |
613 key, PrintableSelectionText(), &index); | |
614 } | |
615 } | |
616 | |
617 void RenderViewContextMenu::InitMenu() { | |
618 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_CUSTOM)) { | 190 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_CUSTOM)) { |
619 AppendCustomItems(); | 191 AppendCustomItems(); |
620 | 192 |
621 const bool has_selection = !params_.selection_text.empty(); | 193 const bool has_selection = !params_.selection_text.empty(); |
622 if (has_selection) { | 194 if (has_selection) { |
623 // We will add more items if there's a selection, so add a separator. | 195 // We will add more items if there's a selection, so add a separator. |
624 // TODO(lazyboy): Clean up separator logic. | 196 // TODO(lazyboy): Clean up separator logic. |
625 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | 197 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); |
626 } | 198 } |
627 } | 199 } |
628 | |
629 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE)) | |
630 AppendPageItems(); | |
631 | |
632 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME)) { | |
633 // Merge in frame items with page items if we clicked within a frame that | |
634 // needs them. | |
635 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
636 AppendFrameItems(); | |
637 } | |
638 | |
639 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK)) { | |
640 AppendLinkItems(); | |
641 if (params_.media_type != WebContextMenuData::MediaTypeNone) | |
642 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
643 } | |
644 | |
645 if (content_type_->SupportsGroup( | |
646 ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE)) { | |
647 AppendImageItems(); | |
648 } | |
649 | |
650 if (content_type_->SupportsGroup( | |
651 ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)) { | |
652 AppendSearchWebForImageItems(); | |
653 } | |
654 | |
655 if (content_type_->SupportsGroup( | |
656 ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)) { | |
657 AppendVideoItems(); | |
658 } | |
659 | |
660 if (content_type_->SupportsGroup( | |
661 ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO)) { | |
662 AppendAudioItems(); | |
663 } | |
664 | |
665 if (content_type_->SupportsGroup( | |
666 ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS)) { | |
667 AppendCanvasItems(); | |
668 } | |
669 | |
670 if (content_type_->SupportsGroup( | |
671 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) { | |
672 AppendPluginItems(); | |
673 } | |
674 | |
675 // ITEM_GROUP_MEDIA_FILE has no specific items. | |
676 | |
677 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE)) | |
678 AppendEditableItems(); | |
679 | |
680 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) { | |
681 DCHECK(!content_type_->SupportsGroup( | |
682 ContextMenuContentType::ITEM_GROUP_EDITABLE)); | |
683 AppendCopyItem(); | |
684 } | |
685 | |
686 if (content_type_->SupportsGroup( | |
687 ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER)) { | |
688 AppendSearchProvider(); | |
689 } | |
690 | |
691 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)) | |
692 AppendPrintItem(); | |
693 | |
694 if (content_type_->SupportsGroup( | |
695 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION)) { | |
696 DCHECK(!content_type_->SupportsGroup( | |
697 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION)); | |
698 AppendAllExtensionItems(); | |
699 } | |
700 | |
701 if (content_type_->SupportsGroup( | |
702 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION)) { | |
703 DCHECK(!content_type_->SupportsGroup( | |
704 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION)); | |
705 AppendCurrentExtensionItems(); | |
706 } | |
707 | |
708 if (content_type_->SupportsGroup( | |
709 ContextMenuContentType::ITEM_GROUP_DEVELOPER)) { | |
710 AppendDeveloperItems(); | |
711 } | |
712 | |
713 if (content_type_->SupportsGroup( | |
714 ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT)) { | |
715 AppendDevtoolsForUnpackedExtensions(); | |
716 } | |
717 | |
718 if (content_type_->SupportsGroup( | |
719 ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW)) { | |
720 AppendPrintPreviewItems(); | |
721 } | |
722 } | 200 } |
723 | 201 |
724 Profile* RenderViewContextMenu::GetProfile() { | 202 void RenderViewContextMenuBase::AddMenuItem(int command_id, |
725 return Profile::FromBrowserContext(browser_context_); | 203 const base::string16& title) { |
726 } | |
727 | |
728 void RenderViewContextMenu::AppendPrintPreviewItems() { | |
729 #if defined(ENABLE_FULL_PRINTING) | |
730 if (!print_preview_menu_observer_.get()) { | |
731 print_preview_menu_observer_.reset( | |
732 new PrintPreviewContextMenuObserver(source_web_contents_)); | |
733 } | |
734 | |
735 observers_.AddObserver(print_preview_menu_observer_.get()); | |
736 #endif | |
737 } | |
738 | |
739 const Extension* RenderViewContextMenu::GetExtension() const { | |
740 extensions::ExtensionSystem* system = | |
741 extensions::ExtensionSystem::Get(browser_context_); | |
742 // There is no process manager in some tests. | |
743 if (!system->process_manager()) | |
744 return NULL; | |
745 | |
746 return system->process_manager()->GetExtensionForRenderViewHost( | |
747 source_web_contents_->GetRenderViewHost()); | |
748 } | |
749 | |
750 void RenderViewContextMenu::AddMenuItem(int command_id, | |
751 const base::string16& title) { | |
752 menu_model_.AddItem(command_id, title); | 204 menu_model_.AddItem(command_id, title); |
753 } | 205 } |
754 | 206 |
755 void RenderViewContextMenu::AddCheckItem(int command_id, | 207 void RenderViewContextMenuBase::AddCheckItem(int command_id, |
756 const base::string16& title) { | 208 const base::string16& title) { |
757 menu_model_.AddCheckItem(command_id, title); | 209 menu_model_.AddCheckItem(command_id, title); |
758 } | 210 } |
759 | 211 |
760 void RenderViewContextMenu::AddSeparator() { | 212 void RenderViewContextMenuBase::AddSeparator() { |
761 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | 213 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); |
762 } | 214 } |
763 | 215 |
764 void RenderViewContextMenu::AddSubMenu(int command_id, | 216 void RenderViewContextMenuBase::AddSubMenu(int command_id, |
765 const base::string16& label, | 217 const base::string16& label, |
766 ui::MenuModel* model) { | 218 ui::MenuModel* model) { |
767 menu_model_.AddSubMenu(command_id, label, model); | 219 menu_model_.AddSubMenu(command_id, label, model); |
768 } | 220 } |
769 | 221 |
770 void RenderViewContextMenu::UpdateMenuItem(int command_id, | 222 void RenderViewContextMenuBase::UpdateMenuItem(int command_id, |
771 bool enabled, | 223 bool enabled, |
772 bool hidden, | 224 bool hidden, |
773 const base::string16& label) { | 225 const base::string16& label) { |
774 if (toolkit_delegate_) { | 226 if (toolkit_delegate_) { |
775 toolkit_delegate_->UpdateMenuItem(command_id, | 227 toolkit_delegate_->UpdateMenuItem(command_id, |
776 enabled, | 228 enabled, |
777 hidden, | 229 hidden, |
778 label); | 230 label); |
779 } | 231 } |
780 } | 232 } |
781 | 233 |
782 RenderViewHost* RenderViewContextMenu::GetRenderViewHost() const { | 234 RenderViewHost* RenderViewContextMenuBase::GetRenderViewHost() const { |
783 return source_web_contents_->GetRenderViewHost(); | 235 return source_web_contents_->GetRenderViewHost(); |
784 } | 236 } |
785 | 237 |
786 WebContents* RenderViewContextMenu::GetWebContents() const { | 238 WebContents* RenderViewContextMenuBase::GetWebContents() const { |
787 return source_web_contents_; | 239 return source_web_contents_; |
788 } | 240 } |
789 | 241 |
790 BrowserContext* RenderViewContextMenu::GetBrowserContext() const { | 242 BrowserContext* RenderViewContextMenuBase::GetBrowserContext() const { |
791 return browser_context_; | 243 return browser_context_; |
792 } | 244 } |
793 | 245 |
794 bool RenderViewContextMenu::AppendCustomItems() { | 246 bool RenderViewContextMenuBase::AppendCustomItems() { |
795 size_t total_items = 0; | 247 size_t total_items = 0; |
796 AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this, | 248 AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this, |
797 &menu_model_); | 249 &menu_model_); |
798 return total_items > 0; | 250 return total_items > 0; |
799 } | 251 } |
800 | 252 |
801 void RenderViewContextMenu::AppendDeveloperItems() { | |
802 // Show Inspect Element in DevTools itself only in case of the debug | |
803 // devtools build. | |
804 bool show_developer_items = !IsDevToolsURL(params_.page_url); | |
805 | |
806 #if defined(DEBUG_DEVTOOLS) | |
807 show_developer_items = true; | |
808 #endif | |
809 | |
810 if (!show_developer_items) | |
811 return; | |
812 | |
813 // In the DevTools popup menu, "developer items" is normally the only | |
814 // section, so omit the separator there. | |
815 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
816 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT, | |
817 IDS_CONTENT_CONTEXT_INSPECTELEMENT); | |
818 } | |
819 | |
820 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() { | |
821 // Add a separator if there are any items already in the menu. | |
822 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
823 | |
824 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP, | |
825 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP); | |
826 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP, | |
827 IDS_CONTENT_CONTEXT_RESTART_APP); | |
828 AppendDeveloperItems(); | |
829 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE, | |
830 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE); | |
831 } | |
832 | |
833 void RenderViewContextMenu::AppendLinkItems() { | |
834 if (!params_.link_url.is_empty()) { | |
835 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB, | |
836 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB); | |
837 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW, | |
838 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW); | |
839 if (params_.link_url.is_valid()) { | |
840 AppendProtocolHandlerSubMenu(); | |
841 } | |
842 | |
843 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD, | |
844 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD); | |
845 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS, | |
846 IDS_CONTENT_CONTEXT_SAVELINKAS); | |
847 } | |
848 | |
849 menu_model_.AddItemWithStringId( | |
850 IDC_CONTENT_CONTEXT_COPYLINKLOCATION, | |
851 params_.link_url.SchemeIs(url::kMailToScheme) ? | |
852 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS : | |
853 IDS_CONTENT_CONTEXT_COPYLINKLOCATION); | |
854 } | |
855 | |
856 void RenderViewContextMenu::AppendImageItems() { | |
857 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS, | |
858 IDS_CONTENT_CONTEXT_SAVEIMAGEAS); | |
859 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION, | |
860 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION); | |
861 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE, | |
862 IDS_CONTENT_CONTEXT_COPYIMAGE); | |
863 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB, | |
864 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB); | |
865 } | |
866 | |
867 void RenderViewContextMenu::AppendSearchWebForImageItems() { | |
868 TemplateURLService* service = | |
869 TemplateURLServiceFactory::GetForProfile(GetProfile()); | |
870 const TemplateURL* const default_provider = | |
871 service->GetDefaultSearchProvider(); | |
872 if (params_.has_image_contents && default_provider && | |
873 !default_provider->image_url().empty() && | |
874 default_provider->image_url_ref().IsValid(service->search_terms_data())) { | |
875 menu_model_.AddItem( | |
876 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE, | |
877 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE, | |
878 default_provider->short_name())); | |
879 } | |
880 } | |
881 | |
882 void RenderViewContextMenu::AppendAudioItems() { | |
883 AppendMediaItems(); | |
884 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
885 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, | |
886 IDS_CONTENT_CONTEXT_SAVEAUDIOAS); | |
887 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION, | |
888 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION); | |
889 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB, | |
890 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB); | |
891 } | |
892 | |
893 void RenderViewContextMenu::AppendCanvasItems() { | |
894 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS, | |
895 IDS_CONTENT_CONTEXT_SAVEIMAGEAS); | |
896 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE, | |
897 IDS_CONTENT_CONTEXT_COPYIMAGE); | |
898 } | |
899 | |
900 void RenderViewContextMenu::AppendVideoItems() { | |
901 AppendMediaItems(); | |
902 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
903 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, | |
904 IDS_CONTENT_CONTEXT_SAVEVIDEOAS); | |
905 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION, | |
906 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION); | |
907 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB, | |
908 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB); | |
909 } | |
910 | |
911 void RenderViewContextMenu::AppendMediaItems() { | |
912 int media_flags = params_.media_flags; | |
913 | |
914 menu_model_.AddItemWithStringId( | |
915 IDC_CONTENT_CONTEXT_PLAYPAUSE, | |
916 media_flags & WebContextMenuData::MediaPaused ? | |
917 IDS_CONTENT_CONTEXT_PLAY : | |
918 IDS_CONTENT_CONTEXT_PAUSE); | |
919 | |
920 menu_model_.AddItemWithStringId( | |
921 IDC_CONTENT_CONTEXT_MUTE, | |
922 media_flags & WebContextMenuData::MediaMuted ? | |
923 IDS_CONTENT_CONTEXT_UNMUTE : | |
924 IDS_CONTENT_CONTEXT_MUTE); | |
925 | |
926 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP, | |
927 IDS_CONTENT_CONTEXT_LOOP); | |
928 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS, | |
929 IDS_CONTENT_CONTEXT_CONTROLS); | |
930 } | |
931 | |
932 void RenderViewContextMenu::AppendPluginItems() { | |
933 if (params_.page_url == params_.src_url) { | |
934 // Full page plugin, so show page menu items. | |
935 if (params_.link_url.is_empty() && params_.selection_text.empty()) | |
936 AppendPageItems(); | |
937 } else { | |
938 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, | |
939 IDS_CONTENT_CONTEXT_SAVEPAGEAS); | |
940 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT); | |
941 } | |
942 | |
943 if (params_.media_flags & WebContextMenuData::MediaCanRotate) { | |
944 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
945 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW, | |
946 IDS_CONTENT_CONTEXT_ROTATECW); | |
947 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW, | |
948 IDS_CONTENT_CONTEXT_ROTATECCW); | |
949 } | |
950 } | |
951 | |
952 void RenderViewContextMenu::AppendPageItems() { | |
953 menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK); | |
954 menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD); | |
955 menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD); | |
956 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
957 menu_model_.AddItemWithStringId(IDC_SAVE_PAGE, | |
958 IDS_CONTENT_CONTEXT_SAVEPAGEAS); | |
959 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT); | |
960 | |
961 if (TranslateService::IsTranslatableURL(params_.page_url)) { | |
962 std::string locale = g_browser_process->GetApplicationLocale(); | |
963 locale = translate::TranslateDownloadManager::GetLanguageCode(locale); | |
964 base::string16 language = | |
965 l10n_util::GetDisplayNameForLocale(locale, locale, true); | |
966 menu_model_.AddItem( | |
967 IDC_CONTENT_CONTEXT_TRANSLATE, | |
968 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language)); | |
969 } | |
970 | |
971 menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE, | |
972 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE); | |
973 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO, | |
974 IDS_CONTENT_CONTEXT_VIEWPAGEINFO); | |
975 } | |
976 | |
977 void RenderViewContextMenu::AppendFrameItems() { | |
978 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME, | |
979 IDS_CONTENT_CONTEXT_RELOADFRAME); | |
980 // These two menu items have yet to be implemented. | |
981 // http://code.google.com/p/chromium/issues/detail?id=11827 | |
982 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS | |
983 // IDS_CONTENT_CONTEXT_PRINTFRAME | |
984 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE, | |
985 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE); | |
986 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO, | |
987 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO); | |
988 } | |
989 | |
990 void RenderViewContextMenu::AppendCopyItem() { | |
991 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY, | |
992 IDS_CONTENT_CONTEXT_COPY); | |
993 } | |
994 | |
995 void RenderViewContextMenu::AppendPrintItem() { | |
996 if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) && | |
997 (params_.media_type == WebContextMenuData::MediaTypeNone || | |
998 params_.media_flags & WebContextMenuData::MediaCanPrint)) { | |
999 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT); | |
1000 } | |
1001 } | |
1002 | |
1003 void RenderViewContextMenu::AppendSearchProvider() { | |
1004 DCHECK(browser_context_); | |
1005 | |
1006 base::TrimWhitespace(params_.selection_text, base::TRIM_ALL, | |
1007 ¶ms_.selection_text); | |
1008 if (params_.selection_text.empty()) | |
1009 return; | |
1010 | |
1011 base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars, | |
1012 base::ASCIIToUTF16(" "), ¶ms_.selection_text); | |
1013 | |
1014 AutocompleteMatch match; | |
1015 AutocompleteClassifierFactory::GetForProfile(GetProfile()) | |
1016 ->Classify(params_.selection_text, | |
1017 false, | |
1018 false, | |
1019 metrics::OmniboxEventProto::INVALID_SPEC, | |
1020 &match, | |
1021 NULL); | |
1022 selection_navigation_url_ = match.destination_url; | |
1023 if (!selection_navigation_url_.is_valid()) | |
1024 return; | |
1025 | |
1026 base::string16 printable_selection_text = PrintableSelectionText(); | |
1027 EscapeAmpersands(&printable_selection_text); | |
1028 | |
1029 if (AutocompleteMatch::IsSearchType(match.type)) { | |
1030 const TemplateURL* const default_provider = | |
1031 TemplateURLServiceFactory::GetForProfile(GetProfile()) | |
1032 ->GetDefaultSearchProvider(); | |
1033 if (!default_provider) | |
1034 return; | |
1035 menu_model_.AddItem( | |
1036 IDC_CONTENT_CONTEXT_SEARCHWEBFOR, | |
1037 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR, | |
1038 default_provider->short_name(), | |
1039 printable_selection_text)); | |
1040 } else { | |
1041 if ((selection_navigation_url_ != params_.link_url) && | |
1042 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme( | |
1043 selection_navigation_url_.scheme())) { | |
1044 menu_model_.AddItem( | |
1045 IDC_CONTENT_CONTEXT_GOTOURL, | |
1046 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL, | |
1047 printable_selection_text)); | |
1048 } | |
1049 } | |
1050 } | |
1051 | |
1052 void RenderViewContextMenu::AppendEditableItems() { | |
1053 const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode(); | |
1054 | |
1055 if (use_spellcheck_and_search) | |
1056 AppendSpellingSuggestionsSubMenu(); | |
1057 | |
1058 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO, | |
1059 IDS_CONTENT_CONTEXT_UNDO); | |
1060 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO, | |
1061 IDS_CONTENT_CONTEXT_REDO); | |
1062 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
1063 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT, | |
1064 IDS_CONTENT_CONTEXT_CUT); | |
1065 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY, | |
1066 IDS_CONTENT_CONTEXT_COPY); | |
1067 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE, | |
1068 IDS_CONTENT_CONTEXT_PASTE); | |
1069 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE, | |
1070 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE); | |
1071 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE, | |
1072 IDS_CONTENT_CONTEXT_DELETE); | |
1073 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
1074 | |
1075 if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) { | |
1076 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE, | |
1077 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE); | |
1078 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
1079 } | |
1080 | |
1081 if (use_spellcheck_and_search) | |
1082 AppendSpellcheckOptionsSubMenu(); | |
1083 AppendPlatformEditableItems(); | |
1084 | |
1085 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
1086 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL, | |
1087 IDS_CONTENT_CONTEXT_SELECTALL); | |
1088 } | |
1089 | |
1090 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() { | |
1091 if (!spelling_menu_observer_.get()) | |
1092 spelling_menu_observer_.reset(new SpellingMenuObserver(this)); | |
1093 observers_.AddObserver(spelling_menu_observer_.get()); | |
1094 spelling_menu_observer_->InitMenu(params_); | |
1095 } | |
1096 | |
1097 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() { | |
1098 if (!spellchecker_submenu_observer_.get()) { | |
1099 spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver( | |
1100 this, this, kSpellcheckRadioGroup)); | |
1101 } | |
1102 spellchecker_submenu_observer_->InitMenu(params_); | |
1103 observers_.AddObserver(spellchecker_submenu_observer_.get()); | |
1104 } | |
1105 | |
1106 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() { | |
1107 const ProtocolHandlerRegistry::ProtocolHandlerList handlers = | |
1108 GetHandlersForLinkUrl(); | |
1109 if (handlers.empty()) | |
1110 return; | |
1111 size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST - | |
1112 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST; | |
1113 for (size_t i = 0; i < handlers.size() && i <= max; i++) { | |
1114 protocol_handler_submenu_model_.AddItem( | |
1115 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i, | |
1116 base::UTF8ToUTF16(handlers[i].url().host())); | |
1117 } | |
1118 protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR); | |
1119 protocol_handler_submenu_model_.AddItem( | |
1120 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS, | |
1121 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE)); | |
1122 | |
1123 menu_model_.AddSubMenu( | |
1124 IDC_CONTENT_CONTEXT_OPENLINKWITH, | |
1125 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH), | |
1126 &protocol_handler_submenu_model_); | |
1127 } | |
1128 | |
1129 void RenderViewContextMenu::AppendPlatformEditableItems() { | |
1130 } | |
1131 | |
1132 // Menu delegate functions ----------------------------------------------------- | 253 // Menu delegate functions ----------------------------------------------------- |
1133 | 254 |
1134 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const { | 255 bool RenderViewContextMenuBase::IsCommandIdEnabled(int id) const { |
1135 // If this command is is added by one of our observers, we dispatch it to the | 256 // If this command is is added by one of our observers, we dispatch |
1136 // observer. | 257 // it to the observer. |
1137 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_); | 258 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_); |
1138 RenderViewContextMenuObserver* observer; | 259 RenderViewContextMenuObserver* observer; |
1139 while ((observer = it.GetNext()) != NULL) { | 260 while ((observer = it.GetNext()) != NULL) { |
1140 if (observer->IsCommandIdSupported(id)) | 261 if (observer->IsCommandIdSupported(id)) |
1141 return observer->IsCommandIdEnabled(id); | 262 return observer->IsCommandIdEnabled(id); |
1142 } | 263 } |
1143 | 264 |
1144 CoreTabHelper* core_tab_helper = | |
1145 CoreTabHelper::FromWebContents(source_web_contents_); | |
1146 int content_restrictions = 0; | |
1147 if (core_tab_helper) | |
1148 content_restrictions = core_tab_helper->content_restrictions(); | |
1149 if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT)) | |
1150 return false; | |
1151 | |
1152 if (id == IDC_SAVE_PAGE && | |
1153 (content_restrictions & CONTENT_RESTRICTION_SAVE)) { | |
1154 return false; | |
1155 } | |
1156 | |
1157 PrefService* prefs = GetPrefs(browser_context_); | |
1158 | |
1159 // Allow Spell Check language items on sub menu for text area context menu. | |
1160 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) && | |
1161 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) { | |
1162 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck); | |
1163 } | |
1164 | |
1165 // Custom items. | 265 // Custom items. |
1166 if (IsContentCustomCommandId(id)) | 266 if (IsContentCustomCommandId(id)) |
1167 return IsCustomItemEnabled(params_.custom_items, id); | 267 return IsCustomItemEnabled(id); |
1168 | 268 |
1169 // Extension items. | 269 return false; |
1170 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) | |
1171 return extension_items_.IsCommandIdEnabled(id); | |
1172 | |
1173 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST && | |
1174 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) { | |
1175 return true; | |
1176 } | |
1177 | |
1178 IncognitoModePrefs::Availability incognito_avail = | |
1179 IncognitoModePrefs::GetAvailability(prefs); | |
1180 switch (id) { | |
1181 case IDC_BACK: | |
1182 return source_web_contents_->GetController().CanGoBack(); | |
1183 | |
1184 case IDC_FORWARD: | |
1185 return source_web_contents_->GetController().CanGoForward(); | |
1186 | |
1187 case IDC_RELOAD: { | |
1188 CoreTabHelper* core_tab_helper = | |
1189 CoreTabHelper::FromWebContents(source_web_contents_); | |
1190 if (!core_tab_helper) | |
1191 return false; | |
1192 | |
1193 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate(); | |
1194 return !core_delegate || | |
1195 core_delegate->CanReloadContents(source_web_contents_); | |
1196 } | |
1197 | |
1198 case IDC_VIEW_SOURCE: | |
1199 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE: | |
1200 return source_web_contents_->GetController().CanViewSource(); | |
1201 | |
1202 case IDC_CONTENT_CONTEXT_INSPECTELEMENT: | |
1203 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: | |
1204 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: | |
1205 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: | |
1206 return IsDevCommandEnabled(id); | |
1207 | |
1208 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: | |
1209 if (source_web_contents_->GetController().GetVisibleEntry() == NULL) | |
1210 return false; | |
1211 // Disabled if no browser is associated (e.g. desktop notifications). | |
1212 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL) | |
1213 return false; | |
1214 return true; | |
1215 | |
1216 case IDC_CONTENT_CONTEXT_TRANSLATE: { | |
1217 ChromeTranslateClient* chrome_translate_client = | |
1218 ChromeTranslateClient::FromWebContents(source_web_contents_); | |
1219 if (!chrome_translate_client) | |
1220 return false; | |
1221 std::string original_lang = | |
1222 chrome_translate_client->GetLanguageState().original_language(); | |
1223 std::string target_lang = g_browser_process->GetApplicationLocale(); | |
1224 target_lang = | |
1225 translate::TranslateDownloadManager::GetLanguageCode(target_lang); | |
1226 // Note that we intentionally enable the menu even if the original and | |
1227 // target languages are identical. This is to give a way to user to | |
1228 // translate a page that might contains text fragments in a different | |
1229 // language. | |
1230 return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) && | |
1231 !original_lang.empty() && // Did we receive the page language yet? | |
1232 !chrome_translate_client->GetLanguageState().IsPageTranslated() && | |
1233 !source_web_contents_->GetInterstitialPage() && | |
1234 // There are some application locales which can't be used as a | |
1235 // target language for translation. | |
1236 translate::TranslateDownloadManager::IsSupportedLanguage( | |
1237 target_lang) && | |
1238 // Disable on the Instant Extended NTP. | |
1239 !chrome::IsInstantNTP(source_web_contents_); | |
1240 } | |
1241 | |
1242 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: | |
1243 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW: | |
1244 return params_.link_url.is_valid(); | |
1245 | |
1246 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION: | |
1247 return params_.unfiltered_link_url.is_valid(); | |
1248 | |
1249 case IDC_CONTENT_CONTEXT_SAVELINKAS: { | |
1250 PrefService* local_state = g_browser_process->local_state(); | |
1251 DCHECK(local_state); | |
1252 // Test if file-selection dialogs are forbidden by policy. | |
1253 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs)) | |
1254 return false; | |
1255 | |
1256 return params_.link_url.is_valid() && | |
1257 ProfileIOData::IsHandledProtocol(params_.link_url.scheme()); | |
1258 } | |
1259 | |
1260 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: { | |
1261 PrefService* local_state = g_browser_process->local_state(); | |
1262 DCHECK(local_state); | |
1263 // Test if file-selection dialogs are forbidden by policy. | |
1264 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs)) | |
1265 return false; | |
1266 | |
1267 if (params_.media_type == WebContextMenuData::MediaTypeCanvas) | |
1268 return true; | |
1269 | |
1270 return params_.src_url.is_valid() && | |
1271 ProfileIOData::IsHandledProtocol(params_.src_url.scheme()); | |
1272 } | |
1273 | |
1274 // The images shown in the most visited thumbnails can't be opened or | |
1275 // searched for conventionally. | |
1276 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB: | |
1277 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE: | |
1278 return params_.src_url.is_valid() && | |
1279 (params_.src_url.scheme() != content::kChromeUIScheme); | |
1280 | |
1281 case IDC_CONTENT_CONTEXT_COPYIMAGE: | |
1282 return params_.has_image_contents; | |
1283 | |
1284 // Media control commands should all be disabled if the player is in an | |
1285 // error state. | |
1286 case IDC_CONTENT_CONTEXT_PLAYPAUSE: | |
1287 case IDC_CONTENT_CONTEXT_LOOP: | |
1288 return (params_.media_flags & | |
1289 WebContextMenuData::MediaInError) == 0; | |
1290 | |
1291 // Mute and unmute should also be disabled if the player has no audio. | |
1292 case IDC_CONTENT_CONTEXT_MUTE: | |
1293 return (params_.media_flags & | |
1294 WebContextMenuData::MediaHasAudio) != 0 && | |
1295 (params_.media_flags & | |
1296 WebContextMenuData::MediaInError) == 0; | |
1297 | |
1298 case IDC_CONTENT_CONTEXT_CONTROLS: | |
1299 return (params_.media_flags & | |
1300 WebContextMenuData::MediaCanToggleControls) != 0; | |
1301 | |
1302 case IDC_CONTENT_CONTEXT_ROTATECW: | |
1303 case IDC_CONTENT_CONTEXT_ROTATECCW: | |
1304 return | |
1305 (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0; | |
1306 | |
1307 case IDC_CONTENT_CONTEXT_COPYAVLOCATION: | |
1308 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION: | |
1309 return params_.src_url.is_valid(); | |
1310 | |
1311 case IDC_CONTENT_CONTEXT_SAVEAVAS: { | |
1312 PrefService* local_state = g_browser_process->local_state(); | |
1313 DCHECK(local_state); | |
1314 // Test if file-selection dialogs are forbidden by policy. | |
1315 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs)) | |
1316 return false; | |
1317 | |
1318 const GURL& url = params_.src_url; | |
1319 bool can_save = | |
1320 (params_.media_flags & WebContextMenuData::MediaCanSave) && | |
1321 url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme()); | |
1322 #if defined(ENABLE_FULL_PRINTING) | |
1323 // Do not save the preview PDF on the print preview page. | |
1324 can_save = can_save && | |
1325 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url)); | |
1326 #endif | |
1327 return can_save; | |
1328 } | |
1329 | |
1330 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB: | |
1331 return true; | |
1332 | |
1333 case IDC_SAVE_PAGE: { | |
1334 CoreTabHelper* core_tab_helper = | |
1335 CoreTabHelper::FromWebContents(source_web_contents_); | |
1336 if (!core_tab_helper) | |
1337 return false; | |
1338 | |
1339 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate(); | |
1340 if (core_delegate && | |
1341 !core_delegate->CanSaveContents(source_web_contents_)) | |
1342 return false; | |
1343 | |
1344 PrefService* local_state = g_browser_process->local_state(); | |
1345 DCHECK(local_state); | |
1346 // Test if file-selection dialogs are forbidden by policy. | |
1347 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs)) | |
1348 return false; | |
1349 | |
1350 // We save the last committed entry (which the user is looking at), as | |
1351 // opposed to any pending URL that hasn't committed yet. | |
1352 NavigationEntry* entry = | |
1353 source_web_contents_->GetController().GetLastCommittedEntry(); | |
1354 return content::IsSavableURL(entry ? entry->GetURL() : GURL()); | |
1355 } | |
1356 | |
1357 case IDC_CONTENT_CONTEXT_RELOADFRAME: | |
1358 return params_.frame_url.is_valid(); | |
1359 | |
1360 case IDC_CONTENT_CONTEXT_UNDO: | |
1361 return !!(params_.edit_flags & WebContextMenuData::CanUndo); | |
1362 | |
1363 case IDC_CONTENT_CONTEXT_REDO: | |
1364 return !!(params_.edit_flags & WebContextMenuData::CanRedo); | |
1365 | |
1366 case IDC_CONTENT_CONTEXT_CUT: | |
1367 return !!(params_.edit_flags & WebContextMenuData::CanCut); | |
1368 | |
1369 case IDC_CONTENT_CONTEXT_COPY: | |
1370 return !!(params_.edit_flags & WebContextMenuData::CanCopy); | |
1371 | |
1372 case IDC_CONTENT_CONTEXT_PASTE: | |
1373 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE: | |
1374 return !!(params_.edit_flags & WebContextMenuData::CanPaste); | |
1375 | |
1376 case IDC_CONTENT_CONTEXT_DELETE: | |
1377 return !!(params_.edit_flags & WebContextMenuData::CanDelete); | |
1378 | |
1379 case IDC_CONTENT_CONTEXT_SELECTALL: | |
1380 return !!(params_.edit_flags & WebContextMenuData::CanSelectAll); | |
1381 | |
1382 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD: | |
1383 return !browser_context_->IsOffTheRecord() && | |
1384 params_.link_url.is_valid() && | |
1385 incognito_avail != IncognitoModePrefs::DISABLED; | |
1386 | |
1387 case IDC_PRINT: | |
1388 return prefs->GetBoolean(prefs::kPrintingEnabled) && | |
1389 (params_.media_type == WebContextMenuData::MediaTypeNone || | |
1390 params_.media_flags & WebContextMenuData::MediaCanPrint); | |
1391 | |
1392 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR: | |
1393 case IDC_CONTENT_CONTEXT_GOTOURL: | |
1394 case IDC_SPELLPANEL_TOGGLE: | |
1395 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: | |
1396 return true; | |
1397 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: | |
1398 // Disabled if no browser is associated (e.g. desktop notifications). | |
1399 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL) | |
1400 return false; | |
1401 return true; | |
1402 | |
1403 case IDC_CHECK_SPELLING_WHILE_TYPING: | |
1404 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck); | |
1405 | |
1406 #if !defined(OS_MACOSX) && defined(OS_POSIX) | |
1407 // TODO(suzhe): this should not be enabled for password fields. | |
1408 case IDC_INPUT_METHODS_MENU: | |
1409 return true; | |
1410 #endif | |
1411 | |
1412 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: | |
1413 return !params_.keyword_url.is_empty(); | |
1414 | |
1415 case IDC_SPELLCHECK_MENU: | |
1416 return true; | |
1417 | |
1418 case IDC_CONTENT_CONTEXT_OPENLINKWITH: | |
1419 return true; | |
1420 | |
1421 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: | |
1422 return true; | |
1423 | |
1424 default: | |
1425 NOTREACHED(); | |
1426 return false; | |
1427 } | |
1428 } | 270 } |
1429 | 271 |
1430 bool RenderViewContextMenu::IsCommandIdChecked(int id) const { | 272 bool RenderViewContextMenuBase::IsCommandIdChecked(int id) const { |
1431 // If this command is is added by one of our observers, we dispatch it to the | 273 // If this command is is added by one of our observers, we dispatch it to the |
1432 // observer. | 274 // observer. |
1433 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_); | 275 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_); |
1434 RenderViewContextMenuObserver* observer; | 276 RenderViewContextMenuObserver* observer; |
1435 while ((observer = it.GetNext()) != NULL) { | 277 while ((observer = it.GetNext()) != NULL) { |
1436 if (observer->IsCommandIdSupported(id)) | 278 if (observer->IsCommandIdSupported(id)) |
1437 return observer->IsCommandIdChecked(id); | 279 return observer->IsCommandIdChecked(id); |
1438 } | 280 } |
1439 | 281 |
1440 // See if the video is set to looping. | |
1441 if (id == IDC_CONTENT_CONTEXT_LOOP) { | |
1442 return (params_.media_flags & | |
1443 WebContextMenuData::MediaLoop) != 0; | |
1444 } | |
1445 | |
1446 if (id == IDC_CONTENT_CONTEXT_CONTROLS) { | |
1447 return (params_.media_flags & | |
1448 WebContextMenuData::MediaControls) != 0; | |
1449 } | |
1450 | |
1451 // Custom items. | 282 // Custom items. |
1452 if (IsContentCustomCommandId(id)) | 283 if (IsContentCustomCommandId(id)) |
1453 return IsCustomItemChecked(params_.custom_items, id); | 284 return IsCustomItemChecked(id); |
1454 | |
1455 // Extension items. | |
1456 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) | |
1457 return extension_items_.IsCommandIdChecked(id); | |
1458 | 285 |
1459 return false; | 286 return false; |
1460 } | 287 } |
1461 | 288 |
1462 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) { | 289 void RenderViewContextMenuBase::ExecuteCommand(int id, int event_flags) { |
1463 command_executed_ = true; | 290 command_executed_ = true; |
1464 RecordUsedItem(id); | 291 RecordUsedItem(id); |
1465 | 292 |
1466 // If this command is is added by one of our observers, we dispatch it to the | 293 // If this command is is added by one of our observers, we dispatch |
1467 // observer. | 294 // it to the observer. |
1468 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_); | 295 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_); |
1469 RenderViewContextMenuObserver* observer; | 296 RenderViewContextMenuObserver* observer; |
1470 while ((observer = it.GetNext()) != NULL) { | 297 while ((observer = it.GetNext()) != NULL) { |
1471 if (observer->IsCommandIdSupported(id)) | 298 if (observer->IsCommandIdSupported(id)) |
1472 return observer->ExecuteCommand(id); | 299 return observer->ExecuteCommand(id); |
1473 } | 300 } |
1474 | 301 |
1475 RenderFrameHost* render_frame_host = | |
1476 RenderFrameHost::FromID(render_process_id_, render_frame_id_); | |
1477 | |
1478 // Process custom actions range. | 302 // Process custom actions range. |
1479 if (IsContentCustomCommandId(id)) { | 303 if (IsContentCustomCommandId(id)) { |
1480 unsigned action = id - content_context_custom_first; | 304 unsigned action = id - content_context_custom_first; |
1481 const content::CustomContextMenuContext& context = params_.custom_context; | 305 const content::CustomContextMenuContext& context = params_.custom_context; |
1482 #if defined(ENABLE_PLUGINS) | 306 #if defined(ENABLE_PLUGINS) |
1483 if (context.request_id && !context.is_pepper_menu) { | 307 if (context.request_id && !context.is_pepper_menu) |
1484 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( | 308 HandleAuthorizeAllPlugins(); |
1485 source_web_contents_, false, std::string()); | |
1486 } | |
1487 #endif | 309 #endif |
1488 source_web_contents_->ExecuteCustomContextMenuCommand(action, context); | 310 source_web_contents_->ExecuteCustomContextMenuCommand(action, context); |
1489 return; | 311 return; |
1490 } | 312 } |
1491 | 313 command_executed_ = false; |
1492 // Process extension menu items. | |
1493 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) { | |
1494 extension_items_.ExecuteCommand(id, source_web_contents_, params_); | |
1495 return; | |
1496 } | |
1497 | |
1498 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST && | |
1499 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) { | |
1500 ProtocolHandlerRegistry::ProtocolHandlerList handlers = | |
1501 GetHandlersForLinkUrl(); | |
1502 if (handlers.empty()) { | |
1503 return; | |
1504 } | |
1505 content::RecordAction( | |
1506 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open")); | |
1507 int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST; | |
1508 WindowOpenDisposition disposition = | |
1509 ForceNewTabDispositionFromEventFlags(event_flags); | |
1510 OpenURL( | |
1511 handlers[handlerIndex].TranslateUrl(params_.link_url), | |
1512 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url, | |
1513 disposition, content::PAGE_TRANSITION_LINK); | |
1514 return; | |
1515 } | |
1516 | |
1517 switch (id) { | |
1518 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: { | |
1519 Browser* browser = | |
1520 chrome::FindBrowserWithWebContents(source_web_contents_); | |
1521 OpenURL( | |
1522 params_.link_url, | |
1523 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url, | |
1524 !browser || browser->is_app() ? | |
1525 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB, | |
1526 content::PAGE_TRANSITION_LINK); | |
1527 break; | |
1528 } | |
1529 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW: | |
1530 OpenURL( | |
1531 params_.link_url, | |
1532 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url, | |
1533 NEW_WINDOW, content::PAGE_TRANSITION_LINK); | |
1534 break; | |
1535 | |
1536 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD: | |
1537 OpenURL(params_.link_url, GURL(), OFF_THE_RECORD, | |
1538 content::PAGE_TRANSITION_LINK); | |
1539 break; | |
1540 | |
1541 case IDC_CONTENT_CONTEXT_SAVELINKAS: { | |
1542 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU); | |
1543 const GURL& referrer = | |
1544 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url; | |
1545 const GURL& url = params_.link_url; | |
1546 DownloadManager* dlm = | |
1547 BrowserContext::GetDownloadManager(browser_context_); | |
1548 scoped_ptr<DownloadUrlParameters> dl_params( | |
1549 DownloadUrlParameters::FromWebContents(source_web_contents_, url)); | |
1550 dl_params->set_referrer( | |
1551 content::Referrer(referrer, params_.referrer_policy)); | |
1552 dl_params->set_referrer_encoding(params_.frame_charset); | |
1553 dl_params->set_suggested_name(params_.suggested_filename); | |
1554 dl_params->set_prompt(true); | |
1555 dlm->DownloadUrl(dl_params.Pass()); | |
1556 break; | |
1557 } | |
1558 | |
1559 case IDC_CONTENT_CONTEXT_SAVEAVAS: | |
1560 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: { | |
1561 if (params_.media_type == WebContextMenuData::MediaTypeCanvas) { | |
1562 source_web_contents_->GetRenderViewHost()->SaveImageAt( | |
1563 params_.x, params_.y); | |
1564 } else { | |
1565 // TODO(zino): We can use SaveImageAt() like a case of canvas. | |
1566 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU); | |
1567 const GURL& referrer = | |
1568 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url; | |
1569 const GURL& url = params_.src_url; | |
1570 source_web_contents_->SaveFrame(url, content::Referrer( | |
1571 referrer, params_.referrer_policy)); | |
1572 } | |
1573 break; | |
1574 } | |
1575 | |
1576 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION: | |
1577 WriteURLToClipboard(params_.unfiltered_link_url); | |
1578 break; | |
1579 | |
1580 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION: | |
1581 case IDC_CONTENT_CONTEXT_COPYAVLOCATION: | |
1582 WriteURLToClipboard(params_.src_url); | |
1583 break; | |
1584 | |
1585 case IDC_CONTENT_CONTEXT_COPYIMAGE: | |
1586 CopyImageAt(params_.x, params_.y); | |
1587 break; | |
1588 | |
1589 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE: | |
1590 GetImageThumbnailForSearch(); | |
1591 break; | |
1592 | |
1593 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB: | |
1594 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB: | |
1595 OpenURL( | |
1596 params_.src_url, | |
1597 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url, | |
1598 NEW_BACKGROUND_TAB, content::PAGE_TRANSITION_LINK); | |
1599 break; | |
1600 | |
1601 case IDC_CONTENT_CONTEXT_PLAYPAUSE: { | |
1602 bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused); | |
1603 if (play) { | |
1604 content::RecordAction(UserMetricsAction("MediaContextMenu_Play")); | |
1605 } else { | |
1606 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause")); | |
1607 } | |
1608 MediaPlayerActionAt(gfx::Point(params_.x, params_.y), | |
1609 WebMediaPlayerAction( | |
1610 WebMediaPlayerAction::Play, play)); | |
1611 break; | |
1612 } | |
1613 | |
1614 case IDC_CONTENT_CONTEXT_MUTE: { | |
1615 bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted); | |
1616 if (mute) { | |
1617 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute")); | |
1618 } else { | |
1619 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute")); | |
1620 } | |
1621 MediaPlayerActionAt(gfx::Point(params_.x, params_.y), | |
1622 WebMediaPlayerAction( | |
1623 WebMediaPlayerAction::Mute, mute)); | |
1624 break; | |
1625 } | |
1626 | |
1627 case IDC_CONTENT_CONTEXT_LOOP: | |
1628 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop")); | |
1629 MediaPlayerActionAt(gfx::Point(params_.x, params_.y), | |
1630 WebMediaPlayerAction( | |
1631 WebMediaPlayerAction::Loop, | |
1632 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP))); | |
1633 break; | |
1634 | |
1635 case IDC_CONTENT_CONTEXT_CONTROLS: | |
1636 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls")); | |
1637 MediaPlayerActionAt( | |
1638 gfx::Point(params_.x, params_.y), | |
1639 WebMediaPlayerAction( | |
1640 WebMediaPlayerAction::Controls, | |
1641 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS))); | |
1642 break; | |
1643 | |
1644 case IDC_CONTENT_CONTEXT_ROTATECW: | |
1645 content::RecordAction( | |
1646 UserMetricsAction("PluginContextMenu_RotateClockwise")); | |
1647 PluginActionAt( | |
1648 gfx::Point(params_.x, params_.y), | |
1649 WebPluginAction( | |
1650 WebPluginAction::Rotate90Clockwise, | |
1651 true)); | |
1652 break; | |
1653 | |
1654 case IDC_CONTENT_CONTEXT_ROTATECCW: | |
1655 content::RecordAction( | |
1656 UserMetricsAction("PluginContextMenu_RotateCounterclockwise")); | |
1657 PluginActionAt( | |
1658 gfx::Point(params_.x, params_.y), | |
1659 WebPluginAction( | |
1660 WebPluginAction::Rotate90Counterclockwise, | |
1661 true)); | |
1662 break; | |
1663 | |
1664 case IDC_BACK: | |
1665 source_web_contents_->GetController().GoBack(); | |
1666 break; | |
1667 | |
1668 case IDC_FORWARD: | |
1669 source_web_contents_->GetController().GoForward(); | |
1670 break; | |
1671 | |
1672 case IDC_SAVE_PAGE: | |
1673 source_web_contents_->OnSavePage(); | |
1674 break; | |
1675 | |
1676 case IDC_RELOAD: | |
1677 source_web_contents_->GetController().Reload(true); | |
1678 break; | |
1679 | |
1680 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: { | |
1681 const Extension* platform_app = GetExtension(); | |
1682 DCHECK(platform_app); | |
1683 DCHECK(platform_app->is_platform_app()); | |
1684 | |
1685 extensions::ExtensionSystem::Get(browser_context_) | |
1686 ->extension_service() | |
1687 ->ReloadExtension(platform_app->id()); | |
1688 break; | |
1689 } | |
1690 | |
1691 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: { | |
1692 const Extension* platform_app = GetExtension(); | |
1693 DCHECK(platform_app); | |
1694 DCHECK(platform_app->is_platform_app()); | |
1695 | |
1696 apps::AppLoadService::Get(GetProfile()) | |
1697 ->RestartApplication(platform_app->id()); | |
1698 break; | |
1699 } | |
1700 | |
1701 case IDC_PRINT: | |
1702 #if defined(ENABLE_PRINTING) | |
1703 if (params_.media_type == WebContextMenuData::MediaTypeNone) { | |
1704 #if defined(ENABLE_FULL_PRINTING) | |
1705 printing::PrintViewManager* print_view_manager = | |
1706 printing::PrintViewManager::FromWebContents(source_web_contents_); | |
1707 | |
1708 if (!print_view_manager) | |
1709 break; | |
1710 if (GetPrefs(browser_context_) | |
1711 ->GetBoolean(prefs::kPrintPreviewDisabled)) { | |
1712 print_view_manager->PrintNow(); | |
1713 } else { | |
1714 print_view_manager->PrintPreviewNow(!params_.selection_text.empty()); | |
1715 } | |
1716 #else | |
1717 printing::PrintViewManagerBasic* print_view_manager = | |
1718 printing::PrintViewManagerBasic::FromWebContents( | |
1719 source_web_contents_); | |
1720 if (!print_view_manager) | |
1721 break; | |
1722 print_view_manager->PrintNow(); | |
1723 #endif // defined(ENABLE_FULL_PRINTING) | |
1724 } else { | |
1725 if (render_frame_host) { | |
1726 render_frame_host->Send(new PrintMsg_PrintNodeUnderContextMenu( | |
1727 render_frame_host->GetRoutingID())); | |
1728 } | |
1729 } | |
1730 #endif // defined(ENABLE_PRINTING) | |
1731 break; | |
1732 | |
1733 case IDC_VIEW_SOURCE: | |
1734 source_web_contents_->ViewSource(); | |
1735 break; | |
1736 | |
1737 case IDC_CONTENT_CONTEXT_INSPECTELEMENT: | |
1738 Inspect(params_.x, params_.y); | |
1739 break; | |
1740 | |
1741 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: { | |
1742 const Extension* platform_app = GetExtension(); | |
1743 DCHECK(platform_app); | |
1744 DCHECK(platform_app->is_platform_app()); | |
1745 | |
1746 extensions::devtools_util::InspectBackgroundPage(platform_app, | |
1747 GetProfile()); | |
1748 break; | |
1749 } | |
1750 | |
1751 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: { | |
1752 NavigationController* controller = &source_web_contents_->GetController(); | |
1753 // Important to use GetVisibleEntry to match what's showing in the | |
1754 // omnibox. This may return null. | |
1755 NavigationEntry* nav_entry = controller->GetVisibleEntry(); | |
1756 if (!nav_entry) | |
1757 return; | |
1758 Browser* browser = | |
1759 chrome::FindBrowserWithWebContents(source_web_contents_); | |
1760 chrome::ShowWebsiteSettings(browser, source_web_contents_, | |
1761 nav_entry->GetURL(), nav_entry->GetSSL()); | |
1762 break; | |
1763 } | |
1764 | |
1765 case IDC_CONTENT_CONTEXT_TRANSLATE: { | |
1766 // A translation might have been triggered by the time the menu got | |
1767 // selected, do nothing in that case. | |
1768 ChromeTranslateClient* chrome_translate_client = | |
1769 ChromeTranslateClient::FromWebContents(source_web_contents_); | |
1770 if (!chrome_translate_client || | |
1771 chrome_translate_client->GetLanguageState().IsPageTranslated() || | |
1772 chrome_translate_client->GetLanguageState().translation_pending()) { | |
1773 return; | |
1774 } | |
1775 std::string original_lang = | |
1776 chrome_translate_client->GetLanguageState().original_language(); | |
1777 std::string target_lang = g_browser_process->GetApplicationLocale(); | |
1778 target_lang = | |
1779 translate::TranslateDownloadManager::GetLanguageCode(target_lang); | |
1780 // Since the user decided to translate for that language and site, clears | |
1781 // any preferences for not translating them. | |
1782 scoped_ptr<translate::TranslatePrefs> prefs( | |
1783 ChromeTranslateClient::CreateTranslatePrefs( | |
1784 GetPrefs(browser_context_))); | |
1785 prefs->UnblockLanguage(original_lang); | |
1786 prefs->RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets()); | |
1787 translate::TranslateManager* manager = | |
1788 chrome_translate_client->GetTranslateManager(); | |
1789 DCHECK(manager); | |
1790 manager->TranslatePage(original_lang, target_lang, true); | |
1791 break; | |
1792 } | |
1793 | |
1794 case IDC_CONTENT_CONTEXT_RELOADFRAME: | |
1795 // We always obey the cache here. | |
1796 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do | |
1797 // a cache-ignoring reload of the frame. | |
1798 source_web_contents_->ReloadFocusedFrame(false); | |
1799 break; | |
1800 | |
1801 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE: | |
1802 source_web_contents_->ViewFrameSource(params_.frame_url, | |
1803 params_.frame_page_state); | |
1804 break; | |
1805 | |
1806 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: { | |
1807 Browser* browser = chrome::FindBrowserWithWebContents( | |
1808 source_web_contents_); | |
1809 chrome::ShowWebsiteSettings(browser, source_web_contents_, | |
1810 params_.frame_url, params_.security_info); | |
1811 break; | |
1812 } | |
1813 | |
1814 case IDC_CONTENT_CONTEXT_UNDO: | |
1815 source_web_contents_->Undo(); | |
1816 break; | |
1817 | |
1818 case IDC_CONTENT_CONTEXT_REDO: | |
1819 source_web_contents_->Redo(); | |
1820 break; | |
1821 | |
1822 case IDC_CONTENT_CONTEXT_CUT: | |
1823 source_web_contents_->Cut(); | |
1824 break; | |
1825 | |
1826 case IDC_CONTENT_CONTEXT_COPY: | |
1827 source_web_contents_->Copy(); | |
1828 break; | |
1829 | |
1830 case IDC_CONTENT_CONTEXT_PASTE: | |
1831 source_web_contents_->Paste(); | |
1832 break; | |
1833 | |
1834 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE: | |
1835 source_web_contents_->PasteAndMatchStyle(); | |
1836 break; | |
1837 | |
1838 case IDC_CONTENT_CONTEXT_DELETE: | |
1839 source_web_contents_->Delete(); | |
1840 break; | |
1841 | |
1842 case IDC_CONTENT_CONTEXT_SELECTALL: | |
1843 source_web_contents_->SelectAll(); | |
1844 break; | |
1845 | |
1846 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR: | |
1847 case IDC_CONTENT_CONTEXT_GOTOURL: { | |
1848 WindowOpenDisposition disposition = | |
1849 ForceNewTabDispositionFromEventFlags(event_flags); | |
1850 OpenURL(selection_navigation_url_, GURL(), disposition, | |
1851 content::PAGE_TRANSITION_LINK); | |
1852 break; | |
1853 } | |
1854 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: { | |
1855 WindowOpenDisposition disposition = | |
1856 ForceNewTabDispositionFromEventFlags(event_flags); | |
1857 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage); | |
1858 OpenURL(url, GURL(), disposition, content::PAGE_TRANSITION_LINK); | |
1859 break; | |
1860 } | |
1861 | |
1862 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: { | |
1863 content::RecordAction( | |
1864 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings")); | |
1865 WindowOpenDisposition disposition = | |
1866 ForceNewTabDispositionFromEventFlags(event_flags); | |
1867 GURL url = chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage); | |
1868 OpenURL(url, GURL(), disposition, content::PAGE_TRANSITION_LINK); | |
1869 break; | |
1870 } | |
1871 | |
1872 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: { | |
1873 // Make sure the model is loaded. | |
1874 TemplateURLService* model = | |
1875 TemplateURLServiceFactory::GetForProfile(GetProfile()); | |
1876 if (!model) | |
1877 return; | |
1878 model->Load(); | |
1879 | |
1880 SearchEngineTabHelper* search_engine_tab_helper = | |
1881 SearchEngineTabHelper::FromWebContents(source_web_contents_); | |
1882 if (search_engine_tab_helper && | |
1883 search_engine_tab_helper->delegate()) { | |
1884 base::string16 keyword(TemplateURL::GenerateKeyword(params_.page_url)); | |
1885 TemplateURLData data; | |
1886 data.short_name = keyword; | |
1887 data.SetKeyword(keyword); | |
1888 data.SetURL(params_.keyword_url.spec()); | |
1889 data.favicon_url = | |
1890 TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin()); | |
1891 // Takes ownership of the TemplateURL. | |
1892 search_engine_tab_helper->delegate()->ConfirmAddSearchProvider( | |
1893 new TemplateURL(data), GetProfile()); | |
1894 } | |
1895 break; | |
1896 } | |
1897 | |
1898 default: | |
1899 NOTREACHED(); | |
1900 break; | |
1901 } | |
1902 } | 314 } |
1903 | 315 |
1904 ProtocolHandlerRegistry::ProtocolHandlerList | 316 void RenderViewContextMenuBase::MenuWillShow(ui::SimpleMenuModel* source) { |
1905 RenderViewContextMenu::GetHandlersForLinkUrl() { | |
1906 ProtocolHandlerRegistry::ProtocolHandlerList handlers = | |
1907 protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme()); | |
1908 std::sort(handlers.begin(), handlers.end()); | |
1909 return handlers; | |
1910 } | |
1911 | |
1912 void RenderViewContextMenu::MenuWillShow(ui::SimpleMenuModel* source) { | |
1913 for (int i = 0; i < source->GetItemCount(); ++i) { | 317 for (int i = 0; i < source->GetItemCount(); ++i) { |
1914 if (source->IsVisibleAt(i) && | 318 if (source->IsVisibleAt(i) && |
1915 source->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR) { | 319 source->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR) { |
1916 RecordShownItem(source->GetCommandIdAt(i)); | 320 RecordShownItem(source->GetCommandIdAt(i)); |
1917 } | 321 } |
1918 } | 322 } |
1919 | 323 |
1920 // Ignore notifications from submenus. | 324 // Ignore notifications from submenus. |
1921 if (source != &menu_model_) | 325 if (source != &menu_model_) |
1922 return; | 326 return; |
1923 | 327 |
1924 content::RenderWidgetHostView* view = | 328 content::RenderWidgetHostView* view = |
1925 source_web_contents_->GetRenderWidgetHostView(); | 329 source_web_contents_->GetRenderWidgetHostView(); |
1926 if (view) | 330 if (view) |
1927 view->SetShowingContextMenu(true); | 331 view->SetShowingContextMenu(true); |
1928 | 332 |
1929 content::NotificationService::current()->Notify( | 333 NotifyMenuShown(); |
1930 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN, | |
1931 content::Source<RenderViewContextMenu>(this), | |
1932 content::NotificationService::NoDetails()); | |
1933 } | 334 } |
1934 | 335 |
1935 void RenderViewContextMenu::MenuClosed(ui::SimpleMenuModel* source) { | 336 void RenderViewContextMenuBase::MenuClosed(ui::SimpleMenuModel* source) { |
1936 // Ignore notifications from submenus. | 337 // Ignore notifications from submenus. |
1937 if (source != &menu_model_) | 338 if (source != &menu_model_) |
1938 return; | 339 return; |
1939 | 340 |
1940 content::RenderWidgetHostView* view = | 341 content::RenderWidgetHostView* view = |
1941 source_web_contents_->GetRenderWidgetHostView(); | 342 source_web_contents_->GetRenderWidgetHostView(); |
1942 if (view) | 343 if (view) |
1943 view->SetShowingContextMenu(false); | 344 view->SetShowingContextMenu(false); |
1944 source_web_contents_->NotifyContextMenuClosed(params_.custom_context); | 345 source_web_contents_->NotifyContextMenuClosed(params_.custom_context); |
1945 | 346 |
1946 if (!command_executed_) { | 347 if (!command_executed_) { |
1947 FOR_EACH_OBSERVER(RenderViewContextMenuObserver, | 348 FOR_EACH_OBSERVER(RenderViewContextMenuObserver, |
1948 observers_, | 349 observers_, |
1949 OnMenuCancel()); | 350 OnMenuCancel()); |
1950 } | 351 } |
1951 } | 352 } |
1952 | 353 |
1953 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const { | 354 RenderFrameHost* RenderViewContextMenuBase::GetRenderFrameHost() { |
1954 if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT || | 355 return RenderFrameHost::FromID(render_process_id_, render_frame_id_); |
1955 id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) { | |
1956 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
1957 if (!GetPrefs(browser_context_) | |
1958 ->GetBoolean(prefs::kWebKitJavascriptEnabled) || | |
1959 command_line->HasSwitch(switches::kDisableJavaScript)) | |
1960 return false; | |
1961 | |
1962 // Don't enable the web inspector if the developer tools are disabled via | |
1963 // the preference dev-tools-disabled. | |
1964 if (GetPrefs(browser_context_)->GetBoolean(prefs::kDevToolsDisabled)) | |
1965 return false; | |
1966 } | |
1967 | |
1968 return true; | |
1969 } | |
1970 | |
1971 base::string16 RenderViewContextMenu::PrintableSelectionText() { | |
1972 return gfx::TruncateString(params_.selection_text, | |
1973 kMaxSelectionTextLength, | |
1974 gfx::WORD_BREAK); | |
1975 } | 356 } |
1976 | 357 |
1977 // Controller functions -------------------------------------------------------- | 358 // Controller functions -------------------------------------------------------- |
1978 | 359 |
1979 void RenderViewContextMenu::OpenURL( | 360 void RenderViewContextMenuBase::OpenURL( |
1980 const GURL& url, const GURL& referring_url, | 361 const GURL& url, const GURL& referring_url, |
1981 WindowOpenDisposition disposition, | 362 WindowOpenDisposition disposition, |
1982 content::PageTransition transition) { | 363 content::PageTransition transition) { |
1983 content::Referrer referrer(referring_url.GetAsReferrer(), | 364 content::Referrer referrer(referring_url.GetAsReferrer(), |
1984 params_.referrer_policy); | 365 params_.referrer_policy); |
1985 | 366 |
1986 if (params_.link_url == url && disposition != OFF_THE_RECORD) | 367 if (params_.link_url == url && disposition != OFF_THE_RECORD) |
1987 params_.custom_context.link_followed = url; | 368 params_.custom_context.link_followed = url; |
1988 | 369 |
1989 WebContents* new_contents = source_web_contents_->OpenURL(OpenURLParams( | 370 WebContents* new_contents = source_web_contents_->OpenURL(OpenURLParams( |
1990 url, referrer, disposition, transition, false)); | 371 url, referrer, disposition, transition, false)); |
1991 if (!new_contents) | 372 if (!new_contents) |
1992 return; | 373 return; |
1993 | 374 |
1994 RetargetingDetails details; | 375 NotifyURLOpened(url, new_contents); |
1995 details.source_web_contents = source_web_contents_; | |
1996 details.source_render_frame_id = render_frame_id_; | |
1997 details.target_url = url; | |
1998 details.target_web_contents = new_contents; | |
1999 details.not_yet_in_tabstrip = false; | |
2000 content::NotificationService::current()->Notify( | |
2001 chrome::NOTIFICATION_RETARGETING, | |
2002 content::Source<Profile>(GetProfile()), | |
2003 content::Details<RetargetingDetails>(&details)); | |
2004 } | 376 } |
2005 | 377 |
2006 void RenderViewContextMenu::CopyImageAt(int x, int y) { | 378 bool RenderViewContextMenuBase::IsCustomItemChecked(int id) const { |
2007 source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y); | 379 return IsCustomItemCheckedInternal(params_.custom_items, id); |
2008 } | 380 } |
2009 | 381 |
2010 void RenderViewContextMenu::GetImageThumbnailForSearch() { | 382 bool RenderViewContextMenuBase::IsCustomItemEnabled(int id) const { |
2011 RenderFrameHost* render_frame_host = | 383 return IsCustomItemEnabledInternal(params_.custom_items, id); |
2012 RenderFrameHost::FromID(render_process_id_, render_frame_id_); | |
2013 if (!render_frame_host) | |
2014 return; | |
2015 render_frame_host->Send(new ChromeViewMsg_RequestThumbnailForContextNode( | |
2016 render_frame_host->GetRoutingID(), | |
2017 kImageSearchThumbnailMinSize, | |
2018 gfx::Size(kImageSearchThumbnailMaxWidth, | |
2019 kImageSearchThumbnailMaxHeight))); | |
2020 } | 384 } |
2021 | 385 |
2022 void RenderViewContextMenu::Inspect(int x, int y) { | |
2023 content::RecordAction(UserMetricsAction("DevTools_InspectElement")); | |
2024 RenderFrameHost* render_frame_host = | |
2025 RenderFrameHost::FromID(render_process_id_, render_frame_id_); | |
2026 if (!render_frame_host) | |
2027 return; | |
2028 DevToolsWindow::InspectElement(render_frame_host->GetRenderViewHost(), x, y); | |
2029 } | |
2030 | |
2031 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) { | |
2032 chrome_common_net::WriteURLToClipboard( | |
2033 url, | |
2034 GetPrefs(browser_context_)->GetString(prefs::kAcceptLanguages), | |
2035 ui::Clipboard::GetForCurrentThread()); | |
2036 } | |
2037 | |
2038 void RenderViewContextMenu::MediaPlayerActionAt( | |
2039 const gfx::Point& location, | |
2040 const WebMediaPlayerAction& action) { | |
2041 source_web_contents_->GetRenderViewHost()-> | |
2042 ExecuteMediaPlayerActionAtLocation(location, action); | |
2043 } | |
2044 | |
2045 void RenderViewContextMenu::PluginActionAt( | |
2046 const gfx::Point& location, | |
2047 const WebPluginAction& action) { | |
2048 source_web_contents_->GetRenderViewHost()-> | |
2049 ExecutePluginActionAtLocation(location, action); | |
2050 } | |
OLD | NEW |