Fix bug with context menus in incognito mode.

If an extension uses "spanning" mode, the context menu items are shared
between profiles. If an extension uses "split" mode, the items are separate
per profile. In either case, they only appear in incognito if the extension is
enabled in incognito.

Also fixed a minor bug, so that tabs.create now can open extension URLs in
incognito if the extension uses split mode.

BUG=61147
TEST=see bug for repro steps; context menu items should work in incognito mode

Review URL: http://codereview.chromium.org/4090011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64812 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_context_menu_api.cc b/chrome/browser/extensions/extension_context_menu_api.cc
index 51e9dfb..a004b97 100644
--- a/chrome/browser/extensions/extension_context_menu_api.cc
+++ b/chrome/browser/extensions/extension_context_menu_api.cc
@@ -174,22 +174,21 @@
   return true;
 }
 
-
 bool ExtensionContextMenuFunction::GetParent(
     const DictionaryValue& properties,
     const ExtensionMenuManager& manager,
     ExtensionMenuItem** result) {
   if (!properties.HasKey(kParentIdKey))
     return true;
-  ExtensionMenuItem::Id parent_id(extension_id(), 0);
+  ExtensionMenuItem::Id parent_id(profile(), extension_id(), 0);
   if (properties.HasKey(kParentIdKey) &&
-      !properties.GetInteger(kParentIdKey, &parent_id.second))
+      !properties.GetInteger(kParentIdKey, &parent_id.uid))
     return false;
 
   ExtensionMenuItem* parent = manager.GetItemById(parent_id);
   if (!parent) {
     error_ = "Cannot find menu item with id " +
-        base::IntToString(parent_id.second);
+        base::IntToString(parent_id.uid);
     return false;
   }
   if (parent->type() != ExtensionMenuItem::NORMAL) {
@@ -205,9 +204,9 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &properties));
   EXTENSION_FUNCTION_VALIDATE(properties != NULL);
 
-  ExtensionMenuItem::Id id(extension_id(), 0);
+  ExtensionMenuItem::Id id(profile(), extension_id(), 0);
   EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kGeneratedIdKey,
-                                                     &id.second));
+                                                     &id.uid));
   std::string title;
   if (properties->HasKey(kTitleKey) &&
       !properties->GetString(kTitleKey, &title))
@@ -241,13 +240,13 @@
 
   bool success = true;
   if (properties->HasKey(kParentIdKey)) {
-    ExtensionMenuItem::Id parent_id(extension_id(), 0);
+    ExtensionMenuItem::Id parent_id(profile(), extension_id(), 0);
     EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kParentIdKey,
-                                                       &parent_id.second));
+                                                       &parent_id.uid));
     ExtensionMenuItem* parent = menu_manager->GetItemById(parent_id);
     if (!parent) {
       error_ = ExtensionErrorUtils::FormatErrorMessage(
-          kCannotFindItemError, base::IntToString(parent_id.second));
+          kCannotFindItemError, base::IntToString(parent_id.uid));
       return false;
     }
     if (parent->type() != ExtensionMenuItem::NORMAL) {
@@ -266,15 +265,15 @@
 }
 
 bool UpdateContextMenuFunction::RunImpl() {
-  ExtensionMenuItem::Id item_id(extension_id(), 0);
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.second));
+  ExtensionMenuItem::Id item_id(profile(), extension_id(), 0);
+  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.uid));
 
   ExtensionsService* service = profile()->GetExtensionsService();
   ExtensionMenuManager* manager = service->menu_manager();
   ExtensionMenuItem* item = manager->GetItemById(item_id);
   if (!item || item->extension_id() != extension_id()) {
     error_ = ExtensionErrorUtils::FormatErrorMessage(
-        kCannotFindItemError, base::IntToString(item_id.second));
+        kCannotFindItemError, base::IntToString(item_id.uid));
     return false;
   }
 
