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

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

Issue 432003007: Separate chrome independent part from RVContextMenu (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 range of command IDs reserved for content's custom menus.
lazyboy 2014/08/01 07:59:34 The (inclusive) range of ...
36 // TODO(oshima): These values will be injected by embedders.
lazyboy 2014/08/01 07:59:34 This TODO has been taken care of?
oshima 2014/08/01 10:38:45 Done. Thanks
37 int content_context_custom_first = -1;
lazyboy 2014/08/01 07:59:34 These should also have g_ prefix as they are globa
oshima 2014/08/01 10:38:44 same here. they're file scoped, not global.
38 int content_context_custom_last = -1;
39
40 bool IsCustomItemEnabledInternal(const std::vector<content::MenuItem>& items,
41 int id) {
42 DCHECK(RenderViewContextMenuBase::IsContentCustomCommandId(id));
43 for (size_t i = 0; i < items.size(); ++i) {
44 int action_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
45 items[i].action);
46 if (action_id == id)
47 return items[i].enabled;
48 if (items[i].type == content::MenuItem::SUBMENU) {
49 if (IsCustomItemEnabledInternal(items[i].submenu, id))
50 return true;
51 }
52 }
53 return false;
54 }
55
56 bool IsCustomItemCheckedInternal(const std::vector<content::MenuItem>& items,
57 int id) {
58 DCHECK(RenderViewContextMenuBase::IsContentCustomCommandId(id));
59 for (size_t i = 0; i < items.size(); ++i) {
60 int action_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
61 items[i].action);
62 if (action_id == id)
63 return items[i].checked;
64 if (items[i].type == content::MenuItem::SUBMENU) {
65 if (IsCustomItemCheckedInternal(items[i].submenu, id))
66 return true;
67 }
68 }
69 return false;
70 }
71
72 const size_t kMaxCustomMenuDepth = 5;
73 const size_t kMaxCustomMenuTotalItems = 1000;
74
75 void AddCustomItemsToMenu(const std::vector<content::MenuItem>& items,
76 size_t depth,
77 size_t* total_items,
78 ui::SimpleMenuModel::Delegate* delegate,
79 ui::SimpleMenuModel* menu_model) {
80 if (depth > kMaxCustomMenuDepth) {
81 LOG(ERROR) << "Custom menu too deeply nested.";
82 return;
83 }
84 for (size_t i = 0; i < items.size(); ++i) {
85 int command_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
86 items[i].action);
87 if (!RenderViewContextMenuBase::IsContentCustomCommandId(command_id)) {
88 LOG(ERROR) << "Custom menu action value out of range.";
89 return;
90 }
91 if (*total_items >= kMaxCustomMenuTotalItems) {
92 LOG(ERROR) << "Custom menu too large (too many items).";
93 return;
94 }
95 (*total_items)++;
96 switch (items[i].type) {
97 case content::MenuItem::OPTION:
98 menu_model->AddItem(
99 RenderViewContextMenuBase::ConvertToContentCustomCommandId(
100 items[i].action),
101 items[i].label);
102 break;
103 case content::MenuItem::CHECKABLE_OPTION:
104 menu_model->AddCheckItem(
105 RenderViewContextMenuBase::ConvertToContentCustomCommandId(
106 items[i].action),
107 items[i].label);
108 break;
109 case content::MenuItem::GROUP:
110 // TODO(viettrungluu): I don't know what this is supposed to do.
111 NOTREACHED();
112 break;
113 case content::MenuItem::SEPARATOR:
114 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
115 break;
116 case content::MenuItem::SUBMENU: {
117 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate);
118 AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate,
119 submenu);
120 menu_model->AddSubMenu(
121 RenderViewContextMenuBase::ConvertToContentCustomCommandId(
122 items[i].action),
123 items[i].label,
124 submenu);
125 break;
126 }
127 default:
128 NOTREACHED();
129 break;
130 }
131 }
132 }
133
134 } // namespace
135
136 // static
137 void RenderViewContextMenuBase::SetContentCustomCommandIdRange(
lazyboy 2014/08/01 07:59:34 Add a note that this range is inclusive.
oshima 2014/08/01 10:38:44 Done.
138 int first, int last) {
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(referring_url.GetAsReferrer(),
365 params_.referrer_policy);
366
367 if (params_.link_url == url && disposition != OFF_THE_RECORD)
368 params_.custom_context.link_followed = url;
369
370 WebContents* new_contents = source_web_contents_->OpenURL(OpenURLParams(
371 url, referrer, disposition, transition, false));
372 if (!new_contents)
373 return;
374
375 NotifyURLOpened(url, new_contents);
376 }
377
378 bool RenderViewContextMenuBase::IsCustomItemChecked(int id) const {
379 return IsCustomItemCheckedInternal(params_.custom_items, id);
380 }
381
382 bool RenderViewContextMenuBase::IsCustomItemEnabled(int id) const {
383 return IsCustomItemEnabledInternal(params_.custom_items, id);
384 }
385
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698