Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: components/renderer_context_menu/render_view_context_menu_base.cc

Issue 432003007: Separate chrome independent part from RVContextMenu (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 &params_.selection_text);
1008 if (params_.selection_text.empty())
1009 return;
1010
1011 base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
1012 base::ASCIIToUTF16(" "), &params_.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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698