@@ -333,8 +332,8 @@
 }
 
 bool RemoveContextMenuFunction::RunImpl() {
-  ExtensionMenuItem::Id id(extension_id(), 0);
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.second));
+  ExtensionMenuItem::Id id(profile(), extension_id(), 0);
+  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.uid));
   ExtensionsService* service = profile()->GetExtensionsService();
   ExtensionMenuManager* manager = service->menu_manager();
 
@@ -342,7 +341,7 @@
   // Ensure one extension can't remove another's menu items.
   if (!item || item->extension_id() != extension_id()) {
     error_ = ExtensionErrorUtils::FormatErrorMessage(
-        kCannotFindItemError, base::IntToString(id.second));
+        kCannotFindItemError, base::IntToString(id.uid));
     return false;
   }
 
diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc
index b0041ad..73f4acf 100644
--- a/chrome/browser/extensions/extension_context_menu_browsertest.cc
+++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc
@@ -5,6 +5,7 @@
 #include "app/menus/menu_model.h"
 #include "chrome/app/chrome_dll_resource.h"
 #include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
 #include "chrome/browser/extensions/extensions_service.h"
@@ -122,9 +123,16 @@
     return LoadExtension(extension_dir);
   }
 
-  TestRenderViewContextMenu* CreateMenu(const GURL& page_url,
+  bool LoadContextMenuExtensionIncognito(std::string subdirectory) {
+    FilePath extension_dir =
+        test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory);
+    return LoadExtensionIncognito(extension_dir);
+  }
+
+  TestRenderViewContextMenu* CreateMenu(Browser* browser,
+                                        const GURL& page_url,
                                         const GURL& link_url) {
-    TabContents* tab_contents = browser()->GetSelectedTabContents();
+    TabContents* tab_contents = browser->GetSelectedTabContents();
     WebContextMenuData data;
     ContextMenuParams params(data);
     params.page_url = page_url;
@@ -173,7 +181,8 @@
   bool MenuHasItemWithLabel(const GURL& page_url,
                             const GURL& link_url,
                             const std::string& label) {
-    scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(page_url, link_url));
+    scoped_ptr<TestRenderViewContextMenu> menu(
+        CreateMenu(browser(), page_url, link_url));
     return menu->HasExtensionItemWithLabel(label);
   }
 };
@@ -190,7 +199,8 @@
   GURL page_url("http://www.google.com");
 
   // Create and build our test context menu.
-  scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(page_url, GURL()));
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      CreateMenu(browser(), page_url, GURL()));
 
   // Look for the extension item in the menu, and execute it.
   int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
@@ -249,7 +259,8 @@
   // Create a context menu, then find the item's label. It should be properly
   // truncated.
   GURL url("http://foo.com/");
-  scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(url, GURL()));
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      CreateMenu(browser(), url, GURL()));
 
   string16 label;
   ASSERT_TRUE(menu->GetItemLabel(item->id(), &label));
@@ -313,7 +324,8 @@
   listener1.WaitUntilSatisfied();
 
   GURL url("http://www.google.com/");
-  scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(url, GURL()));
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      CreateMenu(browser(), url, GURL()));
 
   // The top-level item should be an "automagic parent" with the extension's
   // name.
@@ -336,7 +348,7 @@
   ui_test_utils::NavigateToURL(browser(),
                                GURL(extension->GetResourceURL("test2.html")));
   listener2.WaitUntilSatisfied();
-  menu.reset(CreateMenu(url, GURL()));
+  menu.reset(CreateMenu(browser(), url, GURL()));
   ASSERT_TRUE(menu->GetMenuModelAndItemIndex(
       IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, &model, &index));
   EXPECT_EQ(UTF8ToUTF16("parent"), model->GetLabelAt(index));
@@ -368,3 +380,50 @@
                                     non_google_url,
                                     std::string("item1")));
 }
