Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/extensions/menu_manager.h" | 5 #include "chrome/browser/extensions/menu_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/values.h" | 14 #include "base/values.h" |
| 15 #include "chrome/browser/chrome_notification_types.h" | 15 #include "chrome/browser/chrome_notification_types.h" |
| 16 #include "chrome/browser/extensions/event_names.h" | 16 #include "chrome/browser/extensions/event_names.h" |
| 17 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
| 18 #include "chrome/browser/extensions/extension_tab_util.h" | 18 #include "chrome/browser/extensions/extension_tab_util.h" |
| 19 #include "chrome/browser/extensions/menu_manager_factory.h" | 19 #include "chrome/browser/extensions/menu_manager_factory.h" |
| 20 #include "chrome/browser/extensions/state_store.h" | 20 #include "chrome/browser/extensions/state_store.h" |
| 21 #include "chrome/browser/extensions/tab_helper.h" | 21 #include "chrome/browser/extensions/tab_helper.h" |
| 22 #include "chrome/browser/guestview/guestview.h" | |
| 22 #include "chrome/browser/profiles/profile.h" | 23 #include "chrome/browser/profiles/profile.h" |
| 23 #include "chrome/common/extensions/api/context_menus.h" | 24 #include "chrome/common/extensions/api/context_menus.h" |
| 24 #include "content/public/browser/notification_details.h" | 25 #include "content/public/browser/notification_details.h" |
| 25 #include "content/public/browser/notification_service.h" | 26 #include "content/public/browser/notification_service.h" |
| 26 #include "content/public/browser/notification_source.h" | 27 #include "content/public/browser/notification_source.h" |
| 27 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
| 28 #include "content/public/common/context_menu_params.h" | 29 #include "content/public/common/context_menu_params.h" |
| 29 #include "extensions/browser/event_router.h" | 30 #include "extensions/browser/event_router.h" |
| 30 #include "extensions/browser/extension_system.h" | 31 #include "extensions/browser/extension_system.h" |
| 31 #include "extensions/common/extension.h" | 32 #include "extensions/common/extension.h" |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 502 items_by_id_.erase(*removed_iter); | 503 items_by_id_.erase(*removed_iter); |
| 503 } | 504 } |
| 504 | 505 |
| 505 if (list.empty()) { | 506 if (list.empty()) { |
| 506 context_items_.erase(extension_id); | 507 context_items_.erase(extension_id); |
| 507 icon_manager_.RemoveIcon(extension_id); | 508 icon_manager_.RemoveIcon(extension_id); |
| 508 } | 509 } |
| 509 return result; | 510 return result; |
| 510 } | 511 } |
| 511 | 512 |
| 513 void MenuManager::RemoveAllWebviewContextItems(const std::string& extension_id, | |
| 514 int webview_instance_id) { | |
| 515 MenuItem::List::iterator i; | |
| 516 for (i = context_items_[extension_id].begin(); | |
|
Fady Samuel
2014/03/04 01:56:46
I think it would be much cleaner if context items
lazyboy
2014/03/04 16:11:31
Hmmm, for most cases, webview_instance_id is 0, ad
Fady Samuel
2014/03/04 16:36:00
There is no additional indirection being added in
lazyboy
2014/03/04 20:50:24
Included instance id to the key, called MenuItem::
| |
| 517 i != context_items_[extension_id].end(); | |
| 518 ++i) { | |
| 519 MenuItem* item = *i; | |
| 520 if (item->id().webview_instance_id != webview_instance_id) | |
| 521 continue; | |
| 522 items_by_id_.erase(item->id()); | |
| 523 | |
| 524 // Remove descendants from this item and erase them from the lookup cache. | |
| 525 std::set<MenuItem::Id> removed_ids = item->RemoveAllDescendants(); | |
| 526 std::set<MenuItem::Id>::const_iterator j; | |
| 527 for (j = removed_ids.begin(); j != removed_ids.end(); ++j) | |
| 528 items_by_id_.erase(*j); | |
| 529 } | |
| 530 | |
| 531 // TODO(lazyboy): Consider better data structure. We are naivly iterating | |
| 532 // through each items in the extension and remvoving the ones that belong | |
| 533 // to the webview. | |
| 534 MenuItem::List& items = context_items_[extension_id]; | |
| 535 i = items.begin(); | |
| 536 MenuItem::List::iterator check_iter = items.begin(); | |
| 537 MenuItem::List::iterator insert_iter = items.begin(); | |
| 538 | |
| 539 while (check_iter != items.end()) { | |
| 540 int item_webview_instance_id = (*check_iter)->id().webview_instance_id; | |
| 541 if (item_webview_instance_id != webview_instance_id) { | |
| 542 *insert_iter = *check_iter; | |
| 543 ++insert_iter; | |
| 544 } else { | |
| 545 delete *check_iter; | |
| 546 } | |
| 547 ++check_iter; | |
| 548 } | |
| 549 | |
| 550 // Shrink. | |
| 551 items.resize(insert_iter - items.begin()); | |
| 552 if (!items.size()) | |
| 553 context_items_.erase(extension_id); | |
| 554 } | |
| 555 | |
| 512 void MenuManager::RemoveAllContextItems(const std::string& extension_id) { | 556 void MenuManager::RemoveAllContextItems(const std::string& extension_id) { |
| 513 MenuItem::List::iterator i; | 557 MenuItem::List::iterator i; |
| 514 for (i = context_items_[extension_id].begin(); | 558 for (i = context_items_[extension_id].begin(); |
| 515 i != context_items_[extension_id].end(); ++i) { | 559 i != context_items_[extension_id].end(); ++i) { |
| 516 MenuItem* item = *i; | 560 MenuItem* item = *i; |
| 517 items_by_id_.erase(item->id()); | 561 items_by_id_.erase(item->id()); |
| 518 | 562 |
| 519 // Remove descendants from this item and erase them from the lookup cache. | 563 // Remove descendants from this item and erase them from the lookup cache. |
| 520 std::set<MenuItem::Id> removed_ids = item->RemoveAllDescendants(); | 564 std::set<MenuItem::Id> removed_ids = item->RemoveAllDescendants(); |
| 521 std::set<MenuItem::Id>::const_iterator j; | 565 std::set<MenuItem::Id>::const_iterator j; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 639 AddURLProperty(properties, "linkUrl", params.unfiltered_link_url); | 683 AddURLProperty(properties, "linkUrl", params.unfiltered_link_url); |
| 640 AddURLProperty(properties, "srcUrl", params.src_url); | 684 AddURLProperty(properties, "srcUrl", params.src_url); |
| 641 AddURLProperty(properties, "pageUrl", params.page_url); | 685 AddURLProperty(properties, "pageUrl", params.page_url); |
| 642 AddURLProperty(properties, "frameUrl", params.frame_url); | 686 AddURLProperty(properties, "frameUrl", params.frame_url); |
| 643 | 687 |
| 644 if (params.selection_text.length() > 0) | 688 if (params.selection_text.length() > 0) |
| 645 properties->SetString("selectionText", params.selection_text); | 689 properties->SetString("selectionText", params.selection_text); |
| 646 | 690 |
| 647 properties->SetBoolean("editable", params.is_editable); | 691 properties->SetBoolean("editable", params.is_editable); |
| 648 | 692 |
| 693 GuestView* guest_view = GuestView::FromWebContents(web_contents); | |
| 694 if (guest_view) | |
| 695 properties->SetInteger("webviewInstanceId", guest_view->view_instance_id()); | |
|
Fady Samuel
2014/03/04 01:56:46
What is this?
lazyboy
2014/03/04 16:11:31
This is a property on the onClick event.
Fady Samuel
2014/03/04 16:36:00
Is this visible to the developer? What's it used f
lazyboy
2014/03/04 20:50:24
Yes.
This is to indicate which webview the event c
lazyboy
2014/03/04 21:13:49
As discussed offline, I've removed exposing webvie
| |
| 696 | |
| 649 args->Append(properties); | 697 args->Append(properties); |
| 650 | 698 |
| 651 // Add the tab info to the argument list. | 699 // Add the tab info to the argument list. |
| 652 // No tab info in a platform app. | 700 // No tab info in a platform app. |
| 653 if (!extension || !extension->is_platform_app()) { | 701 if (!extension || !extension->is_platform_app()) { |
| 654 // Note: web_contents are NULL in unit tests :( | 702 // Note: web_contents are NULL in unit tests :( |
| 655 if (web_contents) { | 703 if (web_contents) { |
| 656 args->Append(ExtensionTabUtil::CreateTabValue(web_contents)); | 704 args->Append(ExtensionTabUtil::CreateTabValue(web_contents)); |
| 657 } else { | 705 } else { |
| 658 args->Append(new base::DictionaryValue()); | 706 args->Append(new base::DictionaryValue()); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 676 WriteToStorage(extension); | 724 WriteToStorage(extension); |
| 677 } | 725 } |
| 678 | 726 |
| 679 // Note: web_contents are NULL in unit tests :( | 727 // Note: web_contents are NULL in unit tests :( |
| 680 if (web_contents && extensions::TabHelper::FromWebContents(web_contents)) { | 728 if (web_contents && extensions::TabHelper::FromWebContents(web_contents)) { |
| 681 extensions::TabHelper::FromWebContents(web_contents)-> | 729 extensions::TabHelper::FromWebContents(web_contents)-> |
| 682 active_tab_permission_granter()->GrantIfRequested(extension); | 730 active_tab_permission_granter()->GrantIfRequested(extension); |
| 683 } | 731 } |
| 684 | 732 |
| 685 { | 733 { |
| 734 // Dispatch to menu item's .onclick handler. | |
| 686 scoped_ptr<Event> event(new Event( | 735 scoped_ptr<Event> event(new Event( |
| 687 event_names::kOnContextMenus, | 736 event_names::kOnContextMenus, |
| 688 scoped_ptr<base::ListValue>(args->DeepCopy()))); | 737 scoped_ptr<base::ListValue>(args->DeepCopy()))); |
| 689 event->restrict_to_browser_context = profile; | 738 event->restrict_to_browser_context = profile; |
| 690 event->user_gesture = EventRouter::USER_GESTURE_ENABLED; | 739 event->user_gesture = EventRouter::USER_GESTURE_ENABLED; |
| 691 event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); | 740 event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); |
| 692 } | 741 } |
| 693 { | 742 { |
| 694 scoped_ptr<Event> event(new Event(context_menus::OnClicked::kEventName, | 743 // Dispatch to .contextMenus.onClicked handler. |
| 695 args.Pass())); | 744 scoped_ptr<Event> event( |
| 745 new Event(guest_view ? event_names::kOnWebviewContextMenus | |
| 746 : context_menus::OnClicked::kEventName, | |
| 747 args.Pass())); | |
| 696 event->restrict_to_browser_context = profile; | 748 event->restrict_to_browser_context = profile; |
| 697 event->user_gesture = EventRouter::USER_GESTURE_ENABLED; | 749 event->user_gesture = EventRouter::USER_GESTURE_ENABLED; |
| 750 if (guest_view) | |
| 751 event->filter_info.SetInstanceID(guest_view->view_instance_id()); | |
| 698 event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); | 752 event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); |
| 699 } | 753 } |
| 700 } | 754 } |
| 701 | 755 |
| 702 void MenuManager::SanitizeRadioList(const MenuItem::List& item_list) { | 756 void MenuManager::SanitizeRadioList(const MenuItem::List& item_list) { |
| 703 MenuItem::List::const_iterator i = item_list.begin(); | 757 MenuItem::List::const_iterator i = item_list.begin(); |
| 704 while (i != item_list.end()) { | 758 while (i != item_list.end()) { |
| 705 if ((*i)->type() != MenuItem::RADIO) { | 759 if ((*i)->type() != MenuItem::RADIO) { |
| 706 ++i; | 760 ++i; |
| 707 break; | 761 break; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 } | 810 } |
| 757 | 811 |
| 758 void MenuManager::WriteToStorage(const Extension* extension) { | 812 void MenuManager::WriteToStorage(const Extension* extension) { |
| 759 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) | 813 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
| 760 return; | 814 return; |
| 761 const MenuItem::List* top_items = MenuItems(extension->id()); | 815 const MenuItem::List* top_items = MenuItems(extension->id()); |
| 762 MenuItem::List all_items; | 816 MenuItem::List all_items; |
| 763 if (top_items) { | 817 if (top_items) { |
| 764 for (MenuItem::List::const_iterator i = top_items->begin(); | 818 for (MenuItem::List::const_iterator i = top_items->begin(); |
| 765 i != top_items->end(); ++i) { | 819 i != top_items->end(); ++i) { |
| 820 if ((*i)->id().webview_instance_id) | |
| 821 continue; | |
| 766 (*i)->GetFlattenedSubtree(&all_items); | 822 (*i)->GetFlattenedSubtree(&all_items); |
| 767 } | 823 } |
| 768 } | 824 } |
| 769 | 825 |
| 770 if (store_) | 826 if (store_) { |
| 771 store_->SetExtensionValue(extension->id(), kContextMenusKey, | 827 store_->SetExtensionValue(extension->id(), kContextMenusKey, |
| 772 MenuItemsToValue(all_items)); | 828 MenuItemsToValue(all_items)); |
| 829 } | |
| 773 } | 830 } |
| 774 | 831 |
| 775 void MenuManager::ReadFromStorage(const std::string& extension_id, | 832 void MenuManager::ReadFromStorage(const std::string& extension_id, |
| 776 scoped_ptr<base::Value> value) { | 833 scoped_ptr<base::Value> value) { |
| 777 const Extension* extension = | 834 const Extension* extension = |
| 778 ExtensionSystem::Get(profile_)->extension_service()->extensions()-> | 835 ExtensionSystem::Get(profile_)->extension_service()->extensions()-> |
| 779 GetByID(extension_id); | 836 GetByID(extension_id); |
| 780 if (!extension) | 837 if (!extension) |
| 781 return; | 838 return; |
| 782 | 839 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 852 items_to_remove.insert(iter->first); | 909 items_to_remove.insert(iter->first); |
| 853 } | 910 } |
| 854 | 911 |
| 855 std::set<MenuItem::Id>::iterator remove_iter; | 912 std::set<MenuItem::Id>::iterator remove_iter; |
| 856 for (remove_iter = items_to_remove.begin(); | 913 for (remove_iter = items_to_remove.begin(); |
| 857 remove_iter != items_to_remove.end(); | 914 remove_iter != items_to_remove.end(); |
| 858 ++remove_iter) | 915 ++remove_iter) |
| 859 RemoveContextMenuItem(*remove_iter); | 916 RemoveContextMenuItem(*remove_iter); |
| 860 } | 917 } |
| 861 | 918 |
| 862 MenuItem::Id::Id() : incognito(false), uid(0) {} | 919 MenuItem::Id::Id() : incognito(false), uid(0), webview_instance_id(0) {} |
| 863 | 920 |
| 864 MenuItem::Id::Id(bool incognito, const std::string& extension_id) | 921 MenuItem::Id::Id(bool incognito, const std::string& extension_id) |
| 865 : incognito(incognito), extension_id(extension_id), uid(0) {} | 922 : incognito(incognito), |
| 923 extension_id(extension_id), | |
| 924 uid(0), | |
| 925 webview_instance_id(0) {} | |
| 866 | 926 |
| 867 MenuItem::Id::~Id() { | 927 MenuItem::Id::~Id() { |
| 868 } | 928 } |
| 869 | 929 |
| 870 bool MenuItem::Id::operator==(const Id& other) const { | 930 bool MenuItem::Id::operator==(const Id& other) const { |
| 871 return (incognito == other.incognito && | 931 return (incognito == other.incognito && extension_id == other.extension_id && |
| 872 extension_id == other.extension_id && | 932 uid == other.uid && string_uid == other.string_uid && |
| 873 uid == other.uid && | 933 webview_instance_id == other.webview_instance_id); |
| 874 string_uid == other.string_uid); | |
| 875 } | 934 } |
| 876 | 935 |
| 877 bool MenuItem::Id::operator!=(const Id& other) const { | 936 bool MenuItem::Id::operator!=(const Id& other) const { |
| 878 return !(*this == other); | 937 return !(*this == other); |
| 879 } | 938 } |
| 880 | 939 |
| 881 bool MenuItem::Id::operator<(const Id& other) const { | 940 bool MenuItem::Id::operator<(const Id& other) const { |
| 882 if (incognito < other.incognito) | 941 if (incognito < other.incognito) |
| 883 return true; | 942 return true; |
| 884 if (incognito == other.incognito) { | 943 if (incognito == other.incognito) { |
| 885 if (extension_id < other.extension_id) | 944 if (extension_id < other.extension_id) |
| 886 return true; | 945 return true; |
| 887 if (extension_id == other.extension_id) { | 946 if (extension_id == other.extension_id) { |
| 888 if (uid < other.uid) | 947 if (webview_instance_id < other.webview_instance_id) |
| 889 return true; | 948 return true; |
| 890 if (uid == other.uid) | 949 |
| 891 return string_uid < other.string_uid; | 950 if (webview_instance_id == other.webview_instance_id) { |
| 951 if (uid < other.uid) | |
| 952 return true; | |
| 953 if (uid == other.uid) | |
| 954 return string_uid < other.string_uid; | |
| 955 } | |
| 892 } | 956 } |
| 893 } | 957 } |
| 894 return false; | 958 return false; |
| 895 } | 959 } |
| 896 | 960 |
| 897 } // namespace extensions | 961 } // namespace extensions |
| OLD | NEW |