OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <algorithm> | 5 #include <algorithm> |
6 #include <set> | 6 #include <set> |
7 | 7 |
8 #include "chrome/browser/tab_contents/render_view_context_menu.h" | 8 #include "chrome/browser/tab_contents/render_view_context_menu.h" |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 #include "chrome/browser/page_info_window.h" | 29 #include "chrome/browser/page_info_window.h" |
30 #include "chrome/browser/platform_util.h" | 30 #include "chrome/browser/platform_util.h" |
31 #include "chrome/browser/prefs/pref_member.h" | 31 #include "chrome/browser/prefs/pref_member.h" |
32 #include "chrome/browser/prefs/pref_service.h" | 32 #include "chrome/browser/prefs/pref_service.h" |
33 #include "chrome/browser/printing/print_preview_tab_controller.h" | 33 #include "chrome/browser/printing/print_preview_tab_controller.h" |
34 #include "chrome/browser/profiles/profile.h" | 34 #include "chrome/browser/profiles/profile.h" |
35 #include "chrome/browser/search_engines/template_url.h" | 35 #include "chrome/browser/search_engines/template_url.h" |
36 #include "chrome/browser/search_engines/template_url_model.h" | 36 #include "chrome/browser/search_engines/template_url_model.h" |
37 #include "chrome/browser/spellcheck_host.h" | 37 #include "chrome/browser/spellcheck_host.h" |
38 #include "chrome/browser/spellchecker_platform_engine.h" | 38 #include "chrome/browser/spellchecker_platform_engine.h" |
| 39 #include "chrome/browser/tab_contents/context_menu_utils.h" |
39 #include "chrome/browser/translate/translate_prefs.h" | 40 #include "chrome/browser/translate/translate_prefs.h" |
40 #include "chrome/browser/translate/translate_manager.h" | 41 #include "chrome/browser/translate/translate_manager.h" |
41 #include "chrome/common/chrome_constants.h" | 42 #include "chrome/common/chrome_constants.h" |
42 #include "chrome/common/chrome_switches.h" | 43 #include "chrome/common/chrome_switches.h" |
43 #include "chrome/common/content_restriction.h" | 44 #include "chrome/common/content_restriction.h" |
44 #include "chrome/common/pref_names.h" | 45 #include "chrome/common/pref_names.h" |
45 #include "chrome/common/print_messages.h" | 46 #include "chrome/common/print_messages.h" |
46 #include "chrome/common/url_constants.h" | 47 #include "chrome/common/url_constants.h" |
47 #include "content/browser/child_process_security_policy.h" | 48 #include "content/browser/child_process_security_policy.h" |
48 #include "content/browser/renderer_host/render_view_host.h" | 49 #include "content/browser/renderer_host/render_view_host.h" |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 RenderViewContextMenu::~RenderViewContextMenu() { | 190 RenderViewContextMenu::~RenderViewContextMenu() { |
190 } | 191 } |
191 | 192 |
192 // Menu construction functions ------------------------------------------------- | 193 // Menu construction functions ------------------------------------------------- |
193 | 194 |
194 void RenderViewContextMenu::Init() { | 195 void RenderViewContextMenu::Init() { |
195 InitMenu(); | 196 InitMenu(); |
196 PlatformInit(); | 197 PlatformInit(); |
197 } | 198 } |
198 | 199 |
199 static bool ExtensionContextMatch(const ContextMenuParams& params, | |
200 ExtensionMenuItem::ContextList contexts) { | |
201 bool has_link = !params.link_url.is_empty(); | |
202 bool has_selection = !params.selection_text.empty(); | |
203 bool in_frame = !params.frame_url.is_empty(); | |
204 | |
205 if (contexts.Contains(ExtensionMenuItem::ALL) || | |
206 (has_selection && contexts.Contains(ExtensionMenuItem::SELECTION)) || | |
207 (has_link && contexts.Contains(ExtensionMenuItem::LINK)) || | |
208 (params.is_editable && contexts.Contains(ExtensionMenuItem::EDITABLE)) || | |
209 (in_frame && contexts.Contains(ExtensionMenuItem::FRAME))) { | |
210 return true; | |
211 } | |
212 | |
213 switch (params.media_type) { | |
214 case WebContextMenuData::MediaTypeImage: | |
215 return contexts.Contains(ExtensionMenuItem::IMAGE); | |
216 | |
217 case WebContextMenuData::MediaTypeVideo: | |
218 return contexts.Contains(ExtensionMenuItem::VIDEO); | |
219 | |
220 case WebContextMenuData::MediaTypeAudio: | |
221 return contexts.Contains(ExtensionMenuItem::AUDIO); | |
222 | |
223 default: | |
224 break; | |
225 } | |
226 | |
227 // PAGE is the least specific context, so we only examine that if none of the | |
228 // other contexts apply (except for FRAME, which is included in PAGE for | |
229 // backwards compatibility). | |
230 if (!has_link && !has_selection && !params.is_editable && | |
231 params.media_type == WebContextMenuData::MediaTypeNone && | |
232 contexts.Contains(ExtensionMenuItem::PAGE)) | |
233 return true; | |
234 | |
235 return false; | |
236 } | |
237 | |
238 static bool ExtensionPatternMatch(const ExtensionExtent& patterns, | |
239 const GURL& url) { | |
240 // No patterns means no restriction, so that implicitly matches. | |
241 if (patterns.is_empty()) | |
242 return true; | |
243 return patterns.ContainsURL(url); | |
244 } | |
245 | |
246 static const GURL& GetDocumentURL(const ContextMenuParams& params) { | |
247 return params.frame_url.is_empty() ? params.page_url : params.frame_url; | |
248 } | |
249 | |
250 // Given a list of items, returns the ones that match given the contents | |
251 // of |params| and the profile. | |
252 static ExtensionMenuItem::List GetRelevantExtensionItems( | |
253 const ExtensionMenuItem::List& items, | |
254 const ContextMenuParams& params, | |
255 Profile* profile, | |
256 bool can_cross_incognito) { | |
257 ExtensionMenuItem::List result; | |
258 for (ExtensionMenuItem::List::const_iterator i = items.begin(); | |
259 i != items.end(); ++i) { | |
260 const ExtensionMenuItem* item = *i; | |
261 | |
262 if (!ExtensionContextMatch(params, item->contexts())) | |
263 continue; | |
264 | |
265 const GURL& document_url = GetDocumentURL(params); | |
266 if (!ExtensionPatternMatch(item->document_url_patterns(), document_url)) | |
267 continue; | |
268 | |
269 const GURL& target_url = | |
270 params.src_url.is_empty() ? params.link_url : params.src_url; | |
271 if (!ExtensionPatternMatch(item->target_url_patterns(), target_url)) | |
272 continue; | |
273 | |
274 if (item->id().profile == profile || can_cross_incognito) | |
275 result.push_back(*i); | |
276 } | |
277 return result; | |
278 } | |
279 | |
280 void RenderViewContextMenu::AppendExtensionItems( | 200 void RenderViewContextMenu::AppendExtensionItems( |
281 const std::string& extension_id, int* index) { | 201 const std::string& extension_id, int* index) { |
282 ExtensionService* service = profile_->GetExtensionService(); | 202 ExtensionService* service = profile_->GetExtensionService(); |
283 ExtensionMenuManager* manager = service->menu_manager(); | 203 ExtensionMenuManager* manager = service->menu_manager(); |
284 const Extension* extension = service->GetExtensionById(extension_id, false); | 204 const Extension* extension = service->GetExtensionById(extension_id, false); |
285 DCHECK_GE(*index, 0); | 205 DCHECK_GE(*index, 0); |
286 int max_index = | 206 int max_index = |
287 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; | 207 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; |
288 if (!extension || *index >= max_index) | 208 if (!extension || *index >= max_index) |
289 return; | 209 return; |
290 | 210 |
291 // Find matching items. | 211 // Find matching items. |
292 const ExtensionMenuItem::List* all_items = manager->MenuItems(extension_id); | 212 const ExtensionMenuItem::List* all_items = manager->MenuItems(extension_id); |
293 if (!all_items || all_items->empty()) | 213 if (!all_items || all_items->empty()) |
294 return; | 214 return; |
295 bool can_cross_incognito = service->CanCrossIncognito(extension); | 215 bool can_cross_incognito = service->CanCrossIncognito(extension); |
296 ExtensionMenuItem::List items = | 216 ExtensionMenuItem::List items = |
297 GetRelevantExtensionItems(*all_items, params_, profile_, | 217 ContextMenuUtils::GetRelevantExtensionItems(*all_items, |
298 can_cross_incognito); | 218 params_, |
| 219 profile_, |
| 220 can_cross_incognito); |
299 if (items.empty()) | 221 if (items.empty()) |
300 return; | 222 return; |
301 | 223 |
302 // If this is the first extension-provided menu item, add a separator. | 224 // If this is the first extension-provided menu item, add a separator. |
303 if (*index == 0) | 225 if (*index == 0) |
304 menu_model_.AddSeparator(); | 226 menu_model_.AddSeparator(); |
305 | 227 |
306 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; | 228 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; |
307 | 229 |
308 // Extensions are only allowed one top-level slot (and it can't be a radio or | 230 // Extensions are only allowed one top-level slot (and it can't be a radio or |
309 // checkbox item because we are going to put the extension icon next to it). | 231 // checkbox item because we are going to put the extension icon next to it). |
310 // If they have more than that, we automatically push them into a submenu. | 232 // If they have more than that, we automatically push them into a submenu. |
311 string16 title; | 233 string16 title; |
312 ExtensionMenuItem::List submenu_items; | 234 ExtensionMenuItem::List submenu_items; |
313 if (items.size() > 1 || items[0]->type() != ExtensionMenuItem::NORMAL) { | 235 if (items.size() > 1 || items[0]->type() != ExtensionMenuItem::NORMAL) { |
314 title = UTF8ToUTF16(extension->name()); | 236 title = UTF8ToUTF16(extension->name()); |
315 submenu_items = items; | 237 submenu_items = items; |
316 } else { | 238 } else { |
317 ExtensionMenuItem* item = items[0]; | 239 ExtensionMenuItem* item = items[0]; |
318 extension_item_map_[menu_id] = item->id(); | 240 extension_item_map_[menu_id] = item->id(); |
319 title = item->TitleWithReplacement(PrintableSelectionText(), | 241 title = item->TitleWithReplacement(PrintableSelectionText(), |
320 kMaxExtensionItemTitleLength); | 242 kMaxExtensionItemTitleLength); |
321 submenu_items = GetRelevantExtensionItems(item->children(), params_, | 243 submenu_items = ContextMenuUtils::GetRelevantExtensionItems( |
322 profile_, can_cross_incognito); | 244 item->children(), params_, profile_, can_cross_incognito); |
323 } | 245 } |
324 | 246 |
325 // Now add our item(s) to the menu_model_. | 247 // Now add our item(s) to the menu_model_. |
326 if (submenu_items.empty()) { | 248 if (submenu_items.empty()) { |
327 menu_model_.AddItem(menu_id, title); | 249 menu_model_.AddItem(menu_id, title); |
328 } else { | 250 } else { |
329 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); | 251 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); |
330 extension_menu_models_.push_back(submenu); | 252 extension_menu_models_.push_back(submenu); |
331 menu_model_.AddSubMenu(menu_id, title, submenu); | 253 menu_model_.AddSubMenu(menu_id, title, submenu); |
332 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu, | 254 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu, |
(...skipping 24 matching lines...) Expand all Loading... |
357 } | 279 } |
358 | 280 |
359 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; | 281 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; |
360 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) | 282 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) |
361 return; | 283 return; |
362 extension_item_map_[menu_id] = item->id(); | 284 extension_item_map_[menu_id] = item->id(); |
363 string16 title = item->TitleWithReplacement(selection_text, | 285 string16 title = item->TitleWithReplacement(selection_text, |
364 kMaxExtensionItemTitleLength); | 286 kMaxExtensionItemTitleLength); |
365 if (item->type() == ExtensionMenuItem::NORMAL) { | 287 if (item->type() == ExtensionMenuItem::NORMAL) { |
366 ExtensionMenuItem::List children = | 288 ExtensionMenuItem::List children = |
367 GetRelevantExtensionItems(item->children(), params_, | 289 ContextMenuUtils::GetRelevantExtensionItems( |
368 profile_, can_cross_incognito); | 290 item->children(), params_, profile_, can_cross_incognito); |
369 if (children.empty()) { | 291 if (children.empty()) { |
370 menu_model->AddItem(menu_id, title); | 292 menu_model->AddItem(menu_id, title); |
371 } else { | 293 } else { |
372 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); | 294 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); |
373 extension_menu_models_.push_back(submenu); | 295 extension_menu_models_.push_back(submenu); |
374 menu_model->AddSubMenu(menu_id, title, submenu); | 296 menu_model->AddSubMenu(menu_id, title, submenu); |
375 RecursivelyAppendExtensionItems(children, can_cross_incognito, | 297 RecursivelyAppendExtensionItems(children, can_cross_incognito, |
376 submenu, index); | 298 submenu, index); |
377 } | 299 } |
378 } else if (item->type() == ExtensionMenuItem::CHECKBOX) { | 300 } else if (item->type() == ExtensionMenuItem::CHECKBOX) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 | 332 |
411 menu_model_.SetIcon(index, icon); | 333 menu_model_.SetIcon(index, icon); |
412 } | 334 } |
413 | 335 |
414 void RenderViewContextMenu::AppendAllExtensionItems() { | 336 void RenderViewContextMenu::AppendAllExtensionItems() { |
415 extension_item_map_.clear(); | 337 extension_item_map_.clear(); |
416 ExtensionService* service = profile_->GetExtensionService(); | 338 ExtensionService* service = profile_->GetExtensionService(); |
417 if (!service) | 339 if (!service) |
418 return; // In unit-tests, we may not have an ExtensionService. | 340 return; // In unit-tests, we may not have an ExtensionService. |
419 ExtensionMenuManager* menu_manager = service->menu_manager(); | 341 ExtensionMenuManager* menu_manager = service->menu_manager(); |
420 const GURL& document_url = GetDocumentURL(params_); | 342 const GURL& document_url = ContextMenuUtils::GetDocumentURL(params_); |
421 if (!menu_manager->HasAllowedScheme(document_url)) | 343 if (!menu_manager->HasAllowedScheme(document_url)) |
422 return; | 344 return; |
423 | 345 |
424 // Get a list of extension id's that have context menu items, and sort it by | 346 // Get a list of extension id's that have context menu items, and sort it by |
425 // the extension's name. | 347 // the extension's name. |
426 std::set<std::string> ids = menu_manager->ExtensionIds(); | 348 std::set<std::string> ids = menu_manager->ExtensionIds(); |
427 std::vector<std::pair<std::string, std::string> > sorted_ids; | 349 std::vector<std::pair<std::string, std::string> > sorted_ids; |
428 for (std::set<std::string>::iterator i = ids.begin(); i != ids.end(); ++i) { | 350 for (std::set<std::string>::iterator i = ids.begin(); i != ids.end(); ++i) { |
429 const Extension* extension = service->GetExtensionById(*i, false); | 351 const Extension* extension = service->GetExtensionById(*i, false); |
430 if (extension) | 352 if (extension) |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 break; | 421 break; |
500 case WebContextMenuData::MediaTypeVideo: | 422 case WebContextMenuData::MediaTypeVideo: |
501 AppendVideoItems(); | 423 AppendVideoItems(); |
502 break; | 424 break; |
503 case WebContextMenuData::MediaTypeAudio: | 425 case WebContextMenuData::MediaTypeAudio: |
504 AppendAudioItems(); | 426 AppendAudioItems(); |
505 break; | 427 break; |
506 case WebContextMenuData::MediaTypePlugin: | 428 case WebContextMenuData::MediaTypePlugin: |
507 AppendPluginItems(); | 429 AppendPluginItems(); |
508 break; | 430 break; |
509 #ifdef WEBCONTEXT_MEDIATYPEFILE_DEFINED | |
510 case WebContextMenuData::MediaTypeFile: | 431 case WebContextMenuData::MediaTypeFile: |
| 432 AppendFileItems(); |
511 break; | 433 break; |
512 #endif | |
513 } | 434 } |
514 | 435 |
515 if (params_.is_editable) | 436 if (params_.is_editable) |
516 AppendEditableItems(); | 437 AppendEditableItems(); |
517 else if (has_selection) | 438 else if (has_selection) |
518 AppendCopyItem(); | 439 AppendCopyItem(); |
519 | 440 |
520 if (has_selection) | 441 if (has_selection) |
521 AppendSearchProvider(); | 442 AppendSearchProvider(); |
522 | 443 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 AppendMediaItems(); | 513 AppendMediaItems(); |
593 menu_model_.AddSeparator(); | 514 menu_model_.AddSeparator(); |
594 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, | 515 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, |
595 IDS_CONTENT_CONTEXT_SAVEVIDEOAS); | 516 IDS_CONTENT_CONTEXT_SAVEVIDEOAS); |
596 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION, | 517 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION, |
597 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION); | 518 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION); |
598 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB, | 519 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB, |
599 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB); | 520 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB); |
600 } | 521 } |
601 | 522 |
| 523 void RenderViewContextMenu::AppendFileItems() { |
| 524 // TODO(zelidrag): Add file context operations here (i.e. cut, copy, paste...) |
| 525 } |
| 526 |
602 void RenderViewContextMenu::AppendMediaItems() { | 527 void RenderViewContextMenu::AppendMediaItems() { |
603 int media_flags = params_.media_flags; | 528 int media_flags = params_.media_flags; |
604 | 529 |
605 menu_model_.AddItemWithStringId( | 530 menu_model_.AddItemWithStringId( |
606 IDC_CONTENT_CONTEXT_PLAYPAUSE, | 531 IDC_CONTENT_CONTEXT_PLAYPAUSE, |
607 media_flags & WebContextMenuData::MediaPaused ? | 532 media_flags & WebContextMenuData::MediaPaused ? |
608 IDS_CONTENT_CONTEXT_PLAY : | 533 IDS_CONTENT_CONTEXT_PLAY : |
609 IDS_CONTENT_CONTEXT_PAUSE); | 534 IDS_CONTENT_CONTEXT_PAUSE); |
610 | 535 |
611 menu_model_.AddItemWithStringId( | 536 menu_model_.AddItemWithStringId( |
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1545 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), | 1470 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), |
1546 g_browser_process->clipboard()); | 1471 g_browser_process->clipboard()); |
1547 } | 1472 } |
1548 | 1473 |
1549 void RenderViewContextMenu::MediaPlayerActionAt( | 1474 void RenderViewContextMenu::MediaPlayerActionAt( |
1550 const gfx::Point& location, | 1475 const gfx::Point& location, |
1551 const WebMediaPlayerAction& action) { | 1476 const WebMediaPlayerAction& action) { |
1552 source_tab_contents_->render_view_host()->MediaPlayerActionAt( | 1477 source_tab_contents_->render_view_host()->MediaPlayerActionAt( |
1553 location, action); | 1478 location, action); |
1554 } | 1479 } |
OLD | NEW |