+
+// Tests adding a simple context menu item.
+IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, IncognitoSplit) {
+  ExtensionTestMessageListener created("created item regular", false);
+  ExtensionTestMessageListener created_incognito("created item incognito",
+                                                 false);
+
+  ExtensionTestMessageListener onclick("onclick fired regular", false);
+  ExtensionTestMessageListener onclick_incognito("onclick fired incognito",
+                                                 false);
+
+  // Open an incognito window.
+  ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
+
+  ASSERT_TRUE(LoadContextMenuExtensionIncognito("incognito"));
+
+  // Wait for the extension's processes to tell us they've created an item.
+  ASSERT_TRUE(created.WaitUntilSatisfied());
+  ASSERT_TRUE(created_incognito.WaitUntilSatisfied());
+
+  GURL page_url("http://www.google.com");
+
+  // Create and build our test context menu.
+  Browser* browser_incognito = BrowserList::FindBrowserWithType(
+      browser()->profile()->GetOffTheRecordProfile(),
+      Browser::TYPE_NORMAL, false);
+  ASSERT_TRUE(browser_incognito);
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      CreateMenu(browser(), page_url, GURL()));
+  scoped_ptr<TestRenderViewContextMenu> menu_incognito(
+      CreateMenu(browser_incognito, page_url, GURL()));
+
+  // Look for the extension item in the menu, and execute it.
+  int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
+  ASSERT_TRUE(menu->IsCommandIdEnabled(command_id));
+  menu->ExecuteCommand(command_id);
+
+  // Wait for the extension's script to tell us its onclick fired. Ensure
+  // that the incognito version doesn't fire until we explicitly click the
+  // incognito menu item.
+  ASSERT_TRUE(onclick.WaitUntilSatisfied());
+  EXPECT_FALSE(onclick_incognito.was_satisfied());
+
+  ASSERT_TRUE(menu_incognito->IsCommandIdEnabled(command_id));
+  menu_incognito->ExecuteCommand(command_id);
+  ASSERT_TRUE(onclick_incognito.WaitUntilSatisfied());
+}
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc
index b1577167..c033454 100644
--- a/chrome/browser/extensions/extension_event_router.cc
+++ b/chrome/browser/extensions/extension_event_router.cc
@@ -33,17 +33,6 @@
       extension_id, kDispatchEvent, args, event_url));
 }
 
-static bool CanCrossIncognito(Profile* profile,
-                              const std::string& extension_id) {
-  // We allow the extension to see events and data from another profile iff it
-  // uses "spanning" behavior and it has incognito access. "split" mode
-  // extensions only see events for a matching profile.
-  const Extension* extension =
-      profile->GetExtensionsService()->GetExtensionById(extension_id, false);
-  return (profile->GetExtensionsService()->IsIncognitoEnabled(extension) &&
-          !extension->incognito_split_mode());
-}
-
 }  // namespace
 
 struct ExtensionEventRouter::EventListener {
@@ -63,6 +52,24 @@
   }
 };
 
