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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 #include <memory>
11 #include <set>
12 #include <utility>
13 
14 #include "base/bind.h"
15 #include "base/command_line.h"
16 #include "base/feature_list.h"
17 #include "base/logging.h"
18 #include "base/metrics/field_trial.h"
19 #include "base/metrics/histogram_macros.h"
20 #include "base/metrics/user_metrics.h"
21 #include "base/no_destructor.h"
22 #include "base/stl_util.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "build/branding_buildflags.h"
27 #include "build/build_config.h"
28 #include "chrome/app/chrome_command_ids.h"
29 #include "chrome/app/vector_icons/vector_icons.h"
30 #include "chrome/browser/app_mode/app_mode_utils.h"
31 #include "chrome/browser/apps/app_service/app_launch_params.h"
32 #include "chrome/browser/apps/app_service/app_service_proxy.h"
33 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
34 #include "chrome/browser/apps/app_service/browser_app_launcher.h"
35 #include "chrome/browser/apps/platform_apps/app_load_service.h"
36 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
37 #include "chrome/browser/browser_features.h"
38 #include "chrome/browser/browser_process.h"
39 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
40 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
41 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
42 #include "chrome/browser/devtools/devtools_window.h"
43 #include "chrome/browser/download/download_stats.h"
44 #include "chrome/browser/language/language_model_manager_factory.h"
45 #include "chrome/browser/media/router/media_router_feature.h"
46 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
47 #include "chrome/browser/platform_util.h"
48 #include "chrome/browser/prefs/incognito_mode_prefs.h"
49 #include "chrome/browser/profiles/profile.h"
50 #include "chrome/browser/profiles/profile_attributes_entry.h"
51 #include "chrome/browser/profiles/profile_attributes_storage.h"
52 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
53 #include "chrome/browser/profiles/profile_io_data.h"
54 #include "chrome/browser/profiles/profile_manager.h"
55 #include "chrome/browser/profiles/profile_window.h"
56 #include "chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.h"
57 #include "chrome/browser/renderer_context_menu/context_menu_content_type_factory.h"
58 #include "chrome/browser/renderer_context_menu/copy_link_to_text_menu_observer.h"
59 #include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
60 #include "chrome/browser/search/search.h"
61 #include "chrome/browser/search_engines/template_url_service_factory.h"
62 #include "chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h"
63 #include "chrome/browser/send_tab_to_self/send_tab_to_self_util.h"
64 #include "chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h"
65 #include "chrome/browser/sharing/click_to_call/click_to_call_metrics.h"
66 #include "chrome/browser/sharing/click_to_call/click_to_call_utils.h"
67 #include "chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.h"
68 #include "chrome/browser/sharing/shared_clipboard/shared_clipboard_utils.h"
69 #include "chrome/browser/spellchecker/spellcheck_service.h"
70 #include "chrome/browser/translate/chrome_translate_client.h"
71 #include "chrome/browser/translate/translate_service.h"
72 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
73 #include "chrome/browser/ui/browser.h"
74 #include "chrome/browser/ui/browser_commands.h"
75 #include "chrome/browser/ui/browser_finder.h"
76 #include "chrome/browser/ui/browser_navigator_params.h"
77 #include "chrome/browser/ui/chrome_pages.h"
78 #include "chrome/browser/ui/exclusive_access/keyboard_lock_controller.h"
79 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
80 #include "chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.h"
81 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
82 #include "chrome/browser/ui/tabs/tab_strip_model.h"
83 #include "chrome/browser/ui/webui/history/foreign_session_handler.h"
84 #include "chrome/browser/web_applications/components/app_icon_manager.h"
85 #include "chrome/browser/web_applications/components/app_registrar.h"
86 #include "chrome/browser/web_applications/components/web_app_helpers.h"
87 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
88 #include "chrome/common/chrome_constants.h"
89 #include "chrome/common/chrome_features.h"
90 #include "chrome/common/chrome_render_frame.mojom.h"
91 #include "chrome/common/chrome_switches.h"
92 #include "chrome/common/content_restriction.h"
93 #include "chrome/common/pref_names.h"
94 #include "chrome/common/url_constants.h"
95 #include "chrome/common/webui_url_constants.h"
96 #include "chrome/grit/chromium_strings.h"
97 #include "chrome/grit/generated_resources.h"
98 #include "components/arc/arc_features.h"
99 #include "components/autofill/core/browser/ui/popup_item_ids.h"
100 #include "components/autofill/core/common/password_generation_util.h"
101 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
102 #include "components/download/public/common/download_url_parameters.h"
103 #include "components/google/core/common/google_util.h"
104 #include "components/guest_view/browser/guest_view_base.h"
105 #include "components/language/core/browser/language_model_manager.h"
106 #include "components/media_router/browser/media_router_dialog_controller.h"
107 #include "components/media_router/browser/media_router_metrics.h"
108 #include "components/omnibox/browser/autocomplete_classifier.h"
109 #include "components/omnibox/browser/autocomplete_match.h"
110 #include "components/password_manager/content/browser/content_password_manager_driver.h"
111 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
112 #include "components/password_manager/core/browser/password_manager_util.h"
113 #include "components/policy/content/policy_blocklist_service.h"
114 #include "components/prefs/pref_member.h"
115 #include "components/prefs/pref_service.h"
116 #include "components/search_engines/search_engines_pref_names.h"
117 #include "components/search_engines/template_url.h"
118 #include "components/search_engines/template_url_service.h"
119 #include "components/spellcheck/browser/pref_names.h"
120 #include "components/spellcheck/browser/spellcheck_host_metrics.h"
121 #include "components/spellcheck/common/spellcheck_common.h"
122 #include "components/spellcheck/spellcheck_buildflags.h"
123 #include "components/strings/grit/components_strings.h"
124 #include "components/translate/core/browser/translate_download_manager.h"
125 #include "components/translate/core/browser/translate_manager.h"
126 #include "components/translate/core/browser/translate_prefs.h"
127 #include "components/url_formatter/url_formatter.h"
128 #include "components/user_prefs/user_prefs.h"
129 #include "components/web_modal/web_contents_modal_dialog_manager.h"
130 #include "content/public/browser/child_process_security_policy.h"
131 #include "content/public/browser/download_manager.h"
132 #include "content/public/browser/navigation_details.h"
133 #include "content/public/browser/navigation_entry.h"
134 #include "content/public/browser/picture_in_picture_window_controller.h"
135 #include "content/public/browser/render_frame_host.h"
136 #include "content/public/browser/render_process_host.h"
137 #include "content/public/browser/render_view_host.h"
138 #include "content/public/browser/render_widget_host_view.h"
139 #include "content/public/browser/ssl_status.h"
140 #include "content/public/browser/web_contents.h"
141 #include "content/public/common/menu_item.h"
142 #include "content/public/common/url_utils.h"
143 #include "extensions/buildflags/buildflags.h"
144 #include "media/base/media_switches.h"
145 #include "mojo/public/cpp/bindings/associated_remote.h"
146 #include "net/base/escape.h"
147 #include "net/traffic_annotation/network_traffic_annotation.h"
148 #include "ppapi/buildflags/buildflags.h"
149 #include "printing/buildflags/buildflags.h"
150 #include "services/service_manager/public/cpp/interface_provider.h"
151 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
152 #include "third_party/blink/public/common/context_menu_data/edit_flags.h"
153 #include "third_party/blink/public/common/context_menu_data/input_field_type.h"
154 #include "third_party/blink/public/common/context_menu_data/media_type.h"
155 #include "third_party/blink/public/mojom/frame/media_player_action.mojom.h"
156 #include "third_party/blink/public/public_buildflags.h"
157 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
158 #include "ui/base/clipboard/clipboard.h"
159 #include "ui/base/clipboard/scoped_clipboard_writer.h"
160 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
161 #include "ui/base/emoji/emoji_panel_helper.h"
162 #include "ui/base/l10n/l10n_util.h"
163 #include "ui/base/models/image_model.h"
164 #include "ui/gfx/favicon_size.h"
165 #include "ui/gfx/geometry/point.h"
166 #include "ui/gfx/image/image.h"
167 #include "ui/gfx/text_elider.h"
168 #include "ui/strings/grit/ui_strings.h"
169 
170 #if BUILDFLAG(USE_RENDERER_SPELLCHECKER)
171 #include "chrome/browser/renderer_context_menu/spelling_options_submenu_observer.h"
172 #endif
173 
174 #if BUILDFLAG(ENABLE_EXTENSIONS)
175 #include "chrome/browser/apps/app_service/app_launch_params.h"
176 #include "chrome/browser/extensions/devtools_util.h"
177 #include "chrome/browser/extensions/extension_service.h"
178 #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
179 #include "extensions/browser/extension_host.h"
180 #include "extensions/browser/extension_registry.h"
181 #include "extensions/browser/extension_system.h"
182 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
183 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
184 #include "extensions/browser/view_type_utils.h"
185 #include "extensions/common/extension.h"
186 #endif
187 
188 #if BUILDFLAG(ENABLE_PLUGINS)
189 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
190 #endif
191 
192 #if BUILDFLAG(ENABLE_PRINTING)
193 #include "chrome/browser/printing/print_view_manager_common.h"
194 #include "components/printing/common/print.mojom.h"
195 
196 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
197 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
198 #include "chrome/browser/printing/print_preview_dialog_controller.h"
199 #endif  // BUILDFLAG(ENABLE_PRINT_PREVIEW)
200 #endif  // BUILDFLAG(ENABLE_PRINTING)
201 
202 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
203 #include "chrome/browser/supervised_user/supervised_user_service.h"
204 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
205 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
206 #endif
207 
208 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
209 #include "chrome/grit/theme_resources.h"
210 #include "ui/base/resource/resource_bundle.h"
211 #endif
212 
213 #if defined(OS_CHROMEOS)
214 #include "ash/public/cpp/clipboard_history_controller.h"
215 #include "chrome/browser/chromeos/arc/arc_util.h"
216 #include "chrome/browser/chromeos/arc/intent_helper/open_with_menu.h"
217 #include "chrome/browser/chromeos/arc/intent_helper/start_smart_selection_action_menu.h"
218 #include "chrome/browser/renderer_context_menu/quick_answers_menu_observer.h"
219 #include "chromeos/constants/chromeos_features.h"
220 #include "ui/views/controls/menu/menu_types.h"
221 #endif
222 
223 using base::UserMetricsAction;
224 using blink::ContextMenuDataEditFlags;
225 using blink::ContextMenuDataMediaType;
226 using blink::WebContextMenuData;
227 using blink::WebString;
228 using blink::WebURL;
229 using content::BrowserContext;
230 using content::ChildProcessSecurityPolicy;
231 using content::DownloadManager;
232 using content::NavigationEntry;
233 using content::OpenURLParams;
234 using content::RenderFrameHost;
235 using content::RenderViewHost;
236 using content::SSLStatus;
237 using content::WebContents;
238 using download::DownloadUrlParameters;
239 using extensions::ContextMenuMatcher;
240 using extensions::Extension;
241 using extensions::MenuItem;
242 using extensions::MenuManager;
243 
244 namespace {
245 
GetMenuShownCallback()246 base::OnceCallback<void(RenderViewContextMenu*)>* GetMenuShownCallback() {
247   static base::NoDestructor<base::OnceCallback<void(RenderViewContextMenu*)>>
248       callback;
249   return callback.get();
250 }
251 
252 enum class UmaEnumIdLookupType {
253   GeneralEnumId,
254   ContextSpecificEnumId,
255 };
256 
GetIdcToUmaMap(UmaEnumIdLookupType type)257 const std::map<int, int>& GetIdcToUmaMap(UmaEnumIdLookupType type) {
258   // These maps are from IDC_* -> UMA value. Never alter UMA ids. You may remove
259   // items, but add a line to keep the old value from being reused.
260 
261   // These UMA values are for the the RenderViewContextMenuItem enum, used for
262   // the RenderViewContextMenu.Shown and RenderViewContextMenu.Used histograms.
263   static const base::NoDestructor<std::map<int, int>> kGeneralMap(
264       {// NB: UMA values for 0 and 1 are detected using
265        // RenderViewContextMenu::IsContentCustomCommandId() and
266        // ContextMenuMatcher::IsExtensionsCustomCommandId()
267        {IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST, 2},
268        {IDC_CONTENT_CONTEXT_OPENLINKNEWTAB, 3},
269        {IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW, 4},
270        {IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD, 5},
271        {IDC_CONTENT_CONTEXT_SAVELINKAS, 6},
272        {IDC_CONTENT_CONTEXT_SAVEAVAS, 7},
273        {IDC_CONTENT_CONTEXT_SAVEIMAGEAS, 8},
274        {IDC_CONTENT_CONTEXT_COPYLINKLOCATION, 9},
275        {IDC_CONTENT_CONTEXT_COPYIMAGELOCATION, 10},
276        {IDC_CONTENT_CONTEXT_COPYAVLOCATION, 11},
277        {IDC_CONTENT_CONTEXT_COPYIMAGE, 12},
278        {IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB, 13},
279        {IDC_CONTENT_CONTEXT_OPENAVNEWTAB, 14},
280        {IDC_CONTENT_CONTEXT_PLAYPAUSE, 15},
281        {IDC_CONTENT_CONTEXT_MUTE, 16},
282        {IDC_CONTENT_CONTEXT_LOOP, 17},
283        {IDC_CONTENT_CONTEXT_CONTROLS, 18},
284        {IDC_CONTENT_CONTEXT_ROTATECW, 19},
285        {IDC_CONTENT_CONTEXT_ROTATECCW, 20},
286        {IDC_BACK, 21},
287        {IDC_FORWARD, 22},
288        {IDC_SAVE_PAGE, 23},
289        {IDC_RELOAD, 24},
290        {IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP, 25},
291        {IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP, 26},
292        {IDC_PRINT, 27},
293        {IDC_VIEW_SOURCE, 28},
294        {IDC_CONTENT_CONTEXT_INSPECTELEMENT, 29},
295        {IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE, 30},
296        {IDC_CONTENT_CONTEXT_VIEWPAGEINFO, 31},
297        {IDC_CONTENT_CONTEXT_TRANSLATE, 32},
298        {IDC_CONTENT_CONTEXT_RELOADFRAME, 33},
299        {IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE, 34},
300        {IDC_CONTENT_CONTEXT_VIEWFRAMEINFO, 35},
301        {IDC_CONTENT_CONTEXT_UNDO, 36},
302        {IDC_CONTENT_CONTEXT_REDO, 37},
303        {IDC_CONTENT_CONTEXT_CUT, 38},
304        {IDC_CONTENT_CONTEXT_COPY, 39},
305        {IDC_CONTENT_CONTEXT_PASTE, 40},
306        {IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE, 41},
307        {IDC_CONTENT_CONTEXT_DELETE, 42},
308        {IDC_CONTENT_CONTEXT_SELECTALL, 43},
309        {IDC_CONTENT_CONTEXT_SEARCHWEBFOR, 44},
310        {IDC_CONTENT_CONTEXT_GOTOURL, 45},
311        {IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS, 46},
312        {IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS, 47},
313        {IDC_CONTENT_CONTEXT_OPENLINKWITH, 52},
314        {IDC_CHECK_SPELLING_WHILE_TYPING, 53},
315        {IDC_SPELLCHECK_MENU, 54},
316        {IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, 55},
317        {IDC_SPELLCHECK_LANGUAGES_FIRST, 56},
318        {IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE, 57},
319        {IDC_SPELLCHECK_SUGGESTION_0, 58},
320        {IDC_SPELLCHECK_ADD_TO_DICTIONARY, 59},
321        {IDC_SPELLPANEL_TOGGLE, 60},
322        {IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB, 61},
323        {IDC_WRITING_DIRECTION_MENU, 62},
324        {IDC_WRITING_DIRECTION_DEFAULT, 63},
325        {IDC_WRITING_DIRECTION_LTR, 64},
326        {IDC_WRITING_DIRECTION_RTL, 65},
327        {IDC_CONTENT_CONTEXT_LOAD_IMAGE, 66},
328        {IDC_ROUTE_MEDIA, 68},
329        {IDC_CONTENT_CONTEXT_COPYLINKTEXT, 69},
330        {IDC_CONTENT_CONTEXT_OPENLINKINPROFILE, 70},
331        {IDC_OPEN_LINK_IN_PROFILE_FIRST, 71},
332        {IDC_CONTENT_CONTEXT_GENERATEPASSWORD, 72},
333        {IDC_SPELLCHECK_MULTI_LINGUAL, 73},
334        {IDC_CONTENT_CONTEXT_OPEN_WITH1, 74},
335        {IDC_CONTENT_CONTEXT_OPEN_WITH2, 75},
336        {IDC_CONTENT_CONTEXT_OPEN_WITH3, 76},
337        {IDC_CONTENT_CONTEXT_OPEN_WITH4, 77},
338        {IDC_CONTENT_CONTEXT_OPEN_WITH5, 78},
339        {IDC_CONTENT_CONTEXT_OPEN_WITH6, 79},
340        {IDC_CONTENT_CONTEXT_OPEN_WITH7, 80},
341        {IDC_CONTENT_CONTEXT_OPEN_WITH8, 81},
342        {IDC_CONTENT_CONTEXT_OPEN_WITH9, 82},
343        {IDC_CONTENT_CONTEXT_OPEN_WITH10, 83},
344        {IDC_CONTENT_CONTEXT_OPEN_WITH11, 84},
345        {IDC_CONTENT_CONTEXT_OPEN_WITH12, 85},
346        {IDC_CONTENT_CONTEXT_OPEN_WITH13, 86},
347        {IDC_CONTENT_CONTEXT_OPEN_WITH14, 87},
348        {IDC_CONTENT_CONTEXT_EXIT_FULLSCREEN, 88},
349        {IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP, 89},
350        {IDC_CONTENT_CONTEXT_SHOWALLSAVEDPASSWORDS, 90},
351        {IDC_CONTENT_CONTEXT_PICTUREINPICTURE, 91},
352        {IDC_CONTENT_CONTEXT_EMOJI, 92},
353        {IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1, 93},
354        {IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION2, 94},
355        {IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION3, 95},
356        {IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION4, 96},
357        {IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION5, 97},
358        {IDC_CONTENT_CONTEXT_LOOK_UP, 98},
359        {IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE, 99},
360        {IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE_ONCE, 100},
361        {IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS, 101},
362        {IDC_SEND_TAB_TO_SELF, 102},
363        {IDC_CONTENT_LINK_SEND_TAB_TO_SELF, 103},
364        {IDC_SEND_TAB_TO_SELF_SINGLE_TARGET, 104},
365        {IDC_CONTENT_LINK_SEND_TAB_TO_SELF_SINGLE_TARGET, 105},
366        {IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE, 106},
367        {IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_MULTIPLE_DEVICES, 107},
368        {IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE, 108},
369        {IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES, 109},
370        {IDC_CONTENT_CONTEXT_GENERATE_QR_CODE, 110},
371        {IDC_CONTENT_CLIPBOARD_HISTORY_MENU, 111},
372        {IDC_CONTENT_CONTEXT_COPYLINKTOTEXT, 112},
373        // To add new items:
374        //   - Add one more line above this comment block, using the UMA value
375        //     from the line below this comment block.
376        //   - Increment the UMA value in that latter line.
377        //   - Add the new item to the RenderViewContextMenuItem enum in
378        //     tools/metrics/histograms/enums.xml.
379        {0, 113}});
380 
381   // These UMA values are for the the ContextMenuOptionDesktop enum, used for
382   // the ContextMenu.SelectedOptionDesktop histograms.
383   static const base::NoDestructor<std::map<int, int>> kSpecificMap(
384       {{IDC_CONTENT_CONTEXT_OPENLINKNEWTAB, 0},
385        {IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD, 1},
386        {IDC_CONTENT_CONTEXT_COPYLINKLOCATION, 2},
387        {IDC_CONTENT_CONTEXT_COPY, 3},
388        {IDC_CONTENT_CONTEXT_SAVELINKAS, 4},
389        {IDC_CONTENT_CONTEXT_SAVEIMAGEAS, 5},
390        {IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB, 6},
391        {IDC_CONTENT_CONTEXT_COPYIMAGE, 7},
392        {IDC_CONTENT_CONTEXT_COPYIMAGELOCATION, 8},
393        {IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE, 9},
394        {IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW, 10},
395        {IDC_PRINT, 11},
396        {IDC_CONTENT_CONTEXT_SEARCHWEBFOR, 12},
397        {IDC_CONTENT_CONTEXT_SAVEAVAS, 13},
398        {IDC_SPELLCHECK_SUGGESTION_0, 14},
399        {IDC_SPELLCHECK_ADD_TO_DICTIONARY, 15},
400        {IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, 16},
401        {IDC_CONTENT_CONTEXT_CUT, 17},
402        {IDC_CONTENT_CONTEXT_PASTE, 18},
403        {IDC_CONTENT_CONTEXT_GOTOURL, 19},
404        {IDC_CONTENT_CONTEXT_COPYLINKTOTEXT, 20},
405        // To add new items:
406        //   - Add one more line above this comment block, using the UMA value
407        //     from the line below this comment block.
408        //   - Increment the UMA value in that latter line.
409        //   - Add the new item to the ContextMenuOptionDesktop enum in
410        //     tools/metrics/histograms/enums.xml.
411        {0, 21}});
412 
413   return *(type == UmaEnumIdLookupType::GeneralEnumId ? kGeneralMap
414                                                       : kSpecificMap);
415 }
416 
GetUmaValueMax(UmaEnumIdLookupType type)417 int GetUmaValueMax(UmaEnumIdLookupType type) {
418   // The IDC_ "value" of 0 is really a sentinel for the UMA max value.
419   return GetIdcToUmaMap(type).find(0)->second;
420 }
421 
422 // Collapses large ranges of ids before looking for UMA enum.
CollapseCommandsForUMA(int id)423 int CollapseCommandsForUMA(int id) {
424   DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id));
425   DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id));
426 
427   if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
428       id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
429     return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
430   }
431 
432   if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
433       id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
434     return IDC_SPELLCHECK_LANGUAGES_FIRST;
435   }
436 
437   if (id >= IDC_SPELLCHECK_SUGGESTION_0 &&
438       id <= IDC_SPELLCHECK_SUGGESTION_LAST) {
439     return IDC_SPELLCHECK_SUGGESTION_0;
440   }
441 
442   if (id >= IDC_OPEN_LINK_IN_PROFILE_FIRST &&
443       id <= IDC_OPEN_LINK_IN_PROFILE_LAST) {
444     return IDC_OPEN_LINK_IN_PROFILE_FIRST;
445   }
446 
447   return id;
448 }
449 
450 // Returns UMA enum value for command specified by |id| or -1 if not found.
FindUMAEnumValueForCommand(int id,UmaEnumIdLookupType type)451 int FindUMAEnumValueForCommand(int id, UmaEnumIdLookupType type) {
452   if (RenderViewContextMenu::IsContentCustomCommandId(id))
453     return 0;
454 
455   if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
456     return 1;
457 
458   id = CollapseCommandsForUMA(id);
459   const auto& map = GetIdcToUmaMap(type);
460   auto it = map.find(id);
461   if (it == map.end())
462     return -1;
463 
464   return it->second;
465 }
466 
467 // Returns true if the command id is for opening a link.
IsCommandForOpenLink(int id)468 bool IsCommandForOpenLink(int id) {
469   return id == IDC_CONTENT_CONTEXT_OPENLINKNEWTAB ||
470          id == IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW ||
471          id == IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD ||
472          (id >= IDC_OPEN_LINK_IN_PROFILE_FIRST &&
473           id <= IDC_OPEN_LINK_IN_PROFILE_LAST);
474 }
475 
476 // Returns the preference of the profile represented by the |context|.
GetPrefs(content::BrowserContext * context)477 PrefService* GetPrefs(content::BrowserContext* context) {
478   return user_prefs::UserPrefs::Get(context);
479 }
480 
ExtensionPatternMatch(const extensions::URLPatternSet & patterns,const GURL & url)481 bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
482                            const GURL& url) {
483   // No patterns means no restriction, so that implicitly matches.
484   if (patterns.is_empty())
485     return true;
486   return patterns.MatchesURL(url);
487 }
488 
GetDocumentURL(const content::ContextMenuParams & params)489 const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
490   return params.frame_url.is_empty() ? params.page_url : params.frame_url;
491 }
492 
CreateReferrer(const GURL & url,const content::ContextMenuParams & params)493 content::Referrer CreateReferrer(const GURL& url,
494                                  const content::ContextMenuParams& params) {
495   const GURL& referring_url = GetDocumentURL(params);
496   return content::Referrer::SanitizeForRequest(
497       url,
498       content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
499 }
500 
GetWebContentsToUse(content::WebContents * web_contents)501 content::WebContents* GetWebContentsToUse(content::WebContents* web_contents) {
502 #if BUILDFLAG(ENABLE_EXTENSIONS)
503   // If we're viewing in a MimeHandlerViewGuest, use its embedder WebContents.
504   auto* guest_view =
505       extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
506   if (guest_view)
507     return guest_view->embedder_web_contents();
508 #endif
509   return web_contents;
510 }
511 
512 bool g_custom_id_ranges_initialized = false;
513 
514 #if !defined(OS_CHROMEOS)
AddAvatarToLastMenuItem(const gfx::Image & icon,ui::SimpleMenuModel * menu)515 void AddAvatarToLastMenuItem(const gfx::Image& icon,
516                              ui::SimpleMenuModel* menu) {
517   // Don't try to scale too small icons.
518   if (icon.Width() < 16 || icon.Height() < 16)
519     return;
520   int target_dip_width = icon.Width();
521   int target_dip_height = icon.Height();
522   gfx::CalculateFaviconTargetSize(&target_dip_width, &target_dip_height);
523   gfx::Image sized_icon = profiles::GetSizedAvatarIcon(
524       icon, true /* is_rectangle */, target_dip_width, target_dip_height,
525       profiles::SHAPE_CIRCLE);
526   menu->SetIcon(menu->GetItemCount() - 1,
527                 ui::ImageModel::FromImage(sized_icon));
528 }
529 #endif  // !defined(OS_CHROMEOS)
530 
OnProfileCreated(const GURL & link_url,const content::Referrer & referrer,Profile * profile,Profile::CreateStatus status)531 void OnProfileCreated(const GURL& link_url,
532                       const content::Referrer& referrer,
533                       Profile* profile,
534                       Profile::CreateStatus status) {
535   if (status == Profile::CREATE_STATUS_INITIALIZED) {
536     Browser* browser = chrome::FindLastActiveWithProfile(profile);
537     NavigateParams nav_params(
538         browser, link_url,
539         /* |ui::PAGE_TRANSITION_TYPED| is used rather than
540            |ui::PAGE_TRANSITION_LINK| since this ultimately opens the link in
541            another browser. This parameter is used within the tab strip model of
542            the browser it opens in implying a link from the active tab in the
543            destination browser which is not correct. */
544         ui::PAGE_TRANSITION_TYPED);
545     nav_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
546     nav_params.referrer = referrer;
547     nav_params.window_action = NavigateParams::SHOW_WINDOW;
548     Navigate(&nav_params);
549   }
550 }
551 
DoesInputFieldTypeSupportEmoji(blink::ContextMenuDataInputFieldType text_input_type)552 bool DoesInputFieldTypeSupportEmoji(
553     blink::ContextMenuDataInputFieldType text_input_type) {
554   // Disable emoji for input types that definitely do not support emoji.
555   switch (text_input_type) {
556     case blink::ContextMenuDataInputFieldType::kNumber:
557     case blink::ContextMenuDataInputFieldType::kTelephone:
558     case blink::ContextMenuDataInputFieldType::kOther:
559       return false;
560     default:
561       return true;
562   }
563 }
564 
565 }  // namespace
566 
567 // static
IsDevToolsURL(const GURL & url)568 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
569   return url.SchemeIs(content::kChromeDevToolsScheme);
570 }
571 
572 // static
AddSpellCheckServiceItem(ui::SimpleMenuModel * menu,bool is_checked)573 void RenderViewContextMenu::AddSpellCheckServiceItem(ui::SimpleMenuModel* menu,
574                                                      bool is_checked) {
575   if (is_checked) {
576     menu->AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE,
577                                    IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE);
578   } else {
579     menu->AddItemWithStringId(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE,
580                               IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE);
581   }
582 }
583 
RenderViewContextMenu(content::RenderFrameHost * render_frame_host,const content::ContextMenuParams & params)584 RenderViewContextMenu::RenderViewContextMenu(
585     content::RenderFrameHost* render_frame_host,
586     const content::ContextMenuParams& params)
587     : RenderViewContextMenuBase(render_frame_host, params),
588       extension_items_(browser_context_,
589                        this,
590                        &menu_model_,
591                        base::Bind(MenuItemMatchesParams, params_)),
592       profile_link_submenu_model_(this),
593       multiple_profiles_open_(false),
594       protocol_handler_submenu_model_(this),
595       protocol_handler_registry_(
596           ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())),
597       accessibility_labels_submenu_model_(this),
598       embedder_web_contents_(GetWebContentsToUse(source_web_contents_)) {
599   if (!g_custom_id_ranges_initialized) {
600     g_custom_id_ranges_initialized = true;
601     SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
602                                    IDC_CONTENT_CONTEXT_CUSTOM_LAST);
603   }
604   set_content_type(
605       ContextMenuContentTypeFactory::Create(source_web_contents_, params));
606 }
607 
608 RenderViewContextMenu::~RenderViewContextMenu() = default;
609 
610 // Menu construction functions -------------------------------------------------
611 
612 #if BUILDFLAG(ENABLE_EXTENSIONS)
613 // static
ExtensionContextAndPatternMatch(const content::ContextMenuParams & params,const MenuItem::ContextList & contexts,const extensions::URLPatternSet & target_url_patterns)614 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
615     const content::ContextMenuParams& params,
616     const MenuItem::ContextList& contexts,
617     const extensions::URLPatternSet& target_url_patterns) {
618   const bool has_link = !params.link_url.is_empty();
619   const bool has_selection = !params.selection_text.empty();
620   const bool in_frame = !params.frame_url.is_empty();
621 
622   if (contexts.Contains(MenuItem::ALL) ||
623       (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
624       (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
625       (in_frame && contexts.Contains(MenuItem::FRAME)))
626     return true;
627 
628   if (has_link && contexts.Contains(MenuItem::LINK) &&
629       ExtensionPatternMatch(target_url_patterns, params.link_url))
630     return true;
631 
632   switch (params.media_type) {
633     case ContextMenuDataMediaType::kImage:
634       if (contexts.Contains(MenuItem::IMAGE) &&
635           ExtensionPatternMatch(target_url_patterns, params.src_url))
636         return true;
637       break;
638 
639     case ContextMenuDataMediaType::kVideo:
640       if (contexts.Contains(MenuItem::VIDEO) &&
641           ExtensionPatternMatch(target_url_patterns, params.src_url))
642         return true;
643       break;
644 
645     case ContextMenuDataMediaType::kAudio:
646       if (contexts.Contains(MenuItem::AUDIO) &&
647           ExtensionPatternMatch(target_url_patterns, params.src_url))
648         return true;
649       break;
650 
651     default:
652       break;
653   }
654 
655   // PAGE is the least specific context, so we only examine that if none of the
656   // other contexts apply (except for FRAME, which is included in PAGE for
657   // backwards compatibility).
658   if (!has_link && !has_selection && !params.is_editable &&
659       params.media_type == ContextMenuDataMediaType::kNone &&
660       contexts.Contains(MenuItem::PAGE))
661     return true;
662 
663   return false;
664 }
665 
666 // static
MenuItemMatchesParams(const content::ContextMenuParams & params,const extensions::MenuItem * item)667 bool RenderViewContextMenu::MenuItemMatchesParams(
668     const content::ContextMenuParams& params,
669     const extensions::MenuItem* item) {
670   bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
671                                                item->target_url_patterns());
672   if (!match)
673     return false;
674 
675   const GURL& document_url = GetDocumentURL(params);
676   return ExtensionPatternMatch(item->document_url_patterns(), document_url);
677 }
678 
AppendAllExtensionItems()679 void RenderViewContextMenu::AppendAllExtensionItems() {
680   extension_items_.Clear();
681   extensions::ExtensionRegistry* registry =
682       extensions::ExtensionRegistry::Get(browser_context_);
683 
684   MenuManager* menu_manager = MenuManager::Get(browser_context_);
685   if (!menu_manager)
686     return;
687 
688   base::string16 printable_selection_text = PrintableSelectionText();
689   EscapeAmpersands(&printable_selection_text);
690 
691   // Get a list of extension id's that have context menu items, and sort by the
692   // top level context menu title of the extension.
693   std::vector<base::string16> sorted_menu_titles;
694   std::map<base::string16, std::vector<const Extension*>>
695       title_to_extensions_map;
696   for (const auto& id : menu_manager->ExtensionIds()) {
697     const Extension* extension = registry->GetExtensionById(
698         id.extension_id, extensions::ExtensionRegistry::ENABLED);
699     // Platform apps have their context menus created directly in
700     // AppendPlatformAppItems.
701     if (extension && !extension->is_platform_app()) {
702       base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
703           id, printable_selection_text);
704       title_to_extensions_map[menu_title].push_back(extension);
705       sorted_menu_titles.push_back(menu_title);
706     }
707   }
708   if (sorted_menu_titles.empty())
709     return;
710 
711   const std::string app_locale = g_browser_process->GetApplicationLocale();
712   l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
713   sorted_menu_titles.erase(
714       std::unique(sorted_menu_titles.begin(), sorted_menu_titles.end()),
715       sorted_menu_titles.end());
716 
717   int index = 0;
718   for (const auto& title : sorted_menu_titles) {
719     const std::vector<const Extension*>& extensions =
720         title_to_extensions_map[title];
721     for (const Extension* extension : extensions) {
722       MenuItem::ExtensionKey extension_key(extension->id());
723       extension_items_.AppendExtensionItems(extension_key,
724                                             printable_selection_text, &index,
725                                             /*is_action_menu=*/false);
726     }
727   }
728 }
729 
AppendCurrentExtensionItems()730 void RenderViewContextMenu::AppendCurrentExtensionItems() {
731   // Avoid appending extension related items when |extension| is null.
732   // For Panel, this happens when the panel is navigated to a url outside of the
733   // extension's package.
734   const Extension* extension = GetExtension();
735   if (!extension)
736     return;
737 
738   extensions::WebViewGuest* web_view_guest =
739       extensions::WebViewGuest::FromWebContents(source_web_contents_);
740   MenuItem::ExtensionKey key;
741   if (web_view_guest) {
742     key = MenuItem::ExtensionKey(extension->id(),
743                                  web_view_guest->owner_web_contents()
744                                      ->GetMainFrame()
745                                      ->GetProcess()
746                                      ->GetID(),
747                                  web_view_guest->view_instance_id());
748   } else {
749     key = MenuItem::ExtensionKey(extension->id());
750   }
751 
752   // Only add extension items from this extension.
753   int index = 0;
754   extension_items_.AppendExtensionItems(key, PrintableSelectionText(), &index,
755                                         /*is_action_menu=*/false);
756 }
757 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
758 
FormatURLForClipboard(const GURL & url)759 base::string16 RenderViewContextMenu::FormatURLForClipboard(const GURL& url) {
760   DCHECK(!url.is_empty());
761   DCHECK(url.is_valid());
762 
763   GURL url_to_format = url;
764   url_formatter::FormatUrlTypes format_types;
765   net::UnescapeRule::Type unescape_rules;
766   if (url.SchemeIs(url::kMailToScheme)) {
767     GURL::Replacements replacements;
768     replacements.ClearQuery();
769     url_to_format = url.ReplaceComponents(replacements);
770     format_types = url_formatter::kFormatUrlOmitMailToScheme;
771     unescape_rules =
772         net::UnescapeRule::PATH_SEPARATORS |
773         net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS;
774   } else {
775     format_types = url_formatter::kFormatUrlOmitNothing;
776     unescape_rules = net::UnescapeRule::NONE;
777   }
778 
779   return url_formatter::FormatUrl(url_to_format, format_types, unescape_rules,
780                                   nullptr, nullptr, nullptr);
781 }
782 
WriteURLToClipboard(const GURL & url)783 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
784   if (url.is_empty() || !url.is_valid())
785     return;
786 
787   ui::ScopedClipboardWriter scw(
788       ui::ClipboardBuffer::kCopyPaste,
789       CreateDataEndpoint(/*notify_if_restricted=*/true));
790   scw.WriteText(FormatURLForClipboard(url));
791 }
792 
InitMenu()793 void RenderViewContextMenu::InitMenu() {
794   RenderViewContextMenuBase::InitMenu();
795 
796   if (content_type_->SupportsGroup(
797           ContextMenuContentType::ITEM_GROUP_PASSWORD)) {
798     AppendPasswordItems();
799   }
800 
801   if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE))
802     AppendPageItems();
803 
804   if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK)) {
805     AppendLinkItems();
806     if (params_.media_type != ContextMenuDataMediaType::kNone)
807       menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
808   }
809 
810   bool media_image = content_type_->SupportsGroup(
811       ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE);
812   if (media_image)
813     AppendImageItems();
814 
815   if (content_type_->SupportsGroup(
816           ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)) {
817     AppendSearchWebForImageItems();
818   }
819 
820   if (content_type_->SupportsGroup(
821           ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)) {
822     AppendVideoItems();
823   }
824 
825   if (content_type_->SupportsGroup(
826           ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO)) {
827     AppendAudioItems();
828   }
829 
830   if (content_type_->SupportsGroup(
831           ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS)) {
832     AppendCanvasItems();
833   }
834 
835   if (content_type_->SupportsGroup(
836           ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
837     AppendPluginItems();
838   }
839 
840   // ITEM_GROUP_MEDIA_FILE has no specific items.
841 
842   bool editable =
843       content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE);
844   if (editable)
845     AppendEditableItems();
846 
847   if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) {
848     DCHECK(!editable);
849     AppendCopyItem();
850 
851     if (base::FeatureList::IsEnabled(features::kCopyLinkToText)) {
852       AppendCopyLinkToTextItem();
853     }
854   }
855 
856   if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK))
857     AppendSharingItems();
858 
859   if (content_type_->SupportsGroup(
860           ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER) &&
861       params_.misspelled_word.empty()) {
862     AppendSearchProvider();
863   }
864 
865   if (!media_image &&
866       content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)) {
867     AppendPrintItem();
868   }
869 
870   // Spell check and writing direction options are not currently supported by
871   // pepper plugins.
872   if (editable && params_.misspelled_word.empty() &&
873       !content_type_->SupportsGroup(
874           ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
875     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
876     AppendLanguageSettings();
877     AppendPlatformEditableItems();
878   }
879 
880   if (content_type_->SupportsGroup(
881           ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
882     AppendRotationItems();
883   }
884 
885   bool supports_smart_text_selection = false;
886 #if defined(OS_CHROMEOS)
887   supports_smart_text_selection =
888       content_type_->SupportsGroup(
889           ContextMenuContentType::ITEM_GROUP_SMART_SELECTION) &&
890       arc::IsArcPlayStoreEnabledForProfile(GetProfile());
891 #endif  // defined(OS_CHROMEOS)
892   if (supports_smart_text_selection)
893     AppendSmartSelectionActionItems();
894 
895   extension_items_.set_smart_text_selection_enabled(
896       supports_smart_text_selection);
897 
898   if (content_type_->SupportsGroup(
899           ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION)) {
900     DCHECK(!content_type_->SupportsGroup(
901         ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION));
902     AppendAllExtensionItems();
903   }
904 
905   if (content_type_->SupportsGroup(
906           ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION)) {
907     DCHECK(!content_type_->SupportsGroup(
908         ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION));
909     AppendCurrentExtensionItems();
910   }
911 
912   // Accessibility label items are appended to all menus when a screen reader
913   // is enabled. It can be difficult to open a specific context menu with a
914   // screen reader, so this is a UX approved solution.
915   bool added_accessibility_labels_items = AppendAccessibilityLabelsItems();
916 
917   if (content_type_->SupportsGroup(
918           ContextMenuContentType::ITEM_GROUP_DEVELOPER)) {
919     AppendDeveloperItems();
920   }
921 
922   if (content_type_->SupportsGroup(
923           ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT)) {
924     AppendDevtoolsForUnpackedExtensions();
925   }
926 
927   if (content_type_->SupportsGroup(
928           ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW)) {
929     AppendPrintPreviewItems();
930   }
931 
932   // Remove any redundant trailing separator.
933   int index = menu_model_.GetItemCount() - 1;
934   if (index >= 0 &&
935       menu_model_.GetTypeAt(index) == ui::MenuModel::TYPE_SEPARATOR) {
936     menu_model_.RemoveItemAt(index);
937   }
938 
939   // If there is only one item and it is the Accessibility labels item, remove
940   // it. We only show this item when it is not the only item.
941   // Note that the separator added in AppendAccessibilityLabelsItems will not
942   // actually be added if this is the first item in the list, so we don't need
943   // to check for or remove the initial separator.
944   if (added_accessibility_labels_items && menu_model_.GetItemCount() == 1) {
945     menu_model_.RemoveItemAt(0);
946   }
947 
948   // Always add Quick Answers view last, as it is rendered next to the context
949   // menu, meaning that each menu item added/removed in this function will cause
950   // it to visibly jump on the screen (see b/173569669).
951   AppendQuickAnswersItems();
952 }
953 
GetProfile() const954 Profile* RenderViewContextMenu::GetProfile() const {
955   return Profile::FromBrowserContext(browser_context_);
956 }
957 
RecordUsedItem(int id)958 void RenderViewContextMenu::RecordUsedItem(int id) {
959   // Log general ID.
960 
961   int enum_id =
962       FindUMAEnumValueForCommand(id, UmaEnumIdLookupType::GeneralEnumId);
963   if (enum_id == -1) {
964     NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
965     return;
966   }
967 
968   UMA_HISTOGRAM_EXACT_LINEAR(
969       "RenderViewContextMenu.Used", enum_id,
970       GetUmaValueMax(UmaEnumIdLookupType::GeneralEnumId));
971 
972   // Log other situations.
973 
974   if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK) &&
975       // Ignore link-related commands that don't actually open a link.
976       IsCommandForOpenLink(id) &&
977       // Ignore using right click + open in new tab for internal links.
978       !params_.link_url.SchemeIs(content::kChromeUIScheme)) {
979     const GURL doc_url = GetDocumentURL(params_);
980     const GURL history_url = GURL(chrome::kChromeUIHistoryURL);
981     if (doc_url == history_url.Resolve(chrome::kChromeUIHistorySyncedTabs)) {
982       UMA_HISTOGRAM_ENUMERATION(
983           "HistoryPage.OtherDevicesMenu",
984           browser_sync::SyncedTabsHistogram::OPENED_LINK_VIA_CONTEXT_MENU,
985           browser_sync::SyncedTabsHistogram::LIMIT);
986     } else if (doc_url == GURL(chrome::kChromeUIDownloadsURL)) {
987       base::RecordAction(base::UserMetricsAction(
988           "Downloads_OpenUrlOfDownloadedItemFromContextMenu"));
989     } else if (doc_url == GURL(chrome::kChromeSearchLocalNtpUrl)) {
990       base::RecordAction(
991           base::UserMetricsAction("NTP_LinkOpenedFromContextMenu"));
992     } else if (doc_url.GetOrigin() == chrome::kChromeSearchMostVisitedUrl) {
993       base::RecordAction(
994           base::UserMetricsAction("MostVisited_ClickedFromContextMenu"));
995     } else if (doc_url.GetOrigin() == GURL(chrome::kChromeUINewTabPageURL) ||
996                doc_url.GetOrigin() ==
997                    GURL(chrome::kChromeUIUntrustedNewTabPageUrl)) {
998       base::RecordAction(base::UserMetricsAction(
999           "NewTabPage.LinkOpenedFromContextMenu.WebUI"));
1000     }
1001   }
1002 
1003   // Log for specific contexts. Note that since the menu is displayed for
1004   // contexts (all of the ContextMenuContentType::SupportsXXX() functions),
1005   // these UMA metrics are necessarily best-effort in distilling into a context.
1006 
1007   enum_id = FindUMAEnumValueForCommand(
1008       id, UmaEnumIdLookupType::ContextSpecificEnumId);
1009   if (enum_id == -1)
1010     return;
1011 
1012   if (content_type_->SupportsGroup(
1013           ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)) {
1014     UMA_HISTOGRAM_EXACT_LINEAR(
1015         "ContextMenu.SelectedOptionDesktop.Video", enum_id,
1016         GetUmaValueMax(UmaEnumIdLookupType::ContextSpecificEnumId));
1017   } else if (content_type_->SupportsGroup(
1018                  ContextMenuContentType::ITEM_GROUP_LINK) &&
1019              content_type_->SupportsGroup(
1020                  ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE)) {
1021     UMA_HISTOGRAM_EXACT_LINEAR(
1022         "ContextMenu.SelectedOptionDesktop.ImageLink", enum_id,
1023         GetUmaValueMax(UmaEnumIdLookupType::ContextSpecificEnumId));
1024   } else if (content_type_->SupportsGroup(
1025                  ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE)) {
1026     UMA_HISTOGRAM_EXACT_LINEAR(
1027         "ContextMenu.SelectedOptionDesktop.Image", enum_id,
1028         GetUmaValueMax(UmaEnumIdLookupType::ContextSpecificEnumId));
1029   } else if (!params_.misspelled_word.empty()) {
1030     UMA_HISTOGRAM_EXACT_LINEAR(
1031         "ContextMenu.SelectedOptionDesktop.MisspelledWord", enum_id,
1032         GetUmaValueMax(UmaEnumIdLookupType::ContextSpecificEnumId));
1033   } else if (!params_.selection_text.empty() &&
1034              params_.media_type == ContextMenuDataMediaType::kNone) {
1035     // Probably just text.
1036     UMA_HISTOGRAM_EXACT_LINEAR(
1037         "ContextMenu.SelectedOptionDesktop.SelectedText", enum_id,
1038         GetUmaValueMax(UmaEnumIdLookupType::ContextSpecificEnumId));
1039   } else {
1040     UMA_HISTOGRAM_EXACT_LINEAR(
1041         "ContextMenu.SelectedOptionDesktop.Other", enum_id,
1042         GetUmaValueMax(UmaEnumIdLookupType::ContextSpecificEnumId));
1043   }
1044 }
1045 
RecordShownItem(int id)1046 void RenderViewContextMenu::RecordShownItem(int id) {
1047   int enum_id =
1048       FindUMAEnumValueForCommand(id, UmaEnumIdLookupType::GeneralEnumId);
1049   if (enum_id != -1) {
1050     UMA_HISTOGRAM_EXACT_LINEAR(
1051         "RenderViewContextMenu.Shown", enum_id,
1052         GetUmaValueMax(UmaEnumIdLookupType::GeneralEnumId));
1053   } else {
1054     // Just warning here. It's harder to maintain list of all possibly
1055     // visible items than executable items.
1056     DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
1057   }
1058 }
1059 
IsHTML5Fullscreen() const1060 bool RenderViewContextMenu::IsHTML5Fullscreen() const {
1061   Browser* browser = chrome::FindBrowserWithWebContents(source_web_contents_);
1062   if (!browser)
1063     return false;
1064 
1065   FullscreenController* controller =
1066       browser->exclusive_access_manager()->fullscreen_controller();
1067   return controller->IsTabFullscreen();
1068 }
1069 
IsPressAndHoldEscRequiredToExitFullscreen() const1070 bool RenderViewContextMenu::IsPressAndHoldEscRequiredToExitFullscreen() const {
1071   Browser* browser = chrome::FindBrowserWithWebContents(source_web_contents_);
1072   if (!browser)
1073     return false;
1074 
1075   KeyboardLockController* controller =
1076       browser->exclusive_access_manager()->keyboard_lock_controller();
1077   return controller->RequiresPressAndHoldEscToExit();
1078 }
1079 
1080 #if BUILDFLAG(ENABLE_PLUGINS)
HandleAuthorizeAllPlugins()1081 void RenderViewContextMenu::HandleAuthorizeAllPlugins() {
1082   ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
1083       source_web_contents_, false, std::string());
1084 }
1085 #endif
1086 
AppendPrintPreviewItems()1087 void RenderViewContextMenu::AppendPrintPreviewItems() {
1088 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
1089   if (!print_preview_menu_observer_) {
1090     print_preview_menu_observer_ =
1091         std::make_unique<PrintPreviewContextMenuObserver>(source_web_contents_);
1092   }
1093 
1094   observers_.AddObserver(print_preview_menu_observer_.get());
1095 #endif
1096 }
1097 
GetExtension() const1098 const Extension* RenderViewContextMenu::GetExtension() const {
1099   return extensions::ProcessManager::Get(browser_context_)
1100       ->GetExtensionForWebContents(source_web_contents_);
1101 }
1102 
GetTargetLanguage() const1103 std::string RenderViewContextMenu::GetTargetLanguage() const {
1104   std::unique_ptr<translate::TranslatePrefs> prefs(
1105       ChromeTranslateClient::CreateTranslatePrefs(GetPrefs(browser_context_)));
1106   language::LanguageModel* language_model =
1107       LanguageModelManagerFactory::GetForBrowserContext(browser_context_)
1108           ->GetPrimaryModel();
1109   return translate::TranslateManager::GetTargetLanguage(prefs.get(),
1110                                                         language_model);
1111 }
1112 
AppendDeveloperItems()1113 void RenderViewContextMenu::AppendDeveloperItems() {
1114   // Do not Show Inspect Element for DevTools.
1115   bool show_developer_items = !IsDevToolsURL(params_.page_url);
1116 
1117   if (!show_developer_items)
1118     return;
1119 
1120   // In the DevTools popup menu, "developer items" is normally the only
1121   // section, so omit the separator there.
1122   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1123   if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE))
1124     menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
1125                                     IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
1126   if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME)) {
1127     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
1128                                     IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
1129     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
1130                                     IDS_CONTENT_CONTEXT_RELOADFRAME);
1131   }
1132   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
1133                                   IDS_CONTENT_CONTEXT_INSPECTELEMENT);
1134 }
1135 
AppendDevtoolsForUnpackedExtensions()1136 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
1137   // Add a separator if there are any items already in the menu.
1138   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1139 
1140   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
1141                                   IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
1142   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
1143                                   IDS_CONTENT_CONTEXT_RESTART_APP);
1144   AppendDeveloperItems();
1145   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
1146                                   IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
1147 }
1148 
AppendLinkItems()1149 void RenderViewContextMenu::AppendLinkItems() {
1150   if (!params_.link_url.is_empty()) {
1151     const Browser* browser = GetBrowser();
1152     const bool in_app = browser && browser->deprecated_is_app();
1153     WebContents* active_web_contents =
1154         browser ? browser->tab_strip_model()->GetActiveWebContents() : nullptr;
1155 
1156     menu_model_.AddItemWithStringId(
1157         IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
1158         in_app ? IDS_CONTENT_CONTEXT_OPENLINKNEWTAB_INAPP
1159                : IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
1160     if (!in_app) {
1161       menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
1162                                       IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
1163     }
1164 
1165     if (params_.link_url.is_valid()) {
1166       AppendProtocolHandlerSubMenu();
1167     }
1168 
1169     menu_model_.AddItemWithStringId(
1170         IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
1171         in_app ? IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD_INAPP
1172                : IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
1173 
1174     AppendOpenInWebAppLinkItems();
1175     AppendOpenWithLinkItems();
1176 
1177     // While ChromeOS supports multiple profiles, only one can be open at a
1178     // time.
1179     // TODO(jochen): Consider adding support for ChromeOS with similar
1180     // semantics as the profile switcher in the system tray.
1181 #if !defined(OS_CHROMEOS)
1182     // g_browser_process->profile_manager() is null during unit tests.
1183     if (g_browser_process->profile_manager() &&
1184         GetProfile()->IsRegularProfile()) {
1185       ProfileManager* profile_manager = g_browser_process->profile_manager();
1186       // Find all regular profiles other than the current one which have at
1187       // least one open window.
1188       std::vector<ProfileAttributesEntry*> entries =
1189           profile_manager->GetProfileAttributesStorage()
1190               .GetAllProfilesAttributesSortedByName();
1191       std::vector<ProfileAttributesEntry*> target_profiles_entries;
1192       for (ProfileAttributesEntry* entry : entries) {
1193         base::FilePath profile_path = entry->GetPath();
1194         Profile* profile = profile_manager->GetProfileByPath(profile_path);
1195         if (profile != GetProfile() && !entry->IsOmitted() &&
1196             !entry->IsSigninRequired()) {
1197           target_profiles_entries.push_back(entry);
1198           if (chrome::FindLastActiveWithProfile(profile))
1199             multiple_profiles_open_ = true;
1200         }
1201       }
1202 
1203       if (multiple_profiles_open_ && !target_profiles_entries.empty()) {
1204         if (target_profiles_entries.size() == 1) {
1205           int menu_index = static_cast<int>(profile_link_paths_.size());
1206           ProfileAttributesEntry* entry = target_profiles_entries.front();
1207           profile_link_paths_.push_back(entry->GetPath());
1208           menu_model_.AddItem(
1209               IDC_OPEN_LINK_IN_PROFILE_FIRST + menu_index,
1210               l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_OPENLINKINPROFILE,
1211                                          entry->GetName()));
1212           AddAvatarToLastMenuItem(entry->GetAvatarIcon(), &menu_model_);
1213         } else {
1214           for (ProfileAttributesEntry* entry : target_profiles_entries) {
1215             int menu_index = static_cast<int>(profile_link_paths_.size());
1216             // In extreme cases, we might have more profiles than available
1217             // command ids. In that case, just stop creating new entries - the
1218             // menu is probably useless at this point already.
1219             if (IDC_OPEN_LINK_IN_PROFILE_FIRST + menu_index >
1220                 IDC_OPEN_LINK_IN_PROFILE_LAST) {
1221               break;
1222             }
1223             profile_link_paths_.push_back(entry->GetPath());
1224             profile_link_submenu_model_.AddItem(
1225                 IDC_OPEN_LINK_IN_PROFILE_FIRST + menu_index, entry->GetName());
1226             AddAvatarToLastMenuItem(entry->GetAvatarIcon(),
1227                                     &profile_link_submenu_model_);
1228           }
1229           menu_model_.AddSubMenuWithStringId(
1230               IDC_CONTENT_CONTEXT_OPENLINKINPROFILE,
1231               IDS_CONTENT_CONTEXT_OPENLINKINPROFILES,
1232               &profile_link_submenu_model_);
1233         }
1234       }
1235     }
1236 #endif  // !defined(OS_CHROMEOS)
1237 
1238     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1239 
1240     // Place QR Generator close to send-tab-to-self feature for link images.
1241     if (params_.has_image_contents)
1242       AppendQRCodeGeneratorItem(/*for_image=*/true, /*draw_icon=*/true);
1243 
1244     if (browser && send_tab_to_self::ShouldOfferFeatureForLink(
1245                        active_web_contents, params_.link_url)) {
1246       if (send_tab_to_self::GetValidDeviceCount(GetBrowser()->profile()) == 1) {
1247 #if defined(OS_MAC)
1248         menu_model_.AddItem(IDC_CONTENT_LINK_SEND_TAB_TO_SELF_SINGLE_TARGET,
1249                             l10n_util::GetStringFUTF16(
1250                                 IDS_LINK_MENU_SEND_TAB_TO_SELF_SINGLE_TARGET,
1251                                 send_tab_to_self::GetSingleTargetDeviceName(
1252                                     GetBrowser()->profile())));
1253 #else
1254         menu_model_.AddItemWithIcon(
1255             IDC_CONTENT_LINK_SEND_TAB_TO_SELF_SINGLE_TARGET,
1256             l10n_util::GetStringFUTF16(
1257                 IDS_LINK_MENU_SEND_TAB_TO_SELF_SINGLE_TARGET,
1258                 send_tab_to_self::GetSingleTargetDeviceName(
1259                     GetBrowser()->profile())),
1260             ui::ImageModel::FromVectorIcon(kSendTabToSelfIcon));
1261 #endif
1262       } else {
1263         send_tab_to_self_sub_menu_model_ =
1264             std::make_unique<send_tab_to_self::SendTabToSelfSubMenuModel>(
1265                 active_web_contents,
1266                 send_tab_to_self::SendTabToSelfMenuType::kLink,
1267                 params_.link_url);
1268 #if defined(OS_MAC)
1269         menu_model_.AddSubMenuWithStringId(
1270             IDC_CONTENT_LINK_SEND_TAB_TO_SELF, IDS_LINK_MENU_SEND_TAB_TO_SELF,
1271             send_tab_to_self_sub_menu_model_.get());
1272 #else
1273         menu_model_.AddSubMenuWithStringIdAndIcon(
1274             IDC_CONTENT_LINK_SEND_TAB_TO_SELF, IDS_LINK_MENU_SEND_TAB_TO_SELF,
1275             send_tab_to_self_sub_menu_model_.get(),
1276             ui::ImageModel::FromVectorIcon(kSendTabToSelfIcon));
1277 #endif
1278       }
1279     }
1280 
1281     AppendClickToCallItem();
1282 
1283     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1284     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
1285                                     IDS_CONTENT_CONTEXT_SAVELINKAS);
1286   }
1287 
1288   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
1289                                   params_.link_url.SchemeIs(url::kMailToScheme)
1290                                       ? IDS_CONTENT_CONTEXT_COPYEMAILADDRESS
1291                                       : IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
1292 
1293   if (params_.source_type == ui::MENU_SOURCE_TOUCH &&
1294       params_.media_type != ContextMenuDataMediaType::kImage &&
1295       !params_.link_text.empty()) {
1296     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYLINKTEXT,
1297                                     IDS_CONTENT_CONTEXT_COPYLINKTEXT);
1298   }
1299 }
1300 
AppendOpenWithLinkItems()1301 void RenderViewContextMenu::AppendOpenWithLinkItems() {
1302 #if defined(OS_CHROMEOS)
1303   open_with_menu_observer_ =
1304       std::make_unique<arc::OpenWithMenu>(browser_context_, this);
1305   observers_.AddObserver(open_with_menu_observer_.get());
1306   open_with_menu_observer_->InitMenu(params_);
1307 #endif
1308 }
1309 
AppendQuickAnswersItems()1310 void RenderViewContextMenu::AppendQuickAnswersItems() {
1311 #if defined(OS_CHROMEOS)
1312   if (!quick_answers_menu_observer_) {
1313     quick_answers_menu_observer_ =
1314         std::make_unique<QuickAnswersMenuObserver>(this);
1315   }
1316 
1317   observers_.AddObserver(quick_answers_menu_observer_.get());
1318   quick_answers_menu_observer_->InitMenu(params_);
1319 #endif
1320 }
1321 
AppendSmartSelectionActionItems()1322 void RenderViewContextMenu::AppendSmartSelectionActionItems() {
1323 #if defined(OS_CHROMEOS)
1324   start_smart_selection_action_menu_observer_ =
1325       std::make_unique<arc::StartSmartSelectionActionMenu>(this);
1326   observers_.AddObserver(start_smart_selection_action_menu_observer_.get());
1327 
1328   if (menu_model_.GetItemCount())
1329     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1330   start_smart_selection_action_menu_observer_->InitMenu(params_);
1331 #endif
1332 }
1333 
AppendOpenInWebAppLinkItems()1334 void RenderViewContextMenu::AppendOpenInWebAppLinkItems() {
1335   Profile* const profile = Profile::FromBrowserContext(browser_context_);
1336   if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile))
1337     return;
1338 
1339   base::Optional<web_app::AppId> app_id =
1340       web_app::FindInstalledAppWithUrlInScope(profile, params_.link_url);
1341   if (!app_id)
1342     return;
1343 
1344   int open_in_app_string_id;
1345   const Browser* browser = GetBrowser();
1346   if (browser && browser->app_name() ==
1347                      web_app::GenerateApplicationNameFromAppId(*app_id)) {
1348     open_in_app_string_id = IDS_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP_SAMEAPP;
1349   } else {
1350     open_in_app_string_id = IDS_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP;
1351   }
1352 
1353   auto* const provider = web_app::WebAppProviderBase::GetProviderBase(profile);
1354   menu_model_.AddItem(
1355       IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP,
1356       l10n_util::GetStringFUTF16(
1357           open_in_app_string_id,
1358           base::UTF8ToUTF16(provider->registrar().GetAppShortName(*app_id))));
1359 
1360   gfx::Image icon = gfx::Image::CreateFrom1xBitmap(
1361       provider->icon_manager().GetFavicon(*app_id));
1362   menu_model_.SetIcon(menu_model_.GetItemCount() - 1,
1363                       ui::ImageModel::FromImage(icon));
1364 }
1365 
AppendImageItems()1366 void RenderViewContextMenu::AppendImageItems() {
1367   if (!params_.has_image_contents) {
1368     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_LOAD_IMAGE,
1369                                     IDS_CONTENT_CONTEXT_LOAD_IMAGE);
1370   }
1371   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
1372                                   IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
1373   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
1374                                   IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
1375   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
1376                                   IDS_CONTENT_CONTEXT_COPYIMAGE);
1377   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
1378                                   IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
1379 
1380   // Don't double-add for linked images, which also add the item.
1381   if (params_.link_url.is_empty())
1382     AppendQRCodeGeneratorItem(/*for_image=*/true, /*draw_icon=*/false);
1383 }
1384 
AppendSearchWebForImageItems()1385 void RenderViewContextMenu::AppendSearchWebForImageItems() {
1386   if (!params_.has_image_contents)
1387     return;
1388 
1389   TemplateURLService* service =
1390       TemplateURLServiceFactory::GetForProfile(GetProfile());
1391   const TemplateURL* const provider = service->GetDefaultSearchProvider();
1392   if (!provider || provider->image_url().empty() ||
1393       !provider->image_url_ref().IsValid(service->search_terms_data())) {
1394     return;
1395   }
1396 
1397   menu_model_.AddItem(
1398       IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
1399       l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
1400                                  provider->short_name()));
1401 }
1402 
AppendAudioItems()1403 void RenderViewContextMenu::AppendAudioItems() {
1404   AppendMediaItems();
1405   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1406   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
1407                                   IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
1408   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
1409                                   IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
1410   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
1411                                   IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
1412   AppendMediaRouterItem();
1413 }
1414 
AppendCanvasItems()1415 void RenderViewContextMenu::AppendCanvasItems() {
1416   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
1417                                   IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
1418   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
1419                                   IDS_CONTENT_CONTEXT_COPYIMAGE);
1420 }
1421 
AppendVideoItems()1422 void RenderViewContextMenu::AppendVideoItems() {
1423   AppendMediaItems();
1424   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1425   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
1426                                   IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
1427   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
1428                                   IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
1429   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
1430                                   IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
1431   AppendPictureInPictureItem();
1432   AppendMediaRouterItem();
1433 }
1434 
AppendMediaItems()1435 void RenderViewContextMenu::AppendMediaItems() {
1436   menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
1437                                        IDS_CONTENT_CONTEXT_LOOP);
1438   menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
1439                                        IDS_CONTENT_CONTEXT_CONTROLS);
1440 }
1441 
AppendPluginItems()1442 void RenderViewContextMenu::AppendPluginItems() {
1443   if (params_.page_url == params_.src_url ||
1444       (guest_view::GuestViewBase::IsGuest(source_web_contents_) &&
1445        (!embedder_web_contents_ || !embedder_web_contents_->IsSavable()))) {
1446     // Both full page and embedded plugins are hosted as guest now,
1447     // the difference is a full page plugin is not considered as savable.
1448     // For full page plugin, we show page menu items so long as focus is not
1449     // within an editable text area.
1450     if (params_.link_url.is_empty() && params_.selection_text.empty() &&
1451         !params_.is_editable) {
1452       AppendPageItems();
1453     }
1454   } else {
1455     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
1456                                     IDS_CONTENT_CONTEXT_SAVEPAGEAS);
1457     // The "Print" menu item should always be included for plugins. If
1458     // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
1459     // is true the item will be added inside AppendPrintItem(). Otherwise we
1460     // add "Print" here.
1461     if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
1462       menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
1463   }
1464 }
1465 
AppendPageItems()1466 void RenderViewContextMenu::AppendPageItems() {
1467   AppendExitFullscreenItem();
1468 
1469   menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
1470   menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
1471   menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
1472   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1473   menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
1474                                   IDS_CONTENT_CONTEXT_SAVEPAGEAS);
1475   menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
1476   AppendMediaRouterItem();
1477 
1478   // Send-Tab-To-Self (user's other devices), page level.
1479   bool send_tab_to_self_menu_present = false;
1480   if (GetBrowser() &&
1481       send_tab_to_self::ShouldOfferFeature(
1482           GetBrowser()->tab_strip_model()->GetActiveWebContents())) {
1483     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1484     send_tab_to_self_menu_present = true;
1485     if (send_tab_to_self::GetValidDeviceCount(GetBrowser()->profile()) == 1) {
1486 #if defined(OS_MAC)
1487       menu_model_.AddItem(IDC_SEND_TAB_TO_SELF_SINGLE_TARGET,
1488                           l10n_util::GetStringFUTF16(
1489                               IDS_CONTEXT_MENU_SEND_TAB_TO_SELF_SINGLE_TARGET,
1490                               send_tab_to_self::GetSingleTargetDeviceName(
1491                                   GetBrowser()->profile())));
1492 #else
1493       menu_model_.AddItemWithIcon(
1494           IDC_SEND_TAB_TO_SELF_SINGLE_TARGET,
1495           l10n_util::GetStringFUTF16(
1496               IDS_CONTEXT_MENU_SEND_TAB_TO_SELF_SINGLE_TARGET,
1497               send_tab_to_self::GetSingleTargetDeviceName(
1498                   GetBrowser()->profile())),
1499           ui::ImageModel::FromVectorIcon(kSendTabToSelfIcon));
1500 #endif
1501     } else {
1502       send_tab_to_self_sub_menu_model_ =
1503           std::make_unique<send_tab_to_self::SendTabToSelfSubMenuModel>(
1504               GetBrowser()->tab_strip_model()->GetActiveWebContents(),
1505               send_tab_to_self::SendTabToSelfMenuType::kContent);
1506 #if defined(OS_MAC)
1507       menu_model_.AddSubMenuWithStringId(
1508           IDC_SEND_TAB_TO_SELF, IDS_CONTEXT_MENU_SEND_TAB_TO_SELF,
1509           send_tab_to_self_sub_menu_model_.get());
1510 #else
1511       menu_model_.AddSubMenuWithStringIdAndIcon(
1512           IDC_SEND_TAB_TO_SELF, IDS_CONTEXT_MENU_SEND_TAB_TO_SELF,
1513           send_tab_to_self_sub_menu_model_.get(),
1514           ui::ImageModel::FromVectorIcon(kSendTabToSelfIcon));
1515 #endif
1516     }
1517   }
1518 
1519   // Context menu item for QR Code Generator.
1520   if (IsQRCodeGeneratorEnabled()) {
1521     // This is presented alongside the send-tab-to-self items, though each may
1522     // be present without the other due to feature experimentation. Therefore we
1523     // may or may not need to create a new separator.
1524     if (!send_tab_to_self_menu_present)
1525       menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1526 
1527     AppendQRCodeGeneratorItem(/*for_image=*/false, /*draw_icon=*/true);
1528 
1529     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1530   } else if (send_tab_to_self_menu_present) {
1531     // Close out sharing section if send-tab-to-self was present but QR
1532     // generator was not.
1533     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1534   }
1535 
1536   ChromeTranslateClient* chrome_translate_client =
1537       ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1538   const bool canTranslate =
1539       chrome_translate_client &&
1540       chrome_translate_client->GetTranslateManager()->CanManuallyTranslate(
1541           true);
1542   if (canTranslate) {
1543     language::LanguageModel* language_model =
1544         LanguageModelManagerFactory::GetForBrowserContext(browser_context_)
1545             ->GetPrimaryModel();
1546     std::unique_ptr<translate::TranslatePrefs> prefs(
1547         ChromeTranslateClient::CreateTranslatePrefs(
1548             GetPrefs(browser_context_)));
1549     std::string locale = translate::TranslateManager::GetTargetLanguage(
1550         prefs.get(), language_model);
1551     base::string16 language =
1552         l10n_util::GetDisplayNameForLocale(locale, locale, true);
1553     menu_model_.AddItem(
1554         IDC_CONTENT_CONTEXT_TRANSLATE,
1555         l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
1556   }
1557 }
1558 
AppendExitFullscreenItem()1559 void RenderViewContextMenu::AppendExitFullscreenItem() {
1560   Browser* browser = GetBrowser();
1561   if (!browser)
1562     return;
1563 
1564   // Only show item if in fullscreen mode.
1565   if (!browser->exclusive_access_manager()
1566            ->fullscreen_controller()
1567            ->IsControllerInitiatedFullscreen()) {
1568     return;
1569   }
1570 
1571   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_EXIT_FULLSCREEN,
1572                                   IDS_CONTENT_CONTEXT_EXIT_FULLSCREEN);
1573   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1574 }
1575 
AppendCopyItem()1576 void RenderViewContextMenu::AppendCopyItem() {
1577   if (menu_model_.GetItemCount())
1578     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1579   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
1580                                   IDS_CONTENT_CONTEXT_COPY);
1581 }
1582 
AppendCopyLinkToTextItem()1583 void RenderViewContextMenu::AppendCopyLinkToTextItem() {
1584   if (copy_link_to_text_menu_observer_)
1585     return;
1586 
1587   copy_link_to_text_menu_observer_ = CopyLinkToTextMenuObserver::Create(this);
1588   if (copy_link_to_text_menu_observer_) {
1589     observers_.AddObserver(copy_link_to_text_menu_observer_.get());
1590     copy_link_to_text_menu_observer_->InitMenu(params_);
1591   }
1592 }
1593 
AppendPrintItem()1594 void RenderViewContextMenu::AppendPrintItem() {
1595   if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) &&
1596       (params_.media_type == ContextMenuDataMediaType::kNone ||
1597        params_.media_flags & WebContextMenuData::kMediaCanPrint) &&
1598       params_.misspelled_word.empty()) {
1599     menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
1600   }
1601 }
1602 
AppendMediaRouterItem()1603 void RenderViewContextMenu::AppendMediaRouterItem() {
1604   if (media_router::MediaRouterEnabled(browser_context_)) {
1605     menu_model_.AddItemWithStringId(IDC_ROUTE_MEDIA,
1606                                     IDS_MEDIA_ROUTER_MENU_ITEM_TITLE);
1607   }
1608 }
1609 
AppendRotationItems()1610 void RenderViewContextMenu::AppendRotationItems() {
1611   if (params_.media_flags & WebContextMenuData::kMediaCanRotate) {
1612     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1613     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
1614                                     IDS_CONTENT_CONTEXT_ROTATECW);
1615     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
1616                                     IDS_CONTENT_CONTEXT_ROTATECCW);
1617   }
1618 }
1619 
AppendSearchProvider()1620 void RenderViewContextMenu::AppendSearchProvider() {
1621   DCHECK(browser_context_);
1622 
1623   base::TrimWhitespace(params_.selection_text, base::TRIM_ALL,
1624                        &params_.selection_text);
1625   if (params_.selection_text.empty())
1626     return;
1627 
1628   base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
1629                      base::ASCIIToUTF16(" "), &params_.selection_text);
1630 
1631   AutocompleteMatch match;
1632   AutocompleteClassifierFactory::GetForProfile(GetProfile())
1633       ->Classify(params_.selection_text, false, false,
1634                  metrics::OmniboxEventProto::INVALID_SPEC, &match, nullptr);
1635   selection_navigation_url_ = match.destination_url;
1636   if (!selection_navigation_url_.is_valid())
1637     return;
1638 
1639   base::string16 printable_selection_text = PrintableSelectionText();
1640   EscapeAmpersands(&printable_selection_text);
1641 
1642   if (AutocompleteMatch::IsSearchType(match.type)) {
1643     const TemplateURL* const default_provider =
1644         TemplateURLServiceFactory::GetForProfile(GetProfile())
1645             ->GetDefaultSearchProvider();
1646     if (!default_provider)
1647       return;
1648 
1649     if (!base::Contains(
1650             params_.properties,
1651             prefs::kDefaultSearchProviderContextMenuAccessAllowed)) {
1652       return;
1653     }
1654 
1655     menu_model_.AddItem(
1656         IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
1657         l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
1658                                    default_provider->short_name(),
1659                                    printable_selection_text));
1660   } else {
1661     if ((selection_navigation_url_ != params_.link_url) &&
1662         ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
1663             selection_navigation_url_.scheme())) {
1664       menu_model_.AddItem(
1665           IDC_CONTENT_CONTEXT_GOTOURL,
1666           l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
1667                                      printable_selection_text));
1668     }
1669   }
1670 }
1671 
AppendEditableItems()1672 void RenderViewContextMenu::AppendEditableItems() {
1673   const bool use_spelling = !chrome::IsRunningInForcedAppMode();
1674   if (use_spelling)
1675     AppendSpellingSuggestionItems();
1676 
1677   if (!params_.misspelled_word.empty()) {
1678     AppendSearchProvider();
1679     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1680   }
1681   if (params_.misspelled_word.empty() &&
1682       DoesInputFieldTypeSupportEmoji(params_.input_field_type) &&
1683       ui::IsEmojiPanelSupported()) {
1684     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_EMOJI,
1685                                     IDS_CONTENT_CONTEXT_EMOJI);
1686     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1687   }
1688 
1689 // 'Undo' and 'Redo' for text input with no suggestions and no text selected.
1690 // We make an exception for OS X as context clicking will select the closest
1691 // word. In this case both items are always shown.
1692 #if defined(OS_MAC)
1693   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
1694                                   IDS_CONTENT_CONTEXT_UNDO);
1695   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
1696                                   IDS_CONTENT_CONTEXT_REDO);
1697   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1698 #else
1699   // Also want to show 'Undo' and 'Redo' if 'Emoji' is the only item in the menu
1700   // so far.
1701   if (!IsDevToolsURL(params_.page_url) &&
1702       !content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT) &&
1703       (!menu_model_.GetItemCount() ||
1704        menu_model_.GetIndexOfCommandId(IDC_CONTENT_CONTEXT_EMOJI) != -1)) {
1705     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
1706                                     IDS_CONTENT_CONTEXT_UNDO);
1707     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
1708                                     IDS_CONTENT_CONTEXT_REDO);
1709     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1710   }
1711 #endif
1712 
1713   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
1714                                   IDS_CONTENT_CONTEXT_CUT);
1715   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
1716                                   IDS_CONTENT_CONTEXT_COPY);
1717   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
1718                                   IDS_CONTENT_CONTEXT_PASTE);
1719 
1720   const bool has_misspelled_word = !params_.misspelled_word.empty();
1721   if (!has_misspelled_word) {
1722     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
1723                                     IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
1724   }
1725 
1726 #if defined(OS_CHROMEOS)
1727   if (chromeos::features::IsClipboardHistoryEnabled()) {
1728     menu_model_.AddItemWithStringId(
1729         IDC_CONTENT_CLIPBOARD_HISTORY_MENU,
1730         IDS_CONTEXT_MENU_SHOW_CLIPBOARD_HISTORY_MENU);
1731   }
1732 #endif
1733 
1734   if (!has_misspelled_word) {
1735     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
1736                                     IDS_CONTENT_CONTEXT_SELECTALL);
1737   }
1738 
1739   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1740 }
1741 
AppendLanguageSettings()1742 void RenderViewContextMenu::AppendLanguageSettings() {
1743   const bool use_spelling = !chrome::IsRunningInForcedAppMode();
1744   if (!use_spelling)
1745     return;
1746 
1747 #if defined(OS_MAC)
1748   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS,
1749                                   IDS_CONTENT_CONTEXT_LANGUAGE_SETTINGS);
1750 #else
1751   if (!spelling_options_submenu_observer_) {
1752     const int kLanguageRadioGroup = 1;
1753     spelling_options_submenu_observer_ =
1754         std::make_unique<SpellingOptionsSubMenuObserver>(this, this,
1755                                                          kLanguageRadioGroup);
1756   }
1757 
1758   spelling_options_submenu_observer_->InitMenu(params_);
1759   observers_.AddObserver(spelling_options_submenu_observer_.get());
1760 #endif
1761 }
1762 
AppendSpellingSuggestionItems()1763 void RenderViewContextMenu::AppendSpellingSuggestionItems() {
1764   if (!spelling_suggestions_menu_observer_) {
1765     spelling_suggestions_menu_observer_ =
1766         std::make_unique<SpellingMenuObserver>(this);
1767   }
1768   observers_.AddObserver(spelling_suggestions_menu_observer_.get());
1769   spelling_suggestions_menu_observer_->InitMenu(params_);
1770 }
1771 
AppendAccessibilityLabelsItems()1772 bool RenderViewContextMenu::AppendAccessibilityLabelsItems() {
1773   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1774   if (!accessibility_labels_menu_observer_) {
1775     accessibility_labels_menu_observer_ =
1776         std::make_unique<AccessibilityLabelsMenuObserver>(this);
1777   }
1778   observers_.AddObserver(accessibility_labels_menu_observer_.get());
1779   accessibility_labels_menu_observer_->InitMenu(params_);
1780   return accessibility_labels_menu_observer_->ShouldShowLabelsItem();
1781 }
1782 
AppendProtocolHandlerSubMenu()1783 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
1784   const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1785       GetHandlersForLinkUrl();
1786   if (handlers.empty())
1787     return;
1788   size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
1789                IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1790   for (size_t i = 0; i < handlers.size() && i <= max; i++) {
1791     protocol_handler_submenu_model_.AddItem(
1792         IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
1793         base::UTF8ToUTF16(handlers[i].url().host()));
1794   }
1795   protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1796   protocol_handler_submenu_model_.AddItem(
1797       IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
1798       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
1799 
1800   menu_model_.AddSubMenu(
1801       IDC_CONTENT_CONTEXT_OPENLINKWITH,
1802       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
1803       &protocol_handler_submenu_model_);
1804 }
1805 
AppendPasswordItems()1806 void RenderViewContextMenu::AppendPasswordItems() {
1807   bool add_separator = false;
1808 
1809   password_manager::ContentPasswordManagerDriver* driver =
1810       password_manager::ContentPasswordManagerDriver::GetForRenderFrameHost(
1811           GetRenderFrameHost());
1812   // Don't show the item for guest or incognito profiles and also when the
1813   // automatic generation feature is disabled.
1814   if (password_manager_util::ManualPasswordGenerationEnabled(driver)) {
1815     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_GENERATEPASSWORD,
1816                                     IDS_CONTENT_CONTEXT_GENERATEPASSWORD);
1817     add_separator = true;
1818   }
1819   if (password_manager_util::ShowAllSavedPasswordsContextMenuEnabled(driver)) {
1820     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SHOWALLSAVEDPASSWORDS,
1821                                     IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK);
1822     add_separator = true;
1823   }
1824 
1825   if (add_separator)
1826     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1827 }
1828 
AppendPictureInPictureItem()1829 void RenderViewContextMenu::AppendPictureInPictureItem() {
1830   if (base::FeatureList::IsEnabled(media::kPictureInPicture))
1831     menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_PICTUREINPICTURE,
1832                                          IDS_CONTENT_CONTEXT_PICTUREINPICTURE);
1833 }
1834 
AppendSharingItems()1835 void RenderViewContextMenu::AppendSharingItems() {
1836   int items_initial = menu_model_.GetItemCount();
1837   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1838   // Check if the starting separator got added.
1839   int items_before_sharing = menu_model_.GetItemCount();
1840   bool starting_separator_added = items_before_sharing > items_initial;
1841 
1842   AppendClickToCallItem();
1843   AppendSharedClipboardItem();
1844 
1845   // Add an ending separator if there are sharing items, otherwise remove the
1846   // starting separator iff we added one above.
1847   int sharing_items = menu_model_.GetItemCount() - items_before_sharing;
1848   if (sharing_items > 0)
1849     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1850   else if (starting_separator_added)
1851     menu_model_.RemoveItemAt(items_initial);
1852 }
1853 
AppendClickToCallItem()1854 void RenderViewContextMenu::AppendClickToCallItem() {
1855   SharingClickToCallEntryPoint entry_point;
1856   base::Optional<std::string> phone_number;
1857   std::string selection_text;
1858   if (ShouldOfferClickToCallForURL(browser_context_, params_.link_url)) {
1859     entry_point = SharingClickToCallEntryPoint::kRightClickLink;
1860     phone_number = GetUnescapedURLContent(params_.link_url);
1861   } else if (!params_.selection_text.empty()) {
1862     entry_point = SharingClickToCallEntryPoint::kRightClickSelection;
1863     selection_text = base::UTF16ToUTF8(params_.selection_text);
1864     phone_number =
1865         ExtractPhoneNumberForClickToCall(browser_context_, selection_text);
1866   }
1867 
1868   if (!phone_number || phone_number->empty())
1869     return;
1870 
1871   if (!click_to_call_context_menu_observer_) {
1872     click_to_call_context_menu_observer_ =
1873         std::make_unique<ClickToCallContextMenuObserver>(this);
1874     observers_.AddObserver(click_to_call_context_menu_observer_.get());
1875   }
1876 
1877   click_to_call_context_menu_observer_->BuildMenu(*phone_number, selection_text,
1878                                                   entry_point);
1879 }
1880 
AppendSharedClipboardItem()1881 void RenderViewContextMenu::AppendSharedClipboardItem() {
1882   if (!ShouldOfferSharedClipboard(browser_context_, params_.selection_text))
1883     return;
1884 
1885   if (!shared_clipboard_context_menu_observer_) {
1886     shared_clipboard_context_menu_observer_ =
1887         std::make_unique<SharedClipboardContextMenuObserver>(this);
1888     observers_.AddObserver(shared_clipboard_context_menu_observer_.get());
1889   }
1890   shared_clipboard_context_menu_observer_->InitMenu(params_);
1891 }
1892 
1893 // Menu delegate functions -----------------------------------------------------
1894 
IsCommandIdEnabled(int id) const1895 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
1896   // Disable context menu in locked fullscreen mode (the menu is not really
1897   // disabled as the user can still open it, but all the individual context menu
1898   // entries are disabled / greyed out).
1899   if (GetBrowser() && platform_util::IsBrowserLockedFullscreen(GetBrowser()))
1900     return false;
1901 
1902   {
1903     bool enabled = false;
1904     if (RenderViewContextMenuBase::IsCommandIdKnown(id, &enabled))
1905       return enabled;
1906   }
1907 
1908   CoreTabHelper* core_tab_helper =
1909       CoreTabHelper::FromWebContents(source_web_contents_);
1910   int content_restrictions = 0;
1911   if (core_tab_helper)
1912     content_restrictions = core_tab_helper->content_restrictions();
1913   if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
1914     return false;
1915 
1916   if (id == IDC_SAVE_PAGE &&
1917       (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
1918     return false;
1919   }
1920 
1921   PrefService* prefs = GetPrefs(browser_context_);
1922 
1923   // Allow Spell Check language items on sub menu for text area context menu.
1924   if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
1925       (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
1926     return prefs->GetBoolean(spellcheck::prefs::kSpellCheckEnable);
1927   }
1928 
1929   // Extension items.
1930   if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1931     return extension_items_.IsCommandIdEnabled(id);
1932 
1933   if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1934       id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1935     return true;
1936   }
1937 
1938   if (id >= IDC_OPEN_LINK_IN_PROFILE_FIRST &&
1939       id <= IDC_OPEN_LINK_IN_PROFILE_LAST) {
1940     return params_.link_url.is_valid();
1941   }
1942 
1943   switch (id) {
1944     case IDC_BACK:
1945       return embedder_web_contents_->GetController().CanGoBack();
1946 
1947     case IDC_FORWARD:
1948       return embedder_web_contents_->GetController().CanGoForward();
1949 
1950     case IDC_RELOAD:
1951       return IsReloadEnabled();
1952 
1953     case IDC_VIEW_SOURCE:
1954     case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1955       return IsViewSourceEnabled();
1956 
1957     case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1958     case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
1959     case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
1960     case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
1961       return IsDevCommandEnabled(id);
1962 
1963     case IDC_CONTENT_CONTEXT_TRANSLATE:
1964       return IsTranslateEnabled();
1965 
1966     case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
1967     case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1968     case IDC_CONTENT_CONTEXT_OPENLINKINPROFILE:
1969     case IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP:
1970       return params_.link_url.is_valid();
1971 
1972     case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1973       return params_.unfiltered_link_url.is_valid();
1974 
1975     case IDC_CONTENT_CONTEXT_COPYLINKTEXT:
1976       return true;
1977 
1978     case IDC_CONTENT_CONTEXT_SAVELINKAS:
1979       return IsSaveLinkAsEnabled();
1980 
1981     case IDC_CONTENT_CONTEXT_SAVEIMAGEAS:
1982       return IsSaveImageAsEnabled();
1983 
1984     // The images shown in the most visited thumbnails can't be opened or
1985     // searched for conventionally.
1986     case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1987     case IDC_CONTENT_CONTEXT_LOAD_IMAGE:
1988     case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1989     case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1990       return params_.src_url.is_valid() &&
1991              (params_.src_url.scheme() != content::kChromeUIScheme);
1992 
1993     case IDC_CONTENT_CONTEXT_COPYIMAGE:
1994       return params_.has_image_contents;
1995 
1996     // Media control commands should all be disabled if the player is in an
1997     // error state.
1998     case IDC_CONTENT_CONTEXT_PLAYPAUSE:
1999       return (params_.media_flags & WebContextMenuData::kMediaInError) == 0;
2000 
2001     // Loop command should be disabled if the player is in an error state.
2002     case IDC_CONTENT_CONTEXT_LOOP:
2003       return (params_.media_flags & WebContextMenuData::kMediaCanLoop) != 0 &&
2004              (params_.media_flags & WebContextMenuData::kMediaInError) == 0;
2005 
2006     // Mute and unmute should also be disabled if the player has no audio.
2007     case IDC_CONTENT_CONTEXT_MUTE:
2008       return (params_.media_flags & WebContextMenuData::kMediaHasAudio) != 0 &&
2009              (params_.media_flags & WebContextMenuData::kMediaInError) == 0;
2010 
2011     case IDC_CONTENT_CONTEXT_CONTROLS:
2012       return (params_.media_flags &
2013               WebContextMenuData::kMediaCanToggleControls) != 0;
2014 
2015     case IDC_CONTENT_CONTEXT_ROTATECW:
2016     case IDC_CONTENT_CONTEXT_ROTATECCW:
2017       return (params_.media_flags & WebContextMenuData::kMediaCanRotate) != 0;
2018 
2019     case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
2020     case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
2021       return params_.src_url.is_valid();
2022 
2023     case IDC_CONTENT_CONTEXT_SAVEAVAS:
2024       return IsSaveAsEnabled();
2025 
2026     case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
2027       // Currently, a media element can be opened in a new tab iff it can
2028       // be saved. So rather than duplicating the MediaCanSave flag, we rely
2029       // on that here.
2030       return !!(params_.media_flags & WebContextMenuData::kMediaCanSave);
2031 
2032     case IDC_SAVE_PAGE:
2033       return IsSavePageEnabled();
2034 
2035     case IDC_CONTENT_CONTEXT_RELOADFRAME:
2036       return params_.frame_url.is_valid() &&
2037              params_.frame_url.GetOrigin() != chrome::kChromeUIPrintURL;
2038 
2039     case IDC_CONTENT_CONTEXT_UNDO:
2040       return !!(params_.edit_flags & ContextMenuDataEditFlags::kCanUndo);
2041 
2042     case IDC_CONTENT_CONTEXT_REDO:
2043       return !!(params_.edit_flags & ContextMenuDataEditFlags::kCanRedo);
2044 
2045     case IDC_CONTENT_CONTEXT_CUT:
2046       return !!(params_.edit_flags & ContextMenuDataEditFlags::kCanCut);
2047 
2048     case IDC_CONTENT_CONTEXT_COPY:
2049       return !!(params_.edit_flags & ContextMenuDataEditFlags::kCanCopy);
2050 
2051     case IDC_CONTENT_CONTEXT_PASTE:
2052       return IsPasteEnabled();
2053 
2054     case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
2055       return IsPasteAndMatchStyleEnabled();
2056 
2057     case IDC_CONTENT_CONTEXT_DELETE:
2058       return !!(params_.edit_flags & ContextMenuDataEditFlags::kCanDelete);
2059 
2060     case IDC_CONTENT_CONTEXT_SELECTALL:
2061       return !!(params_.edit_flags & ContextMenuDataEditFlags::kCanSelectAll);
2062 
2063     case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
2064       return IsOpenLinkOTREnabled();
2065 
2066     case IDC_PRINT:
2067       return IsPrintPreviewEnabled();
2068 
2069     case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
2070     case IDC_CONTENT_CONTEXT_GOTOURL:
2071     case IDC_SPELLPANEL_TOGGLE:
2072     case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
2073     case IDC_SEND_TAB_TO_SELF:
2074     case IDC_SEND_TAB_TO_SELF_SINGLE_TARGET:
2075       return true;
2076 
2077     case IDC_CONTENT_CONTEXT_GENERATE_QR_CODE:
2078       return IsQRCodeGeneratorEnabled();
2079 
2080     case IDC_CONTENT_LINK_SEND_TAB_TO_SELF:
2081     case IDC_CONTENT_LINK_SEND_TAB_TO_SELF_SINGLE_TARGET:
2082       return send_tab_to_self::AreContentRequirementsMet(
2083           params_.link_url, GetBrowser()->profile());
2084 
2085     case IDC_CHECK_SPELLING_WHILE_TYPING:
2086       return prefs->GetBoolean(spellcheck::prefs::kSpellCheckEnable);
2087 
2088 #if !defined(OS_MAC) && !defined(OS_BSD) && defined(OS_POSIX)
2089     // TODO(suzhe): this should not be enabled for password fields.
2090     case IDC_INPUT_METHODS_MENU:
2091       return true;
2092 #endif
2093 
2094     case IDC_SPELLCHECK_MENU:
2095     case IDC_CONTENT_CONTEXT_OPENLINKWITH:
2096     case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
2097     case IDC_CONTENT_CONTEXT_GENERATEPASSWORD:
2098     case IDC_CONTENT_CONTEXT_SHOWALLSAVEDPASSWORDS:
2099       return true;
2100 
2101     case IDC_ROUTE_MEDIA:
2102       return IsRouteMediaEnabled();
2103 
2104     case IDC_CONTENT_CONTEXT_EXIT_FULLSCREEN:
2105       return true;
2106 
2107     case IDC_CONTENT_CONTEXT_PICTUREINPICTURE:
2108       return !!(params_.media_flags &
2109                 WebContextMenuData::kMediaCanPictureInPicture);
2110 
2111     case IDC_CONTENT_CONTEXT_EMOJI:
2112       return params_.is_editable;
2113 
2114     case IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1:
2115     case IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION2:
2116     case IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION3:
2117     case IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION4:
2118     case IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION5:
2119       return true;
2120 
2121     case IDC_CONTENT_CLIPBOARD_HISTORY_MENU:
2122 #if defined(OS_CHROMEOS)
2123       if (chromeos::features::IsClipboardHistoryEnabled())
2124         return ash::ClipboardHistoryController::Get()->CanShowMenu();
2125 #else
2126       NOTREACHED();
2127 #endif
2128       return false;
2129 
2130     default:
2131       NOTREACHED();
2132       return false;
2133   }
2134 }
2135 
IsCommandIdChecked(int id) const2136 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
2137   if (RenderViewContextMenuBase::IsCommandIdChecked(id))
2138     return true;
2139 
2140   // See if the video is set to looping.
2141   if (id == IDC_CONTENT_CONTEXT_LOOP)
2142     return (params_.media_flags & WebContextMenuData::kMediaLoop) != 0;
2143 
2144   if (id == IDC_CONTENT_CONTEXT_CONTROLS)
2145     return (params_.media_flags & WebContextMenuData::kMediaControls) != 0;
2146 
2147   if (id == IDC_CONTENT_CONTEXT_PICTUREINPICTURE)
2148     return (params_.media_flags & WebContextMenuData::kMediaPictureInPicture) !=
2149            0;
2150 
2151   if (id == IDC_CONTENT_CONTEXT_EMOJI)
2152     return false;
2153 
2154   // Extension items.
2155   if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
2156     return extension_items_.IsCommandIdChecked(id);
2157 
2158   return false;
2159 }
2160 
IsCommandIdVisible(int id) const2161 bool RenderViewContextMenu::IsCommandIdVisible(int id) const {
2162   if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
2163     return extension_items_.IsCommandIdVisible(id);
2164   return RenderViewContextMenuBase::IsCommandIdVisible(id);
2165 }
2166 
ExecuteCommand(int id,int event_flags)2167 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
2168   RenderViewContextMenuBase::ExecuteCommand(id, event_flags);
2169   if (command_executed_)
2170     return;
2171   command_executed_ = true;
2172 
2173   // Process extension menu items.
2174   if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) {
2175     RenderFrameHost* render_frame_host = GetRenderFrameHost();
2176     if (render_frame_host) {
2177       extension_items_.ExecuteCommand(id, source_web_contents_,
2178                                       render_frame_host, params_);
2179     }
2180     return;
2181   }
2182 
2183   if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
2184       id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
2185     ExecProtocolHandler(event_flags,
2186                         id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST);
2187     return;
2188   }
2189 
2190   if (id >= IDC_OPEN_LINK_IN_PROFILE_FIRST &&
2191       id <= IDC_OPEN_LINK_IN_PROFILE_LAST) {
2192     ExecOpenLinkInProfile(id - IDC_OPEN_LINK_IN_PROFILE_FIRST);
2193     return;
2194   }
2195 
2196   switch (id) {
2197     case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
2198       OpenURLWithExtraHeaders(params_.link_url, GetDocumentURL(params_),
2199                               WindowOpenDisposition::NEW_BACKGROUND_TAB,
2200                               ui::PAGE_TRANSITION_LINK, "" /* extra_headers */,
2201                               true /* started_from_context_menu */);
2202       break;
2203 
2204     case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
2205       OpenURLWithExtraHeaders(params_.link_url, GetDocumentURL(params_),
2206                               WindowOpenDisposition::NEW_WINDOW,
2207                               ui::PAGE_TRANSITION_LINK, "" /* extra_headers */,
2208                               true /* started_from_context_menu */);
2209       break;
2210 
2211     case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
2212       OpenURLWithExtraHeaders(params_.link_url, GURL(),
2213                               WindowOpenDisposition::OFF_THE_RECORD,
2214                               ui::PAGE_TRANSITION_LINK, "" /* extra_headers */,
2215                               true /* started_from_context_menu */);
2216       break;
2217 
2218     case IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP:
2219       ExecOpenWebApp();
2220       break;
2221 
2222     case IDC_CONTENT_CONTEXT_SAVELINKAS:
2223       ExecSaveLinkAs();
2224       break;
2225 
2226     case IDC_CONTENT_CONTEXT_SAVEAVAS:
2227     case IDC_CONTENT_CONTEXT_SAVEIMAGEAS:
2228       ExecSaveAs();
2229       break;
2230 
2231     case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
2232       WriteURLToClipboard(params_.unfiltered_link_url);
2233       break;
2234 
2235     case IDC_CONTENT_CONTEXT_COPYLINKTEXT:
2236       ExecCopyLinkText();
2237       break;
2238 
2239     case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
2240     case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
2241       WriteURLToClipboard(params_.src_url);
2242       break;
2243 
2244     case IDC_CONTENT_CONTEXT_COPYIMAGE:
2245       ExecCopyImageAt();
2246       break;
2247 
2248     case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
2249       ExecSearchWebForImage();
2250       break;
2251 
2252     case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
2253       OpenURLWithExtraHeaders(params_.src_url, GetDocumentURL(params_),
2254                               WindowOpenDisposition::NEW_BACKGROUND_TAB,
2255                               ui::PAGE_TRANSITION_LINK, std::string(), false);
2256       break;
2257 
2258     case IDC_CONTENT_CONTEXT_LOAD_IMAGE:
2259       ExecLoadImage();
2260       break;
2261 
2262     case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
2263     case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
2264       OpenURL(params_.src_url, GetDocumentURL(params_),
2265               WindowOpenDisposition::NEW_BACKGROUND_TAB,
2266               ui::PAGE_TRANSITION_LINK);
2267       break;
2268 
2269     case IDC_CONTENT_CONTEXT_PLAYPAUSE:
2270       ExecPlayPause();
2271       break;
2272 
2273     case IDC_CONTENT_CONTEXT_MUTE:
2274       ExecMute();
2275       break;
2276 
2277     case IDC_CONTENT_CONTEXT_LOOP:
2278       ExecLoop();
2279       break;
2280 
2281     case IDC_CONTENT_CONTEXT_CONTROLS:
2282       ExecControls();
2283       break;
2284 
2285     case IDC_CONTENT_CONTEXT_ROTATECW:
2286       ExecRotateCW();
2287       break;
2288 
2289     case IDC_CONTENT_CONTEXT_ROTATECCW:
2290       ExecRotateCCW();
2291       break;
2292 
2293     case IDC_BACK:
2294       embedder_web_contents_->GetController().GoBack();
2295       break;
2296 
2297     case IDC_FORWARD:
2298       embedder_web_contents_->GetController().GoForward();
2299       break;
2300 
2301     case IDC_SAVE_PAGE:
2302       embedder_web_contents_->OnSavePage();
2303       break;
2304 
2305     case IDC_SEND_TAB_TO_SELF_SINGLE_TARGET:
2306       send_tab_to_self::ShareToSingleTarget(
2307           GetBrowser()->tab_strip_model()->GetActiveWebContents());
2308       send_tab_to_self::RecordSendTabToSelfClickResult(
2309           send_tab_to_self::kContentMenu, SendTabToSelfClickResult::kClickItem);
2310       break;
2311 
2312     case IDC_CONTENT_LINK_SEND_TAB_TO_SELF_SINGLE_TARGET:
2313       send_tab_to_self::ShareToSingleTarget(
2314           GetBrowser()->tab_strip_model()->GetActiveWebContents(),
2315           params_.link_url);
2316       send_tab_to_self::RecordSendTabToSelfClickResult(
2317           send_tab_to_self::kLinkMenu, SendTabToSelfClickResult::kClickItem);
2318       break;
2319 
2320     case IDC_CONTENT_CONTEXT_GENERATE_QR_CODE: {
2321       auto* web_contents =
2322           GetBrowser()->tab_strip_model()->GetActiveWebContents();
2323       auto* bubble_controller =
2324           qrcode_generator::QRCodeGeneratorBubbleController::Get(web_contents);
2325       if (params_.media_type == ContextMenuDataMediaType::kImage) {
2326         base::RecordAction(
2327             UserMetricsAction("SharingQRCode.DialogLaunched.ContextMenuImage"));
2328         bubble_controller->ShowBubble(params_.src_url);
2329       } else {
2330         base::RecordAction(
2331             UserMetricsAction("SharingQRCode.DialogLaunched.ContextMenuPage"));
2332         NavigationEntry* entry =
2333             embedder_web_contents_->GetController().GetLastCommittedEntry();
2334         bubble_controller->ShowBubble(entry->GetURL());
2335       }
2336       break;
2337     }
2338 
2339     case IDC_RELOAD:
2340       chrome::Reload(GetBrowser(), WindowOpenDisposition::CURRENT_TAB);
2341       break;
2342 
2343     case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
2344       ExecReloadPackagedApp();
2345       break;
2346 
2347     case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
2348       ExecRestartPackagedApp();
2349       break;
2350 
2351     case IDC_PRINT:
2352       ExecPrint();
2353       break;
2354 
2355     case IDC_ROUTE_MEDIA:
2356       ExecRouteMedia();
2357       break;
2358 
2359     case IDC_CONTENT_CONTEXT_EXIT_FULLSCREEN:
2360       ExecExitFullscreen();
2361       break;
2362 
2363     case IDC_VIEW_SOURCE:
2364       embedder_web_contents_->GetMainFrame()->ViewSource();
2365       break;
2366 
2367     case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
2368       ExecInspectElement();
2369       break;
2370 
2371     case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
2372       ExecInspectBackgroundPage();
2373       break;
2374 
2375     case IDC_CONTENT_CONTEXT_TRANSLATE:
2376       ExecTranslate();
2377       break;
2378 
2379     case IDC_CONTENT_CONTEXT_RELOADFRAME:
2380       source_web_contents_->ReloadFocusedFrame();
2381       break;
2382 
2383     case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
2384       if (GetRenderFrameHost())
2385         GetRenderFrameHost()->ViewSource();
2386       break;
2387 
2388     case IDC_CONTENT_CONTEXT_UNDO:
2389       source_web_contents_->Undo();
2390       break;
2391 
2392     case IDC_CONTENT_CONTEXT_REDO:
2393       source_web_contents_->Redo();
2394       break;
2395 
2396     case IDC_CONTENT_CONTEXT_CUT:
2397       source_web_contents_->Cut();
2398       break;
2399 
2400     case IDC_CONTENT_CONTEXT_COPY:
2401       source_web_contents_->Copy();
2402       break;
2403 
2404     case IDC_CONTENT_CONTEXT_PASTE:
2405       source_web_contents_->Paste();
2406       break;
2407 
2408     case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
2409       source_web_contents_->PasteAndMatchStyle();
2410       break;
2411 
2412     case IDC_CONTENT_CONTEXT_DELETE:
2413       source_web_contents_->Delete();
2414       break;
2415 
2416     case IDC_CONTENT_CONTEXT_SELECTALL:
2417       source_web_contents_->SelectAll();
2418       break;
2419 
2420     case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
2421     case IDC_CONTENT_CONTEXT_GOTOURL:
2422       OpenURL(selection_navigation_url_, GURL(),
2423               ui::DispositionFromEventFlags(
2424                   event_flags, WindowOpenDisposition::NEW_FOREGROUND_TAB),
2425               ui::PAGE_TRANSITION_LINK);
2426       break;
2427 
2428     case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
2429       ExecLanguageSettings(event_flags);
2430       break;
2431 
2432     case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
2433       ExecProtocolHandlerSettings(event_flags);
2434       break;
2435 
2436     case IDC_CONTENT_CONTEXT_GENERATEPASSWORD:
2437       password_manager_util::UserTriggeredManualGenerationFromContextMenu(
2438           ChromePasswordManagerClient::FromWebContents(source_web_contents_));
2439       break;
2440 
2441     case IDC_CONTENT_CONTEXT_SHOWALLSAVEDPASSWORDS:
2442       NavigateToManagePasswordsPage(
2443           GetBrowser(),
2444           password_manager::ManagePasswordsReferrer::kPasswordContextMenu);
2445       break;
2446 
2447     case IDC_CONTENT_CONTEXT_PICTUREINPICTURE:
2448       ExecPictureInPicture();
2449       break;
2450 
2451     case IDC_CONTENT_CONTEXT_EMOJI: {
2452       Browser* browser = GetBrowser();
2453       if (browser) {
2454         browser->window()->ShowEmojiPanel();
2455       } else {
2456         // TODO(https://crbug.com/919167): Ensure this is called in the correct
2457         // process. This fails in print preview for PWA windows on Mac.
2458         ui::ShowEmojiPanel();
2459       }
2460       break;
2461     }
2462 
2463     case IDC_CONTENT_CLIPBOARD_HISTORY_MENU: {
2464 #if defined(OS_CHROMEOS)
2465       // Calculate the anchor point in screen coordinates.
2466       gfx::Point anchor_point_in_screen =
2467           GetRenderFrameHost()->GetNativeView()->GetBoundsInScreen().origin();
2468       anchor_point_in_screen.Offset(params_.x, params_.y);
2469 
2470       // Calculate the menu source type from `event_flags`.
2471       ui::MenuSourceType source_type;
2472       if (event_flags & ui::EF_LEFT_MOUSE_BUTTON)
2473         source_type = ui::MENU_SOURCE_MOUSE;
2474       else if (event_flags & ui::EF_FROM_TOUCH)
2475         source_type = ui::MENU_SOURCE_TOUCH;
2476       else
2477         source_type = ui::MENU_SOURCE_KEYBOARD;
2478 
2479       ash::ClipboardHistoryController::Get()->ShowMenu(
2480           gfx::Rect(anchor_point_in_screen, gfx::Size()),
2481           views::MenuAnchorPosition::kTopLeft, source_type);
2482 #else
2483       NOTREACHED();
2484 #endif
2485       break;
2486     }
2487 
2488     default:
2489       NOTREACHED();
2490       break;
2491   }
2492 }
2493 
AddSpellCheckServiceItem(bool is_checked)2494 void RenderViewContextMenu::AddSpellCheckServiceItem(bool is_checked) {
2495   AddSpellCheckServiceItem(&menu_model_, is_checked);
2496 }
2497 
AddAccessibilityLabelsServiceItem(bool is_checked)2498 void RenderViewContextMenu::AddAccessibilityLabelsServiceItem(bool is_checked) {
2499   if (is_checked) {
2500     menu_model_.AddCheckItemWithStringId(
2501         IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE,
2502         IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_MENU_OPTION);
2503   } else {
2504     // Add the submenu if the whole feature is not enabled.
2505     accessibility_labels_submenu_model_.AddItemWithStringId(
2506         IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE,
2507         IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_SEND);
2508     accessibility_labels_submenu_model_.AddItemWithStringId(
2509         IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE_ONCE,
2510         IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_SEND_ONCE);
2511     menu_model_.AddSubMenu(
2512         IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS,
2513         l10n_util::GetStringUTF16(
2514             IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_MENU_OPTION),
2515         &accessibility_labels_submenu_model_);
2516   }
2517 }
2518 
2519 // static
RegisterMenuShownCallbackForTesting(base::OnceCallback<void (RenderViewContextMenu *)> cb)2520 void RenderViewContextMenu::RegisterMenuShownCallbackForTesting(
2521     base::OnceCallback<void(RenderViewContextMenu*)> cb) {
2522   *GetMenuShownCallback() = std::move(cb);
2523 }
2524 
2525 ProtocolHandlerRegistry::ProtocolHandlerList
GetHandlersForLinkUrl()2526 RenderViewContextMenu::GetHandlersForLinkUrl() {
2527   ProtocolHandlerRegistry::ProtocolHandlerList handlers =
2528       protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
2529   std::sort(handlers.begin(), handlers.end());
2530   return handlers;
2531 }
2532 
NotifyMenuShown()2533 void RenderViewContextMenu::NotifyMenuShown() {
2534   auto* cb = GetMenuShownCallback();
2535   if (!cb->is_null())
2536     std::move(*cb).Run(this);
2537 }
2538 
PrintableSelectionText()2539 base::string16 RenderViewContextMenu::PrintableSelectionText() {
2540   return gfx::TruncateString(params_.selection_text, kMaxSelectionTextLength,
2541                              gfx::WORD_BREAK);
2542 }
2543 
EscapeAmpersands(base::string16 * text)2544 void RenderViewContextMenu::EscapeAmpersands(base::string16* text) {
2545   base::ReplaceChars(*text, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
2546                      text);
2547 }
2548 
2549 // Controller functions --------------------------------------------------------
2550 
IsReloadEnabled() const2551 bool RenderViewContextMenu::IsReloadEnabled() const {
2552   CoreTabHelper* core_tab_helper =
2553       CoreTabHelper::FromWebContents(embedder_web_contents_);
2554   if (!core_tab_helper)
2555     return false;
2556 
2557   Browser* browser = GetBrowser();
2558   return !browser || browser->CanReloadContents(embedder_web_contents_);
2559 }
2560 
IsViewSourceEnabled() const2561 bool RenderViewContextMenu::IsViewSourceEnabled() const {
2562   if (!!extensions::MimeHandlerViewGuest::FromWebContents(
2563           source_web_contents_)) {
2564     return false;
2565   }
2566   return (params_.media_type != ContextMenuDataMediaType::kPlugin) &&
2567          embedder_web_contents_->GetController().CanViewSource();
2568 }
2569 
IsDevCommandEnabled(int id) const2570 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
2571   if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
2572       id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
2573     PrefService* prefs = GetPrefs(browser_context_);
2574     if (!prefs->GetBoolean(prefs::kWebKitJavascriptEnabled))
2575       return false;
2576 
2577     // Don't enable the web inspector if the developer tools are disabled via
2578     // the preference dev-tools-disabled.
2579     if (!DevToolsWindow::AllowDevToolsFor(GetProfile(), source_web_contents_))
2580       return false;
2581   }
2582 
2583   return true;
2584 }
2585 
IsTranslateEnabled() const2586 bool RenderViewContextMenu::IsTranslateEnabled() const {
2587   ChromeTranslateClient* chrome_translate_client =
2588       ChromeTranslateClient::FromWebContents(embedder_web_contents_);
2589   // If no |chrome_translate_client| attached with this WebContents or we're
2590   // viewing in a MimeHandlerViewGuest translate will be disabled.
2591   if (!chrome_translate_client ||
2592       !!extensions::MimeHandlerViewGuest::FromWebContents(
2593           source_web_contents_)) {
2594     return false;
2595   }
2596   std::string original_lang =
2597       chrome_translate_client->GetLanguageState().original_language();
2598   std::string target_lang = GetTargetLanguage();
2599   // Note that we intentionally enable the menu even if the original and
2600   // target languages are identical.  This is to give a way to user to
2601   // translate a page that might contains text fragments in a different
2602   // language.
2603   return ((params_.edit_flags & ContextMenuDataEditFlags::kCanTranslate) !=
2604           0) &&
2605          !original_lang.empty() &&  // Did we receive the page language yet?
2606          !chrome_translate_client->GetLanguageState().IsPageTranslated() &&
2607          // There are some application locales which can't be used as a
2608          // target language for translation. In that case GetTargetLanguage()
2609          // may return empty.
2610          !target_lang.empty() &&
2611          // Disable on the Instant Extended NTP.
2612          !search::IsInstantNTP(embedder_web_contents_);
2613 }
2614 
IsSaveLinkAsEnabled() const2615 bool RenderViewContextMenu::IsSaveLinkAsEnabled() const {
2616   PrefService* local_state = g_browser_process->local_state();
2617   DCHECK(local_state);
2618   // Test if file-selection dialogs are forbidden by policy.
2619   if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
2620     return false;
2621 
2622   PolicyBlocklistService* service =
2623       PolicyBlocklistFactory::GetForBrowserContext(browser_context_);
2624   if (service->GetURLBlocklistState(params_.link_url) ==
2625       policy::URLBlocklist::URLBlocklistState::URL_IN_BLOCKLIST) {
2626     return false;
2627   }
2628 
2629 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
2630   Profile* const profile = Profile::FromBrowserContext(browser_context_);
2631   if (profile->IsChild()) {
2632     SupervisedUserService* supervised_user_service =
2633         SupervisedUserServiceFactory::GetForProfile(profile);
2634     SupervisedUserURLFilter* url_filter =
2635         supervised_user_service->GetURLFilter();
2636     if (url_filter->GetFilteringBehaviorForURL(params_.link_url) !=
2637         SupervisedUserURLFilter::FilteringBehavior::ALLOW)
2638       return false;
2639   }
2640 #endif
2641 
2642   return params_.link_url.is_valid() &&
2643          ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
2644 }
2645 
IsSaveImageAsEnabled() const2646 bool RenderViewContextMenu::IsSaveImageAsEnabled() const {
2647   PrefService* local_state = g_browser_process->local_state();
2648   DCHECK(local_state);
2649   // Test if file-selection dialogs are forbidden by policy.
2650   if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
2651     return false;
2652 
2653   return params_.has_image_contents;
2654 }
2655 
IsSaveAsEnabled() const2656 bool RenderViewContextMenu::IsSaveAsEnabled() const {
2657   PrefService* local_state = g_browser_process->local_state();
2658   DCHECK(local_state);
2659   // Test if file-selection dialogs are forbidden by policy.
2660   if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
2661     return false;
2662 
2663   const GURL& url = params_.src_url;
2664   bool can_save = (params_.media_flags & WebContextMenuData::kMediaCanSave) &&
2665                   url.is_valid() &&
2666                   ProfileIOData::IsHandledProtocol(url.scheme());
2667 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
2668   // Do not save the preview PDF on the print preview page.
2669   can_save = can_save &&
2670              !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
2671 #endif
2672   return can_save;
2673 }
2674 
IsSavePageEnabled() const2675 bool RenderViewContextMenu::IsSavePageEnabled() const {
2676   CoreTabHelper* core_tab_helper =
2677       CoreTabHelper::FromWebContents(embedder_web_contents_);
2678   if (!core_tab_helper)
2679     return false;
2680 
2681   Browser* browser = GetBrowser();
2682   if (browser && !browser->CanSaveContents(embedder_web_contents_))
2683     return false;
2684 
2685   PrefService* local_state = g_browser_process->local_state();
2686   DCHECK(local_state);
2687   // Test if file-selection dialogs are forbidden by policy.
2688   if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
2689     return false;
2690 
2691   // We save the last committed entry (which the user is looking at), as
2692   // opposed to any pending URL that hasn't committed yet.
2693   NavigationEntry* entry =
2694       embedder_web_contents_->GetController().GetLastCommittedEntry();
2695   return content::IsSavableURL(entry ? entry->GetURL() : GURL());
2696 }
2697 
IsPasteEnabled() const2698 bool RenderViewContextMenu::IsPasteEnabled() const {
2699   if (!(params_.edit_flags & ContextMenuDataEditFlags::kCanPaste))
2700     return false;
2701 
2702   std::vector<base::string16> types;
2703   ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
2704       ui::ClipboardBuffer::kCopyPaste,
2705       CreateDataEndpoint(/*notify_if_restricted=*/false).get(), &types);
2706   return !types.empty();
2707 }
2708 
IsPasteAndMatchStyleEnabled() const2709 bool RenderViewContextMenu::IsPasteAndMatchStyleEnabled() const {
2710   if (!(params_.edit_flags & ContextMenuDataEditFlags::kCanPaste))
2711     return false;
2712 
2713   return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
2714       ui::ClipboardFormatType::GetPlainTextType(),
2715       ui::ClipboardBuffer::kCopyPaste,
2716       CreateDataEndpoint(/*notify_if_restricted=*/false).get());
2717 }
2718 
IsPrintPreviewEnabled() const2719 bool RenderViewContextMenu::IsPrintPreviewEnabled() const {
2720   if (params_.media_type != ContextMenuDataMediaType::kNone &&
2721       !(params_.media_flags & WebContextMenuData::kMediaCanPrint)) {
2722     return false;
2723   }
2724 
2725   Browser* browser = GetBrowser();
2726   return browser && chrome::CanPrint(browser);
2727 }
2728 
IsQRCodeGeneratorEnabled() const2729 bool RenderViewContextMenu::IsQRCodeGeneratorEnabled() const {
2730   if (!GetBrowser())
2731     return false;
2732 
2733   NavigationEntry* entry =
2734       embedder_web_contents_->GetController().GetLastCommittedEntry();
2735   if (!entry)
2736     return false;
2737 
2738   bool incognito = browser_context_->IsOffTheRecord();
2739   return qrcode_generator::QRCodeGeneratorBubbleController::
2740       IsGeneratorAvailable(entry->GetURL(), incognito);
2741 }
2742 
AppendQRCodeGeneratorItem(bool for_image,bool draw_icon)2743 void RenderViewContextMenu::AppendQRCodeGeneratorItem(bool for_image,
2744                                                       bool draw_icon) {
2745   if (!IsQRCodeGeneratorEnabled())
2746     return;
2747   auto string_id = for_image ? IDS_CONTEXT_MENU_GENERATE_QR_CODE_IMAGE
2748                              : IDS_CONTEXT_MENU_GENERATE_QR_CODE_PAGE;
2749 #if defined(OS_MAC)
2750   draw_icon = false;
2751 #endif
2752   if (draw_icon) {
2753     menu_model_.AddItemWithStringIdAndIcon(
2754         IDC_CONTENT_CONTEXT_GENERATE_QR_CODE, string_id,
2755         ui::ImageModel::FromVectorIcon(kQrcodeGeneratorIcon));
2756   } else {
2757     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_GENERATE_QR_CODE,
2758                                     string_id);
2759   }
2760 }
2761 
2762 std::unique_ptr<ui::DataTransferEndpoint>
CreateDataEndpoint(bool notify_if_restricted) const2763 RenderViewContextMenu::CreateDataEndpoint(bool notify_if_restricted) const {
2764   RenderFrameHost* render_frame_host = GetRenderFrameHost();
2765   if (render_frame_host) {
2766     return std::make_unique<ui::DataTransferEndpoint>(
2767         render_frame_host->GetLastCommittedOrigin(), notify_if_restricted);
2768   }
2769   return nullptr;
2770 }
2771 
IsRouteMediaEnabled() const2772 bool RenderViewContextMenu::IsRouteMediaEnabled() const {
2773   if (!media_router::MediaRouterEnabled(browser_context_))
2774     return false;
2775 
2776   Browser* browser = GetBrowser();
2777   if (!browser)
2778     return false;
2779 
2780   // Disable the command if there is an active modal dialog.
2781   // We don't use |source_web_contents_| here because it could be the
2782   // WebContents for something that's not the current tab (e.g., WebUI
2783   // modal dialog).
2784   WebContents* web_contents =
2785       browser->tab_strip_model()->GetActiveWebContents();
2786   if (!web_contents)
2787     return false;
2788 
2789   const web_modal::WebContentsModalDialogManager* manager =
2790       web_modal::WebContentsModalDialogManager::FromWebContents(web_contents);
2791   return !manager || !manager->IsDialogActive();
2792 }
2793 
IsOpenLinkOTREnabled() const2794 bool RenderViewContextMenu::IsOpenLinkOTREnabled() const {
2795   if (browser_context_->IsOffTheRecord() || !params_.link_url.is_valid())
2796     return false;
2797 
2798   if (!IsURLAllowedInIncognito(params_.link_url, browser_context_))
2799     return false;
2800 
2801   IncognitoModePrefs::Availability incognito_avail =
2802       IncognitoModePrefs::GetAvailability(GetPrefs(browser_context_));
2803   return incognito_avail != IncognitoModePrefs::DISABLED;
2804 }
2805 
ExecOpenWebApp()2806 void RenderViewContextMenu::ExecOpenWebApp() {
2807   base::Optional<web_app::AppId> app_id =
2808       web_app::FindInstalledAppWithUrlInScope(
2809           Profile::FromBrowserContext(browser_context_), params_.link_url);
2810   // |app_id| could be nullopt if it has been uninstalled since the user
2811   // opened the context menu.
2812   if (!app_id)
2813     return;
2814 
2815   apps::AppLaunchParams launch_params(
2816       *app_id, apps::mojom::LaunchContainer::kLaunchContainerWindow,
2817       WindowOpenDisposition::CURRENT_TAB,
2818       apps::mojom::AppLaunchSource::kSourceContextMenu);
2819   launch_params.override_url = params_.link_url;
2820   apps::AppServiceProxyFactory::GetForProfile(GetProfile())
2821       ->BrowserAppLauncher()
2822       ->LaunchAppWithParams(std::move(launch_params));
2823 }
2824 
ExecProtocolHandler(int event_flags,int handler_index)2825 void RenderViewContextMenu::ExecProtocolHandler(int event_flags,
2826                                                 int handler_index) {
2827   ProtocolHandlerRegistry::ProtocolHandlerList handlers =
2828       GetHandlersForLinkUrl();
2829   if (handlers.empty())
2830     return;
2831 
2832   base::RecordAction(
2833       UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
2834   WindowOpenDisposition disposition = ui::DispositionFromEventFlags(
2835       event_flags, WindowOpenDisposition::NEW_FOREGROUND_TAB);
2836   OpenURL(handlers[handler_index].TranslateUrl(params_.link_url),
2837           GetDocumentURL(params_), disposition, ui::PAGE_TRANSITION_LINK);
2838 }
2839 
ExecOpenLinkInProfile(int profile_index)2840 void RenderViewContextMenu::ExecOpenLinkInProfile(int profile_index) {
2841   DCHECK_GE(profile_index, 0);
2842   DCHECK_LE(profile_index, static_cast<int>(profile_link_paths_.size()));
2843 
2844   base::FilePath profile_path = profile_link_paths_[profile_index];
2845   profiles::SwitchToProfile(
2846       profile_path, false,
2847       base::Bind(OnProfileCreated, params_.link_url,
2848                  CreateReferrer(params_.link_url, params_)));
2849 }
2850 
ExecInspectElement()2851 void RenderViewContextMenu::ExecInspectElement() {
2852   base::RecordAction(UserMetricsAction("DevTools_InspectElement"));
2853   RenderFrameHost* render_frame_host = GetRenderFrameHost();
2854   if (!render_frame_host)
2855     return;
2856   DevToolsWindow::InspectElement(render_frame_host, params_.x, params_.y);
2857 }
2858 
ExecInspectBackgroundPage()2859 void RenderViewContextMenu::ExecInspectBackgroundPage() {
2860   const Extension* platform_app = GetExtension();
2861   DCHECK(platform_app);
2862   DCHECK(platform_app->is_platform_app());
2863 
2864   extensions::devtools_util::InspectBackgroundPage(platform_app, GetProfile());
2865 }
2866 
ExecSaveLinkAs()2867 void RenderViewContextMenu::ExecSaveLinkAs() {
2868   RenderFrameHost* render_frame_host = GetRenderFrameHost();
2869   if (!render_frame_host)
2870     return;
2871 
2872   RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
2873 
2874   const GURL& url = params_.link_url;
2875 
2876   net::NetworkTrafficAnnotationTag traffic_annotation =
2877       net::DefineNetworkTrafficAnnotation("render_view_context_menu", R"(
2878         semantics {
2879           sender: "Save Link As"
2880           description: "Saving url to local file."
2881           trigger:
2882             "The user selects the 'Save link as...' command in the context "
2883             "menu."
2884           data: "None."
2885           destination: WEBSITE
2886         }
2887         policy {
2888           cookies_allowed: YES
2889           cookies_store: "user"
2890           setting:
2891             "This feature cannot be disabled by settings. The request is made "
2892             "only if user chooses 'Save link as...' in the context menu."
2893           policy_exception_justification: "Not implemented."
2894         })");
2895 
2896   auto dl_params = std::make_unique<DownloadUrlParameters>(
2897       url, render_frame_host->GetProcess()->GetID(),
2898       render_frame_host->GetRoutingID(), traffic_annotation);
2899   content::Referrer referrer = CreateReferrer(url, params_);
2900   dl_params->set_referrer(referrer.url);
2901   dl_params->set_referrer_policy(
2902       content::Referrer::ReferrerPolicyForUrlRequest(referrer.policy));
2903   dl_params->set_referrer_encoding(params_.frame_charset);
2904   dl_params->set_suggested_name(params_.suggested_filename);
2905   dl_params->set_prompt(true);
2906   dl_params->set_download_source(download::DownloadSource::CONTEXT_MENU);
2907 
2908   BrowserContext::GetDownloadManager(browser_context_)
2909       ->DownloadUrl(std::move(dl_params));
2910 }
2911 
ExecSaveAs()2912 void RenderViewContextMenu::ExecSaveAs() {
2913   bool is_large_data_url =
2914       params_.has_image_contents && params_.src_url.is_empty();
2915   if (params_.media_type == ContextMenuDataMediaType::kCanvas ||
2916       (params_.media_type == ContextMenuDataMediaType::kImage &&
2917        is_large_data_url)) {
2918     RenderFrameHost* frame_host = GetRenderFrameHost();
2919     if (frame_host)
2920       frame_host->SaveImageAt(params_.x, params_.y);
2921   } else {
2922     RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
2923     const GURL& url = params_.src_url;
2924     content::Referrer referrer = CreateReferrer(url, params_);
2925     std::string headers;
2926     source_web_contents_->SaveFrameWithHeaders(url, referrer, headers,
2927                                                params_.suggested_filename);
2928   }
2929 }
2930 
ExecExitFullscreen()2931 void RenderViewContextMenu::ExecExitFullscreen() {
2932   Browser* browser = GetBrowser();
2933   if (!browser) {
2934     NOTREACHED();
2935     return;
2936   }
2937 
2938   browser->exclusive_access_manager()->ExitExclusiveAccess();
2939 }
2940 
ExecCopyLinkText()2941 void RenderViewContextMenu::ExecCopyLinkText() {
2942   ui::ScopedClipboardWriter scw(
2943       ui::ClipboardBuffer::kCopyPaste,
2944       CreateDataEndpoint(/*notify_if_restricted=*/true));
2945   scw.WriteText(params_.link_text);
2946 }
2947 
ExecCopyImageAt()2948 void RenderViewContextMenu::ExecCopyImageAt() {
2949   RenderFrameHost* frame_host = GetRenderFrameHost();
2950   if (frame_host)
2951     frame_host->CopyImageAt(params_.x, params_.y);
2952 }
2953 
ExecSearchWebForImage()2954 void RenderViewContextMenu::ExecSearchWebForImage() {
2955   CoreTabHelper* core_tab_helper =
2956       CoreTabHelper::FromWebContents(source_web_contents_);
2957   if (!core_tab_helper)
2958     return;
2959   RenderFrameHost* render_frame_host = GetRenderFrameHost();
2960   if (!render_frame_host)
2961     return;
2962   core_tab_helper->SearchByImageInNewTab(render_frame_host, params().src_url);
2963 }
2964 
ExecLoadImage()2965 void RenderViewContextMenu::ExecLoadImage() {
2966   RenderFrameHost* render_frame_host = GetRenderFrameHost();
2967   if (!render_frame_host)
2968     return;
2969   mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame> chrome_render_frame;
2970   render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
2971       &chrome_render_frame);
2972   chrome_render_frame->RequestReloadImageForContextNode();
2973 }
2974 
ExecPlayPause()2975 void RenderViewContextMenu::ExecPlayPause() {
2976   bool play = !!(params_.media_flags & WebContextMenuData::kMediaPaused);
2977   if (play)
2978     base::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
2979   else
2980     base::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
2981 
2982   MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
2983                       blink::mojom::MediaPlayerAction(
2984                           blink::mojom::MediaPlayerActionType::kPlay, play));
2985 }
2986 
ExecMute()2987 void RenderViewContextMenu::ExecMute() {
2988   bool mute = !(params_.media_flags & WebContextMenuData::kMediaMuted);
2989   if (mute)
2990     base::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
2991   else
2992     base::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
2993 
2994   MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
2995                       blink::mojom::MediaPlayerAction(
2996                           blink::mojom::MediaPlayerActionType::kMute, mute));
2997 }
2998 
ExecLoop()2999 void RenderViewContextMenu::ExecLoop() {
3000   base::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
3001   MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
3002                       blink::mojom::MediaPlayerAction(
3003                           blink::mojom::MediaPlayerActionType::kLoop,
3004                           !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
3005 }
3006 
ExecControls()3007 void RenderViewContextMenu::ExecControls() {
3008   base::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
3009   MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
3010                       blink::mojom::MediaPlayerAction(
3011                           blink::mojom::MediaPlayerActionType::kControls,
3012                           !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
3013 }
3014 
ExecRotateCW()3015 void RenderViewContextMenu::ExecRotateCW() {
3016   base::RecordAction(UserMetricsAction("PluginContextMenu_RotateClockwise"));
3017   PluginActionAt(gfx::Point(params_.x, params_.y),
3018                  blink::mojom::PluginActionType::kRotate90Clockwise);
3019 }
3020 
ExecRotateCCW()3021 void RenderViewContextMenu::ExecRotateCCW() {
3022   base::RecordAction(
3023       UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
3024   PluginActionAt(gfx::Point(params_.x, params_.y),
3025                  blink::mojom::PluginActionType::kRotate90Counterclockwise);
3026 }
3027 
ExecReloadPackagedApp()3028 void RenderViewContextMenu::ExecReloadPackagedApp() {
3029   const Extension* platform_app = GetExtension();
3030   DCHECK(platform_app);
3031   DCHECK(platform_app->is_platform_app());
3032 
3033   extensions::ExtensionSystem::Get(browser_context_)
3034       ->extension_service()
3035       ->ReloadExtension(platform_app->id());
3036 }
3037 
ExecRestartPackagedApp()3038 void RenderViewContextMenu::ExecRestartPackagedApp() {
3039   const Extension* platform_app = GetExtension();
3040   DCHECK(platform_app);
3041   DCHECK(platform_app->is_platform_app());
3042 
3043   apps::AppLoadService::Get(GetProfile())
3044       ->RestartApplication(platform_app->id());
3045 }
3046 
ExecPrint()3047 void RenderViewContextMenu::ExecPrint() {
3048 #if BUILDFLAG(ENABLE_PRINTING)
3049   if (params_.media_type != ContextMenuDataMediaType::kNone) {
3050     RenderFrameHost* rfh = GetRenderFrameHost();
3051     if (rfh) {
3052       mojo::AssociatedRemote<printing::mojom::PrintRenderFrame> remote;
3053       rfh->GetRemoteAssociatedInterfaces()->GetInterface(&remote);
3054       remote->PrintNodeUnderContextMenu();
3055     }
3056     return;
3057   }
3058 
3059   printing::StartPrint(
3060       source_web_contents_, mojo::NullAssociatedRemote(),
3061       GetPrefs(browser_context_)->GetBoolean(prefs::kPrintPreviewDisabled),
3062       !params_.selection_text.empty());
3063 #endif  // BUILDFLAG(ENABLE_PRINTING)
3064 }
3065 
ExecRouteMedia()3066 void RenderViewContextMenu::ExecRouteMedia() {
3067   if (!media_router::MediaRouterEnabled(browser_context_))
3068     return;
3069 
3070   media_router::MediaRouterDialogController* dialog_controller =
3071       media_router::MediaRouterDialogController::GetOrCreateForWebContents(
3072           embedder_web_contents_);
3073   if (!dialog_controller)
3074     return;
3075 
3076   dialog_controller->ShowMediaRouterDialog(
3077       media_router::MediaRouterDialogOpenOrigin::CONTEXTUAL_MENU);
3078   media_router::MediaRouterMetrics::RecordMediaRouterDialogOrigin(
3079       media_router::MediaRouterDialogOpenOrigin::CONTEXTUAL_MENU);
3080 }
3081 
ExecTranslate()3082 void RenderViewContextMenu::ExecTranslate() {
3083   ChromeTranslateClient* chrome_translate_client =
3084       ChromeTranslateClient::FromWebContents(embedder_web_contents_);
3085   if (!chrome_translate_client)
3086     return;
3087 
3088   translate::TranslateManager* manager =
3089       chrome_translate_client->GetTranslateManager();
3090   DCHECK(manager);
3091   manager->InitiateManualTranslation(true, true);
3092 }
3093 
ExecLanguageSettings(int event_flags)3094 void RenderViewContextMenu::ExecLanguageSettings(int event_flags) {
3095   WindowOpenDisposition disposition = ui::DispositionFromEventFlags(
3096       event_flags, WindowOpenDisposition::NEW_FOREGROUND_TAB);
3097   GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
3098   OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
3099 }
3100 
ExecProtocolHandlerSettings(int event_flags)3101 void RenderViewContextMenu::ExecProtocolHandlerSettings(int event_flags) {
3102   base::RecordAction(
3103       UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
3104   WindowOpenDisposition disposition = ui::DispositionFromEventFlags(
3105       event_flags, WindowOpenDisposition::NEW_FOREGROUND_TAB);
3106   GURL url = chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage);
3107   OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
3108 }
3109 
ExecPictureInPicture()3110 void RenderViewContextMenu::ExecPictureInPicture() {
3111   if (!base::FeatureList::IsEnabled(media::kPictureInPicture))
3112     return;
3113 
3114   bool picture_in_picture_active =
3115       IsCommandIdChecked(IDC_CONTENT_CONTEXT_PICTUREINPICTURE);
3116 
3117   if (picture_in_picture_active) {
3118     base::RecordAction(
3119         UserMetricsAction("MediaContextMenu_ExitPictureInPicture"));
3120   } else {
3121     base::RecordAction(
3122         UserMetricsAction("MediaContextMenu_EnterPictureInPicture"));
3123   }
3124 
3125   MediaPlayerActionAt(
3126       gfx::Point(params_.x, params_.y),
3127       blink::mojom::MediaPlayerAction(
3128           blink::mojom::MediaPlayerActionType::kPictureInPicture,
3129           !picture_in_picture_active));
3130 }
3131 
MediaPlayerActionAt(const gfx::Point & location,const blink::mojom::MediaPlayerAction & action)3132 void RenderViewContextMenu::MediaPlayerActionAt(
3133     const gfx::Point& location,
3134     const blink::mojom::MediaPlayerAction& action) {
3135   RenderFrameHost* frame_host = GetRenderFrameHost();
3136   if (frame_host)
3137     frame_host->ExecuteMediaPlayerActionAtLocation(location, action);
3138 }
3139 
PluginActionAt(const gfx::Point & location,blink::mojom::PluginActionType plugin_action)3140 void RenderViewContextMenu::PluginActionAt(
3141     const gfx::Point& location,
3142     blink::mojom::PluginActionType plugin_action) {
3143   source_web_contents_->GetMainFrame()
3144       ->GetRenderViewHost()
3145       ->ExecutePluginActionAtLocation(location, plugin_action);
3146 }
3147 
GetBrowser() const3148 Browser* RenderViewContextMenu::GetBrowser() const {
3149   return chrome::FindBrowserWithWebContents(embedder_web_contents_);
3150 }
3151