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 | |
204 if (contexts.Contains(ExtensionMenuItem::ALL) || | |
205 (has_selection && contexts.Contains(ExtensionMenuItem::SELECTION)) || | |
206 (has_link && contexts.Contains(ExtensionMenuItem::LINK)) || | |
207 (params.is_editable && contexts.Contains(ExtensionMenuItem::EDITABLE))) { | |
208 return true; | |
209 } | |
210 | |
211 switch (params.media_type) { | |
212 case WebContextMenuData::MediaTypeImage: | |
213 return contexts.Contains(ExtensionMenuItem::IMAGE); | |
214 | |
215 case WebContextMenuData::MediaTypeVideo: | |
216 return contexts.Contains(ExtensionMenuItem::VIDEO); | |
217 | |
218 case WebContextMenuData::MediaTypeAudio: | |
219 return contexts.Contains(ExtensionMenuItem::AUDIO); | |
220 | |
221 default: | |
222 break; | |
223 } | |
224 | |
225 // PAGE is the least specific context, so we only examine that if none of the | |
226 // other contexts apply. | |
227 if (!has_link && !has_selection && !params.is_editable && | |
228 params.media_type == WebContextMenuData::MediaTypeNone && | |
229 contexts.Contains(ExtensionMenuItem::PAGE)) | |
230 return true; | |
231 | |
232 return false; | |
233 } | |
234 | |
235 static bool ExtensionPatternMatch(const ExtensionExtent& patterns, | |
236 const GURL& url) { | |
237 // No patterns means no restriction, so that implicitly matches. | |
238 if (patterns.is_empty()) | |
239 return true; | |
240 return patterns.ContainsURL(url); | |
241 } | |
242 | |
243 static const GURL& GetDocumentURL(const ContextMenuParams& params) { | |
244 return params.frame_url.is_empty() ? params.page_url : params.frame_url; | |
245 } | |
246 | |
247 // Given a list of items, returns the ones that match given the contents | |
248 // of |params| and the profile. | |
249 static ExtensionMenuItem::List GetRelevantExtensionItems( | |
250 const ExtensionMenuItem::List& items, | |
251 const ContextMenuParams& params, | |
252 Profile* profile, | |
253 bool can_cross_incognito) { | |
254 ExtensionMenuItem::List result; | |
255 for (ExtensionMenuItem::List::const_iterator i = items.begin(); | |
256 i != items.end(); ++i) { | |
257 const ExtensionMenuItem* item = *i; | |
258 | |
259 if (!ExtensionContextMatch(params, item->contexts())) | |
260 continue; | |
261 | |
262 const GURL& document_url = GetDocumentURL(params); | |
263 if (!ExtensionPatternMatch(item->document_url_patterns(), document_url)) | |
264 continue; | |
265 | |
266 const GURL& target_url = | |
267 params.src_url.is_empty() ? params.link_url : params.src_url; | |
268 if (!ExtensionPatternMatch(item->target_url_patterns(), target_url)) | |
269 continue; | |
270 | |
271 if (item->id().profile == profile || can_cross_incognito) | |
272 result.push_back(*i); | |
273 } | |
274 return result; | |
275 } | |
276 | |
277 void RenderViewContextMenu::AppendExtensionItems( | 200 void RenderViewContextMenu::AppendExtensionItems( |
278 const std::string& extension_id, int* index) { | 201 const std::string& extension_id, int* index) { |
279 ExtensionService* service = profile_->GetExtensionService(); | 202 ExtensionService* service = profile_->GetExtensionService(); |
280 ExtensionMenuManager* manager = service->menu_manager(); | 203 ExtensionMenuManager* manager = service->menu_manager(); |
281 const Extension* extension = service->GetExtensionById(extension_id, false); | 204 const Extension* extension = service->GetExtensionById(extension_id, false); |
282 DCHECK_GE(*index, 0); | 205 DCHECK_GE(*index, 0); |
283 int max_index = | 206 int max_index = |
284 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; | 207 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; |
285 if (!extension || *index >= max_index) | 208 if (!extension || *index >= max_index) |
286 return; | 209 return; |
287 | 210 |
288 // Find matching items. | 211 // Find matching items. |
289 const ExtensionMenuItem::List* all_items = manager->MenuItems(extension_id); | 212 const ExtensionMenuItem::List* all_items = manager->MenuItems(extension_id); |
290 if (!all_items || all_items->empty()) | 213 if (!all_items || all_items->empty()) |
291 return; | 214 return; |
292 bool can_cross_incognito = service->CanCrossIncognito(extension); | 215 bool can_cross_incognito = service->CanCrossIncognito(extension); |
293 ExtensionMenuItem::List items = | 216 ExtensionMenuItem::List items = |
294 GetRelevantExtensionItems(*all_items, params_, profile_, | 217 ContextMenuUtils::GetRelevantExtensionItems(*all_items, |
295 can_cross_incognito); | 218 params_, |
| 219 profile_, |
| 220 can_cross_incognito); |
296 if (items.empty()) | 221 if (items.empty()) |
297 return; | 222 return; |
298 | 223 |
299 // 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. |
300 if (*index == 0) | 225 if (*index == 0) |
301 menu_model_.AddSeparator(); | 226 menu_model_.AddSeparator(); |
302 | 227 |
303 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; | 228 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; |
304 | 229 |
305 // 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 |
306 // 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). |
307 // 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. |
308 string16 title; | 233 string16 title; |
309 ExtensionMenuItem::List submenu_items; | 234 ExtensionMenuItem::List submenu_items; |
310 if (items.size() > 1 || items[0]->type() != ExtensionMenuItem::NORMAL) { | 235 if (items.size() > 1 || items[0]->type() != ExtensionMenuItem::NORMAL) { |
311 title = UTF8ToUTF16(extension->name()); | 236 title = UTF8ToUTF16(extension->name()); |
312 submenu_items = items; | 237 submenu_items = items; |
313 } else { | 238 } else { |
314 ExtensionMenuItem* item = items[0]; | 239 ExtensionMenuItem* item = items[0]; |
315 extension_item_map_[menu_id] = item->id(); | 240 extension_item_map_[menu_id] = item->id(); |
316 title = item->TitleWithReplacement(PrintableSelectionText(), | 241 title = item->TitleWithReplacement(PrintableSelectionText(), |
317 kMaxExtensionItemTitleLength); | 242 kMaxExtensionItemTitleLength); |
318 submenu_items = GetRelevantExtensionItems(item->children(), params_, | 243 submenu_items = ContextMenuUtils::GetRelevantExtensionItems( |
319 profile_, can_cross_incognito); | 244 item->children(), params_, profile_, can_cross_incognito); |
320 } | 245 } |
321 | 246 |
322 // Now add our item(s) to the menu_model_. | 247 // Now add our item(s) to the menu_model_. |
323 if (submenu_items.empty()) { | 248 if (submenu_items.empty()) { |
324 menu_model_.AddItem(menu_id, title); | 249 menu_model_.AddItem(menu_id, title); |
325 } else { | 250 } else { |
326 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); | 251 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); |
327 extension_menu_models_.push_back(submenu); | 252 extension_menu_models_.push_back(submenu); |
328 menu_model_.AddSubMenu(menu_id, title, submenu); | 253 menu_model_.AddSubMenu(menu_id, title, submenu); |
329 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu, | 254 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu, |
(...skipping 24 matching lines...) Expand all Loading... |
354 } | 279 } |
355 | 280 |
356 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; | 281 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; |
357 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) | 282 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) |
358 return; | 283 return; |
359 extension_item_map_[menu_id] = item->id(); | 284 extension_item_map_[menu_id] = item->id(); |
360 string16 title = item->TitleWithReplacement(selection_text, | 285 string16 title = item->TitleWithReplacement(selection_text, |
361 kMaxExtensionItemTitleLength); | 286 kMaxExtensionItemTitleLength); |
362 if (item->type() == ExtensionMenuItem::NORMAL) { | 287 if (item->type() == ExtensionMenuItem::NORMAL) { |
363 ExtensionMenuItem::List children = | 288 ExtensionMenuItem::List children = |
364 GetRelevantExtensionItems(item->children(), params_, | 289 ContextMenuUtils::GetRelevantExtensionItems( |
365 profile_, can_cross_incognito); | 290 item->children(), params_, profile_, can_cross_incognito); |
366 if (children.empty()) { | 291 if (children.empty()) { |
367 menu_model->AddItem(menu_id, title); | 292 menu_model->AddItem(menu_id, title); |
368 } else { | 293 } else { |
369 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); | 294 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); |
370 extension_menu_models_.push_back(submenu); | 295 extension_menu_models_.push_back(submenu); |
371 menu_model->AddSubMenu(menu_id, title, submenu); | 296 menu_model->AddSubMenu(menu_id, title, submenu); |
372 RecursivelyAppendExtensionItems(children, can_cross_incognito, | 297 RecursivelyAppendExtensionItems(children, can_cross_incognito, |
373 submenu, index); | 298 submenu, index); |
374 } | 299 } |
375 } 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... |
407 | 332 |
408 menu_model_.SetIcon(index, icon); | 333 menu_model_.SetIcon(index, icon); |
409 } | 334 } |
410 | 335 |
411 void RenderViewContextMenu::AppendAllExtensionItems() { | 336 void RenderViewContextMenu::AppendAllExtensionItems() { |
412 extension_item_map_.clear(); | 337 extension_item_map_.clear(); |
413 ExtensionService* service = profile_->GetExtensionService(); | 338 ExtensionService* service = profile_->GetExtensionService(); |
414 if (!service) | 339 if (!service) |
415 return; // In unit-tests, we may not have an ExtensionService. | 340 return; // In unit-tests, we may not have an ExtensionService. |
416 ExtensionMenuManager* menu_manager = service->menu_manager(); | 341 ExtensionMenuManager* menu_manager = service->menu_manager(); |
417 const GURL& document_url = GetDocumentURL(params_); | 342 const GURL& document_url = ContextMenuUtils::GetDocumentURL(params_); |
418 if (!menu_manager->HasAllowedScheme(document_url)) | 343 if (!menu_manager->HasAllowedScheme(document_url)) |
419 return; | 344 return; |
420 | 345 |
421 // 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 |
422 // the extension's name. | 347 // the extension's name. |
423 std::set<std::string> ids = menu_manager->ExtensionIds(); | 348 std::set<std::string> ids = menu_manager->ExtensionIds(); |
424 std::vector<std::pair<std::string, std::string> > sorted_ids; | 349 std::vector<std::pair<std::string, std::string> > sorted_ids; |
425 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) { |
426 const Extension* extension = service->GetExtensionById(*i, false); | 351 const Extension* extension = service->GetExtensionById(*i, false); |
427 if (extension) | 352 if (extension) |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 break; | 418 break; |
494 case WebContextMenuData::MediaTypeImage: | 419 case WebContextMenuData::MediaTypeImage: |
495 AppendImageItems(); | 420 AppendImageItems(); |
496 break; | 421 break; |
497 case WebContextMenuData::MediaTypeVideo: | 422 case WebContextMenuData::MediaTypeVideo: |
498 AppendVideoItems(); | 423 AppendVideoItems(); |
499 break; | 424 break; |
500 case WebContextMenuData::MediaTypeAudio: | 425 case WebContextMenuData::MediaTypeAudio: |
501 AppendAudioItems(); | 426 AppendAudioItems(); |
502 break; | 427 break; |
| 428 case WebContextMenuData::MediaTypeFile: |
| 429 AppendFileItems(); |
| 430 break; |
503 case WebContextMenuData::MediaTypePlugin: | 431 case WebContextMenuData::MediaTypePlugin: |
504 AppendPluginItems(); | 432 AppendPluginItems(); |
505 break; | 433 break; |
506 } | 434 } |
507 | 435 |
508 if (params_.is_editable) | 436 if (params_.is_editable) |
509 AppendEditableItems(); | 437 AppendEditableItems(); |
510 else if (has_selection) | 438 else if (has_selection) |
511 AppendCopyItem(); | 439 AppendCopyItem(); |
512 | 440 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 AppendMediaItems(); | 513 AppendMediaItems(); |
586 menu_model_.AddSeparator(); | 514 menu_model_.AddSeparator(); |
587 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, | 515 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, |
588 IDS_CONTENT_CONTEXT_SAVEVIDEOAS); | 516 IDS_CONTENT_CONTEXT_SAVEVIDEOAS); |
589 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION, | 517 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION, |
590 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION); | 518 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION); |
591 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB, | 519 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB, |
592 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB); | 520 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB); |
593 } | 521 } |
594 | 522 |
| 523 void RenderViewContextMenu::AppendFileItems() { |
| 524 // TODO(zelidrag): Add file context operations here (i.e. cut, copy, paste...) |
| 525 } |
| 526 |
595 void RenderViewContextMenu::AppendMediaItems() { | 527 void RenderViewContextMenu::AppendMediaItems() { |
596 int media_flags = params_.media_flags; | 528 int media_flags = params_.media_flags; |
597 | 529 |
598 menu_model_.AddItemWithStringId( | 530 menu_model_.AddItemWithStringId( |
599 IDC_CONTENT_CONTEXT_PLAYPAUSE, | 531 IDC_CONTENT_CONTEXT_PLAYPAUSE, |
600 media_flags & WebContextMenuData::MediaPaused ? | 532 media_flags & WebContextMenuData::MediaPaused ? |
601 IDS_CONTENT_CONTEXT_PLAY : | 533 IDS_CONTENT_CONTEXT_PLAY : |
602 IDS_CONTENT_CONTEXT_PAUSE); | 534 IDS_CONTENT_CONTEXT_PAUSE); |
603 | 535 |
604 menu_model_.AddItemWithStringId( | 536 menu_model_.AddItemWithStringId( |
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1538 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), | 1470 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), |
1539 g_browser_process->clipboard()); | 1471 g_browser_process->clipboard()); |
1540 } | 1472 } |
1541 | 1473 |
1542 void RenderViewContextMenu::MediaPlayerActionAt( | 1474 void RenderViewContextMenu::MediaPlayerActionAt( |
1543 const gfx::Point& location, | 1475 const gfx::Point& location, |
1544 const WebMediaPlayerAction& action) { | 1476 const WebMediaPlayerAction& action) { |
1545 source_tab_contents_->render_view_host()->MediaPlayerActionAt( | 1477 source_tab_contents_->render_view_host()->MediaPlayerActionAt( |
1546 location, action); | 1478 location, action); |
1547 } | 1479 } |
OLD | NEW |