+// static
+bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
+                                             const std::string& extension_id) {
+  const Extension* extension =
+      profile->GetExtensionsService()->GetExtensionById(extension_id, false);
+  return CanCrossIncognito(profile, extension);
+}
+
+// static
+bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
+                                             const Extension* extension) {
+  // We allow the extension to see events and data from another profile iff it
+  // uses "spanning" behavior and it has incognito access. "split" mode
+  // extensions only see events for a matching profile.
+  return (profile->GetExtensionsService()->IsIncognitoEnabled(extension) &&
+          !extension->incognito_split_mode());
+}
+
 ExtensionEventRouter::ExtensionEventRouter(Profile* profile)
     : profile_(profile),
       extension_devtools_manager_(profile->GetExtensionDevToolsManager()) {
diff --git a/chrome/browser/extensions/extension_event_router.h b/chrome/browser/extensions/extension_event_router.h
index 5e1ca97..c9f1f21e 100644
--- a/chrome/browser/extensions/extension_event_router.h
+++ b/chrome/browser/extensions/extension_event_router.h
@@ -15,12 +15,19 @@
 #include "chrome/common/notification_registrar.h"
 
 class GURL;
+class Extension;
 class ExtensionDevToolsManager;
 class Profile;
 class RenderProcessHost;
 
 class ExtensionEventRouter : public NotificationObserver {
  public:
+  // Returns true if the given extension can see events and data from another
+  // sub-profile (incognito to original profile, or vice versa).
+  static bool CanCrossIncognito(Profile* profile,
+                                const std::string& extension_id);
+  static bool CanCrossIncognito(Profile* profile, const Extension* extension);
+
   explicit ExtensionEventRouter(Profile* profile);
   ~ExtensionEventRouter();
 
diff --git a/chrome/browser/extensions/extension_menu_manager.cc b/chrome/browser/extensions/extension_menu_manager.cc
index 9ddb0f0..eae74f6 100644
--- a/chrome/browser/extensions/extension_menu_manager.cc
+++ b/chrome/browser/extensions/extension_menu_manager.cc
@@ -389,9 +389,9 @@
   ListValue args;
 
   DictionaryValue* properties = new DictionaryValue();
-  properties->SetInteger("menuItemId", item->id().second);
+  properties->SetInteger("menuItemId", item->id().uid);
   if (item->parent_id())
-    properties->SetInteger("parentMenuItemId", item->parent_id()->second);
+    properties->SetInteger("parentMenuItemId", item->parent_id()->uid);
 
   switch (params.media_type) {
     case WebKit::WebContextMenuData::MediaTypeImage:
@@ -471,3 +471,36 @@
   URLPattern pattern(kAllowedSchemes);
   return pattern.SetScheme(url.scheme());
 }
+
+ExtensionMenuItem::Id::Id()
+    : profile(NULL), uid(0) {
+}
+
+ExtensionMenuItem::Id::Id(Profile* profile, std::string extension_id, int uid)
+    : profile(profile), extension_id(extension_id), uid(uid) {
+}
+
+ExtensionMenuItem::Id::~Id() {
+}
+
+bool ExtensionMenuItem::Id::operator==(const Id& other) const {
+  return (profile == other.profile &&
+          extension_id == other.extension_id &&
+          uid == other.uid);
+}
+
+bool ExtensionMenuItem::Id::operator!=(const Id& other) const {
+  return !(*this == other);
+}
+
+bool ExtensionMenuItem::Id::operator<(const Id& other) const {
+  if (profile < other.profile)
+    return true;
+  if (profile == other.profile) {
+    if (extension_id < other.extension_id)
+      return true;
+    if (extension_id == other.extension_id)
+      return uid < other.uid;
+  }
+  return false;
+}
diff --git a/chrome/browser/extensions/extension_menu_manager.h b/chrome/browser/extensions/extension_menu_manager.h
index 4455ee1..c8224d11 100644
--- a/chrome/browser/extensions/extension_menu_manager.h
+++ b/chrome/browser/extensions/extension_menu_manager.h
@@ -33,9 +33,20 @@
   // A list of ExtensionMenuItem's.
   typedef std::vector<ExtensionMenuItem*> List;
 
-  // An Id is a pair of |extension id|, |int| where the |int| is unique per
-  // extension.
-  typedef std::pair<std::string, int> Id;
+  // An Id uniquely identifies a context menu item registered by an extension.
+  struct Id {
+    Id();
+    Id(Profile* profile, std::string extension_id, int uid);
+    ~Id();
+
+    bool operator==(const Id& other) const;
+    bool operator!=(const Id& other) const;
+    bool operator<(const Id& other) const;
+
+    Profile* profile;
+    std::string extension_id;
+    int uid;
+  };
 
   // For context menus, these are the contexts where an item can appear.
   enum Context {
@@ -93,7 +104,7 @@
   virtual ~ExtensionMenuItem();
 
   // Simple accessor methods.
-  const std::string& extension_id() const { return id_.first; }
+  const std::string& extension_id() const { return id_.extension_id; }
   const std::string& title() const { return title_; }
   const List& children() { return children_; }
   const Id& id() const { return id_; }
diff --git a/chrome/browser/extensions/extension_menu_manager_unittest.cc b/chrome/browser/extensions/extension_menu_manager_unittest.cc
index 549c245..cbd9a52 100644
--- a/chrome/browser/extensions/extension_menu_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_menu_manager_unittest.cc
@@ -37,7 +37,7 @@
   ExtensionMenuItem* CreateTestItem(Extension* extension) {
     ExtensionMenuItem::Type type = ExtensionMenuItem::NORMAL;
     ExtensionMenuItem::ContextList contexts(ExtensionMenuItem::ALL);
-    ExtensionMenuItem::Id id(extension->id(), next_id_++);
+    ExtensionMenuItem::Id id(NULL, extension->id(), next_id_++);
     return new ExtensionMenuItem(id, "test", false, type, contexts);
   }
 
@@ -94,7 +94,7 @@
   ASSERT_EQ(2u, manager_.MenuItems(extension_id)->size());
 
   // Make sure removing a non-existent item returns false.
-  ExtensionMenuItem::Id id(extension->id(), id3.second + 50);
+  ExtensionMenuItem::Id id(NULL, extension->id(), id3.uid + 50);
   ASSERT_FALSE(manager_.RemoveContextMenuItem(id));
 }
 
@@ -461,7 +461,7 @@
 
   int tmp_id = 0;
   ASSERT_TRUE(info->GetInteger("menuItemId", &tmp_id));
-  ASSERT_EQ(id.second, tmp_id);
+  ASSERT_EQ(id.uid, tmp_id);
 
   std::string tmp;
   ASSERT_TRUE(info->GetString("mediaType", &tmp));
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index 3598808..11d5f31 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -598,9 +598,10 @@
     EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kSelectedKey,
                                                  &selected));
 
