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 "components/renderer_context_menu/context_menu_content_type.h"
6 
7 #include "base/bind.h"
8 #include "content/public/browser/web_contents.h"
9 #include "content/public/common/url_constants.h"
10 #include "printing/buildflags/buildflags.h"
11 #include "third_party/blink/public/common/context_menu_data/input_field_type.h"
12 
13 using blink::ContextMenuDataMediaType;
14 using content::WebContents;
15 
16 namespace {
17 
IsDevToolsURL(const GURL & url)18 bool IsDevToolsURL(const GURL& url) {
19   return url.SchemeIs(content::kChromeDevToolsScheme);
20 }
21 
22 }  // namespace
23 
ContextMenuContentType(content::WebContents * web_contents,const content::ContextMenuParams & params,bool supports_custom_items)24 ContextMenuContentType::ContextMenuContentType(
25     content::WebContents* web_contents,
26     const content::ContextMenuParams& params,
27     bool supports_custom_items)
28     : params_(params),
29       source_web_contents_(web_contents),
30       supports_custom_items_(supports_custom_items) {}
31 
~ContextMenuContentType()32 ContextMenuContentType::~ContextMenuContentType() {
33 }
34 
SupportsGroup(int group)35 bool ContextMenuContentType::SupportsGroup(int group) {
36   const bool has_selection = !params_.selection_text.empty();
37 
38   if (supports_custom_items_ && !params_.custom_items.empty()) {
39     if (group == ITEM_GROUP_CUSTOM)
40       return true;
41 
42     if (!has_selection) {
43       // For menus with custom items, if there is no selection, we do not
44       // add items other than developer items. And for Pepper menu, don't even
45       // add developer items.
46       if (!params_.custom_context.is_pepper_menu)
47         return group == ITEM_GROUP_DEVELOPER;
48 
49       return false;
50     }
51 
52     // If there's a selection when there are custom items, fall through to
53     // adding the normal ones after the custom ones.
54   }
55 
56   if (IsDevToolsURL(params_.page_url)) {
57     // DevTools mostly provides custom context menu and uses
58     // only the following default options.
59     if (group != ITEM_GROUP_CUSTOM && group != ITEM_GROUP_EDITABLE &&
60         group != ITEM_GROUP_COPY && group != ITEM_GROUP_DEVELOPER &&
61         group != ITEM_GROUP_SEARCH_PROVIDER) {
62       return false;
63     }
64   }
65 
66   return SupportsGroupInternal(group);
67 }
68 
SupportsGroupInternal(int group)69 bool ContextMenuContentType::SupportsGroupInternal(int group) {
70   const bool has_link = !params_.unfiltered_link_url.is_empty();
71   const bool has_selection = !params_.selection_text.empty();
72   const bool is_password = params_.input_field_type ==
73                            blink::ContextMenuDataInputFieldType::kPassword;
74 
75   switch (group) {
76     case ITEM_GROUP_CUSTOM:
77       return supports_custom_items_ && !params_.custom_items.empty();
78 
79     case ITEM_GROUP_PAGE: {
80       bool is_candidate =
81           params_.media_type == ContextMenuDataMediaType::kNone && !has_link &&
82           !params_.is_editable && !has_selection;
83 
84       if (!is_candidate && params_.page_url.is_empty())
85         DCHECK(params_.frame_url.is_empty());
86 
87       return is_candidate && !params_.page_url.is_empty();
88     }
89 
90     case ITEM_GROUP_FRAME: {
91       bool page_group_supported = SupportsGroupInternal(ITEM_GROUP_PAGE);
92       return page_group_supported && !params_.frame_url.is_empty();
93     }
94 
95     case ITEM_GROUP_LINK:
96       return has_link;
97 
98     case ITEM_GROUP_SMART_SELECTION:
99       return has_selection && !has_link;
100 
101     case ITEM_GROUP_MEDIA_IMAGE:
102       return params_.media_type == ContextMenuDataMediaType::kImage;
103 
104     case ITEM_GROUP_SEARCHWEBFORIMAGE:
105       // Image menu items imply search web for image item.
106       return SupportsGroupInternal(ITEM_GROUP_MEDIA_IMAGE);
107 
108     case ITEM_GROUP_MEDIA_VIDEO:
109       return params_.media_type == ContextMenuDataMediaType::kVideo;
110 
111     case ITEM_GROUP_MEDIA_AUDIO:
112       return params_.media_type == ContextMenuDataMediaType::kAudio;
113 
114     case ITEM_GROUP_MEDIA_CANVAS:
115       return params_.media_type == ContextMenuDataMediaType::kCanvas;
116 
117     case ITEM_GROUP_MEDIA_PLUGIN:
118       return params_.media_type == ContextMenuDataMediaType::kPlugin;
119 
120     case ITEM_GROUP_MEDIA_FILE:
121       return params_.media_type == ContextMenuDataMediaType::kFile;
122 
123     case ITEM_GROUP_EDITABLE:
124       return params_.is_editable;
125 
126     case ITEM_GROUP_COPY:
127       return !params_.is_editable && has_selection;
128 
129     case ITEM_GROUP_SEARCH_PROVIDER:
130       return has_selection && !is_password;
131 
132     case ITEM_GROUP_PRINT: {
133       // Image menu items also imply print items.
134       return has_selection || SupportsGroupInternal(ITEM_GROUP_MEDIA_IMAGE);
135     }
136 
137     case ITEM_GROUP_ALL_EXTENSION:
138       return true;
139 
140     case ITEM_GROUP_CURRENT_EXTENSION:
141       return false;
142 
143     case ITEM_GROUP_DEVELOPER:
144       return true;
145 
146     case ITEM_GROUP_DEVTOOLS_UNPACKED_EXT:
147       return false;
148 
149     case ITEM_GROUP_PRINT_PREVIEW:
150 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
151       return true;
152 #else
153       return false;
154 #endif
155 
156     case ITEM_GROUP_PASSWORD:
157       return params_.input_field_type ==
158              blink::ContextMenuDataInputFieldType::kPassword;
159 
160     default:
161       NOTREACHED();
162       return false;
163   }
164 }
165