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

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

Issue 432003007: Separate chrome independent part from RVContextMenu (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: exclude android webview Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « components/renderer_context_menu/render_view_context_menu_base.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/render_view_context_menu_base.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "content/public/browser/render_frame_host.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/render_widget_host_view.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/common/menu_item.h"
18 #include "extensions/browser/extension_host.h"
19 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/view_type_utils.h"
21 #include "extensions/common/extension.h"
22 #include "third_party/WebKit/public/web/WebContextMenuData.h"
23
24 using blink::WebContextMenuData;
25 using blink::WebString;
26 using blink::WebURL;
27 using content::BrowserContext;
28 using content::OpenURLParams;
29 using content::RenderFrameHost;
30 using content::RenderViewHost;
31 using content::WebContents;
32
33 namespace {
34
35 // The (inclusive) range of command IDs reserved for content's custom menus.
36 int content_context_custom_first = -1;
37 int content_context_custom_last = -1;
38
39 bool IsCustomItemEnabledInternal(const std::vector<content::MenuItem>& items,
40 int id) {
41 DCHECK(RenderViewContextMenuBase::IsContentCustomCommandId(id));
42 for (size_t i = 0; i < items.size(); ++i) {
43 int action_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
44 items[i].action);
45 if (action_id == id)
46 return items[i].enabled;
47 if (items[i].type == content::MenuItem::SUBMENU) {
48 if (IsCustomItemEnabledInternal(items[i].submenu, id))
49 return true;
50 }
51 }
52 return false;
53 }
54
55 bool IsCustomItemCheckedInternal(const std::vector<content::MenuItem>& items,
56 int id) {
57 DCHECK(RenderViewContextMenuBase::IsContentCustomCommandId(id));
58 for (size_t i = 0; i < items.size(); ++i) {
59 int action_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
60 items[i].action);
61 if (action_id == id)
62 return items[i].checked;
63 if (items[i].type == content::MenuItem::SUBMENU) {
64 if (IsCustomItemCheckedInternal(items[i].submenu, id))
65 return true;
66 }
67 }
68 return false;
69 }
70
71 const size_t kMaxCustomMenuDepth = 5;
72 const size_t kMaxCustomMenuTotalItems = 1000;
73
74 void AddCustomItemsToMenu(const std::vector<content::MenuItem>& items,
75 size_t depth,
76 size_t* total_items,
77 ui::SimpleMenuModel::Delegate* delegate,
78 ui::SimpleMenuModel* menu_model) {
79 if (depth > kMaxCustomMenuDepth) {
80 LOG(ERROR) << "Custom menu too deeply nested.";
81 return;
82 }
83 for (size_t i = 0; i < items.size(); ++i) {
84 int command_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
85 items[i].action);
86 if (!RenderViewContextMenuBase::IsContentCustomCommandId(command_id)) {
87 LOG(ERROR) << "Custom menu action value out of range.";
88 return;
89 }
90 if (*total_items >= kMaxCustomMenuTotalItems) {
91 LOG(ERROR) << "Custom menu too large (too many items).";
92 return;
93 }
94 (*total_items)++;
95 switch (items[i].type) {
96 case content::MenuItem::OPTION:
97 menu_model->AddItem(
98 RenderViewContextMenuBase::ConvertToContentCustomCommandId(
99 items[i].action),
100 items[i].label);
101 break;
102 case content::MenuItem::CHECKABLE_OPTION:
103 menu_model->AddCheckItem(
104 RenderViewContextMenuBase::ConvertToContentCustomCommandId(
105 items[i].action),
106 items[i].label);
107 break;
108 case content::MenuItem::GROUP:
109 // TODO(viettrungluu): I don't know what this is supposed to do.
110 NOTREACHED();
111 break;
112 case content::MenuItem::SEPARATOR:
113 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
114 break;
115 case content::MenuItem::SUBMENU: {
116 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate);
117 AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate,
118 submenu);
119 menu_model->AddSubMenu(
120 RenderViewContextMenuBase::ConvertToContentCustomCommandId(
121 items[i].action),
122 items[i].label,
123 submenu);
124 break;
125 }
126 default:
127 NOTREACHED();
128 break;
129 }
130 }
131 }
132
133 } // namespace
134
135 // static
136 void RenderViewContextMenuBase::SetContentCustomCommandIdRange(
137 int first, int last) {
138 // The range is inclusive.
139 content_context_custom_first = first;
140 content_context_custom_last = last;
141 }
142
143 // static
144 const size_t RenderViewContextMenuBase::kMaxSelectionTextLength = 50;
145
146 // static
147 int RenderViewContextMenuBase::ConvertToContentCustomCommandId(int id) {
148 return content_context_custom_first + id;
149 }
150
151 // static
152 bool RenderViewContextMenuBase::IsContentCustomCommandId(int id) {
153 return id >= content_context_custom_first &&
154 id <= content_context_custom_last;
155 }
156
157 RenderViewContextMenuBase::RenderViewContextMenuBase(
158 content::RenderFrameHost* render_frame_host,
159 const content::ContextMenuParams& params)
160 : params_(params),
161 source_web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
162 browser_context_(source_web_contents_->GetBrowserContext()),
163 menu_model_(this),
164 command_executed_(false),
165 render_process_id_(render_frame_host->GetProcess()->GetID()),
166 render_frame_id_(render_frame_host->GetRoutingID()) {
167 }
168
169 RenderViewContextMenuBase::~RenderViewContextMenuBase() {
170 }
171
172 // Menu construction functions -------------------------------------------------
173
174 void RenderViewContextMenuBase::Init() {
175 // Command id range must have been already initializerd.
176 DCHECK_NE(-1, content_context_custom_first);
177 DCHECK_NE(-1, content_context_custom_last);
178
179 InitMenu();
180 if (toolkit_delegate_)
181 toolkit_delegate_->Init(&menu_model_);
182 }
183
184 void RenderViewContextMenuBase::Cancel() {
185 if (toolkit_delegate_)
186 toolkit_delegate_->Cancel();
187 }
188
189 void RenderViewContextMenuBase::InitMenu() {
190 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_CUSTOM)) {
191 AppendCustomItems();
192
193 const bool has_selection = !params_.selection_text.empty();
194 if (has_selection) {
195 // We will add more items if there's a selection, so add a separator.
196 // TODO(lazyboy): Clean up separator logic.
197 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
198 }
199 }
200 }
201
202 void RenderViewContextMenuBase::AddMenuItem(int command_id,
203 const base::string16& title) {
204 menu_model_.AddItem(command_id, title);
205 }
206
207 void RenderViewContextMenuBase::AddCheckItem(int command_id,
208 const base::string16& title) {
209 menu_model_.AddCheckItem(command_id, title);
210 }
211
212 void RenderViewContextMenuBase::AddSeparator() {
213 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
214 }
215
216 void RenderViewContextMenuBase::AddSubMenu(int command_id,
217 const base::string16& label,
218 ui::MenuModel* model) {
219 menu_model_.AddSubMenu(command_id, label, model);
220 }
221
222 void RenderViewContextMenuBase::UpdateMenuItem(int command_id,
223 bool enabled,
224 bool hidden,
225 const base::string16& label) {
226 if (toolkit_delegate_) {
227 toolkit_delegate_->UpdateMenuItem(command_id,
228 enabled,
229 hidden,
230 label);
231 }
232 }
233
234 RenderViewHost* RenderViewContextMenuBase::GetRenderViewHost() const {
235 return source_web_contents_->GetRenderViewHost();
236 }
237
238 WebContents* RenderViewContextMenuBase::GetWebContents() const {
239 return source_web_contents_;
240 }
241
242 BrowserContext* RenderViewContextMenuBase::GetBrowserContext() const {
243 return browser_context_;
244 }
245
246 bool RenderViewContextMenuBase::AppendCustomItems() {
247 size_t total_items = 0;
248 AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this,
249 &menu_model_);
250 return total_items > 0;
251 }
252
253 // Menu delegate functions -----------------------------------------------------
254
255 bool RenderViewContextMenuBase::IsCommandIdEnabled(int id) const {
256 // If this command is is added by one of our observers, we dispatch
257 // it to the observer.
258 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
259 RenderViewContextMenuObserver* observer;
260 while ((observer = it.GetNext()) != NULL) {
261 if (observer->IsCommandIdSupported(id))
262 return observer->IsCommandIdEnabled(id);
263 }
264
265 // Custom items.
266 if (IsContentCustomCommandId(id))
267 return IsCustomItemEnabled(id);
268
269 return false;
270 }
271
272 bool RenderViewContextMenuBase::IsCommandIdChecked(int id) const {
273 // If this command is is added by one of our observers, we dispatch it to the
274 // observer.
275 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
276 RenderViewContextMenuObserver* observer;
277 while ((observer = it.GetNext()) != NULL) {
278 if (observer->IsCommandIdSupported(id))
279 return observer->IsCommandIdChecked(id);
280 }
281
282 // Custom items.
283 if (IsContentCustomCommandId(id))
284 return IsCustomItemChecked(id);
285
286 return false;
287 }
288
289 void RenderViewContextMenuBase::ExecuteCommand(int id, int event_flags) {
290 command_executed_ = true;
291 RecordUsedItem(id);
292
293 // If this command is is added by one of our observers, we dispatch
294 // it to the observer.
295 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
296 RenderViewContextMenuObserver* observer;
297 while ((observer = it.GetNext()) != NULL) {
298 if (observer->IsCommandIdSupported(id))
299 return observer->ExecuteCommand(id);
300 }
301
302 // Process custom actions range.
303 if (IsContentCustomCommandId(id)) {
304 unsigned action = id - content_context_custom_first;
305 const content::CustomContextMenuContext& context = params_.custom_context;
306 #if defined(ENABLE_PLUGINS)
307 if (context.request_id && !context.is_pepper_menu)
308 HandleAuthorizeAllPlugins();
309 #endif
310 source_web_contents_->ExecuteCustomContextMenuCommand(action, context);
311 return;
312 }
313 command_executed_ = false;
314 }
315
316 void RenderViewContextMenuBase::MenuWillShow(ui::SimpleMenuModel* source) {
317 for (int i = 0; i < source->GetItemCount(); ++i) {
318 if (source->IsVisibleAt(i) &&
319 source->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR) {
320 RecordShownItem(source->GetCommandIdAt(i));
321 }
322 }
323
324 // Ignore notifications from submenus.
325 if (source != &menu_model_)
326 return;
327
328 content::RenderWidgetHostView* view =
329 source_web_contents_->GetRenderWidgetHostView();
330 if (view)
331 view->SetShowingContextMenu(true);
332
333 NotifyMenuShown();
334 }
335
336 void RenderViewContextMenuBase::MenuClosed(ui::SimpleMenuModel* source) {
337 // Ignore notifications from submenus.
338 if (source != &menu_model_)
339 return;
340
341 content::RenderWidgetHostView* view =
342 source_web_contents_->GetRenderWidgetHostView();
343 if (view)
344 view->SetShowingContextMenu(false);
345 source_web_contents_->NotifyContextMenuClosed(params_.custom_context);
346
347 if (!command_executed_) {
348 FOR_EACH_OBSERVER(RenderViewContextMenuObserver,
349 observers_,
350 OnMenuCancel());
351 }
352 }
353
354 RenderFrameHost* RenderViewContextMenuBase::GetRenderFrameHost() {
355 return RenderFrameHost::FromID(render_process_id_, render_frame_id_);
356 }
357
358 // Controller functions --------------------------------------------------------
359
360 void RenderViewContextMenuBase::OpenURL(
361 const GURL& url, const GURL& referring_url,
362 WindowOpenDisposition disposition,
363 content::PageTransition transition) {
364 content::Referrer referrer = content::Referrer::SanitizeForRequest(
365 url,
366 content::Referrer(referring_url.GetAsReferrer(),
367 params_.referrer_policy));
368
369 if (params_.link_url == url && disposition != OFF_THE_RECORD)
370 params_.custom_context.link_followed = url;
371
372 WebContents* new_contents = source_web_contents_->OpenURL(OpenURLParams(
373 url, referrer, disposition, transition, false));
374 if (!new_contents)
375 return;
376
377 NotifyURLOpened(url, new_contents);
378 }
379
380 bool RenderViewContextMenuBase::IsCustomItemChecked(int id) const {
381 return IsCustomItemCheckedInternal(params_.custom_items, id);
382 }
383
384 bool RenderViewContextMenuBase::IsCustomItemEnabled(int id) const {
385 return IsCustomItemEnabledInternal(params_.custom_items, id);
386 }
387
OLDNEW
« no previous file with comments | « components/renderer_context_menu/render_view_context_menu_base.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698