-  // We can't load extension URLs into incognito windows. Special case to
-  // fall back to a normal window.
+  // We can't load extension URLs into incognito windows unless the extension
+  // uses split mode. Special case to fall back to a normal window.
   if (url.SchemeIs(chrome::kExtensionScheme) &&
+      !GetExtension()->incognito_split_mode() &&
       browser->profile()->IsOffTheRecord()) {
     Profile* profile = browser->profile()->GetOriginalProfile();
     browser = BrowserList::FindBrowserWithType(profile,
diff --git a/chrome/browser/extensions/extension_test_message_listener.cc b/chrome/browser/extensions/extension_test_message_listener.cc
index 423bf3b1..8ba0683 100644
--- a/chrome/browser/extensions/extension_test_message_listener.cc
+++ b/chrome/browser/extensions/extension_test_message_listener.cc
@@ -43,8 +43,8 @@
     const NotificationSource& source,
     const NotificationDetails& details) {
   const std::string& content = *Details<std::string>(details).ptr();
-  function_ = Source<ExtensionTestSendMessageFunction>(source).ptr();
   if (!satisfied_ && content == expected_message_) {
+    function_ = Source<ExtensionTestSendMessageFunction>(source).ptr();
     satisfied_ = true;
     registrar_.RemoveAll();  // Stop listening for more messages.
     if (!will_reply_) {
diff --git a/chrome/browser/extensions/extension_test_message_listener.h b/chrome/browser/extensions/extension_test_message_listener.h
index bead446a..86c4cf2 100644
--- a/chrome/browser/extensions/extension_test_message_listener.h
+++ b/chrome/browser/extensions/extension_test_message_listener.h
@@ -63,6 +63,8 @@
                        const NotificationSource& source,
                        const NotificationDetails& details);
 
+  bool was_satisfied() const { return satisfied_; }
+
  private:
   NotificationRegistrar registrar_;
 
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index afd5ccb..f792b35 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/debugger/devtools_manager.h"
 #include "chrome/browser/debugger/devtools_window.h"
 #include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/extensions/extension_event_router.h"
 #include "chrome/browser/extensions/extensions_service.h"
 #include "chrome/browser/fonts_languages_window.h"
 #include "chrome/browser/metrics/user_metrics.h"
@@ -150,10 +151,12 @@
 }
 
 // Given a list of items, returns the ones that match given the contents
-// of |params|.
+// of |params| and the profile.
 static ExtensionMenuItem::List GetRelevantExtensionItems(
     const ExtensionMenuItem::List& items,
-    const ContextMenuParams& params) {
+    const ContextMenuParams& params,
+    Profile* profile,
+    bool can_cross_incognito) {
   ExtensionMenuItem::List result;
   for (ExtensionMenuItem::List::const_iterator i = items.begin();
        i != items.end(); ++i) {
@@ -171,7 +174,8 @@
     if (!ExtensionPatternMatch(item->target_url_patterns(), target_url))
       continue;
 
-    result.push_back(*i);
+    if (item->id().profile == profile || can_cross_incognito)
+      result.push_back(*i);
   }
   return result;
 }
@@ -181,6 +185,8 @@
   ExtensionsService* service = profile_->GetExtensionsService();
   ExtensionMenuManager* manager = service->menu_manager();
   const Extension* extension = service->GetExtensionById(extension_id, false);
+  bool can_cross_incognito =
+      ExtensionEventRouter::CanCrossIncognito(profile_, extension);
   DCHECK_GE(*index, 0);
   int max_index =
       IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
@@ -192,7 +198,8 @@
   if (!all_items || all_items->empty())
     return;
   ExtensionMenuItem::List items =
-      GetRelevantExtensionItems(*all_items, params_);
+      GetRelevantExtensionItems(*all_items, params_, profile_,
+                                can_cross_incognito);
   if (items.empty())
     return;
 
@@ -215,7 +222,8 @@
     extension_item_map_[menu_id] = item->id();
     title = item->TitleWithReplacement(PrintableSelectionText(),
                                        kMaxExtensionItemTitleLength);
-    submenu_items = GetRelevantExtensionItems(item->children(), params_);
+    submenu_items = GetRelevantExtensionItems(item->children(), params_,
+                                              profile_, can_cross_incognito);
   }
 
   // Now add our item(s) to the menu_model_.
@@ -225,13 +233,15 @@
     menus::SimpleMenuModel* submenu = new menus::SimpleMenuModel(this);
     extension_menu_models_.push_back(submenu);
     menu_model_.AddSubMenu(menu_id, title, submenu);
-    RecursivelyAppendExtensionItems(submenu_items, submenu, index);
+    RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu,
+                                    index);
   }
   SetExtensionIcon(extension_id);
 }
 
 void RenderViewContextMenu::RecursivelyAppendExtensionItems(
     const ExtensionMenuItem::List& items,
+    bool can_cross_incognito,
     menus::SimpleMenuModel* menu_model,
     int *index) {
   string16 selection_text = PrintableSelectionText();
@@ -258,14 +268,16 @@
                                                 kMaxExtensionItemTitleLength);
     if (item->type() == ExtensionMenuItem::NORMAL) {
       ExtensionMenuItem::List children =
-          GetRelevantExtensionItems(item->children(), params_);
+          GetRelevantExtensionItems(item->children(), params_,
+                                    profile_, can_cross_incognito);
       if (children.size() == 0) {
         menu_model->AddItem(menu_id, title);
       } else {
         menus::SimpleMenuModel* submenu = new menus::SimpleMenuModel(this);
         extension_menu_models_.push_back(submenu);
         menu_model->AddSubMenu(menu_id, title, submenu);
-        RecursivelyAppendExtensionItems(children, submenu, index);
+        RecursivelyAppendExtensionItems(children, can_cross_incognito,
+                                        submenu, index);
       }
     } else if (item->type() == ExtensionMenuItem::CHECKBOX) {
       menu_model->AddCheckItem(menu_id, title);
diff --git a/chrome/browser/tab_contents/render_view_context_menu.h b/chrome/browser/tab_contents/render_view_context_menu.h
index 9fd3108..2f1a83e8 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.h
+++ b/chrome/browser/tab_contents/render_view_context_menu.h
@@ -103,6 +103,7 @@
   // Used for recursively adding submenus of extension items.
   void RecursivelyAppendExtensionItems(
       const std::vector<ExtensionMenuItem*>& items,
+      bool can_cross_incognito,
       menus::SimpleMenuModel* menu_model,
       int *index);
   // This will set the icon on the most recently-added item in the menu_model_.