mac: add focus-target alternates to Tab menu

The Tab menu in the Mac system menu bar has some options that target the
foreground tab, like "Mute Site" and such. This change introduces
alternates that show up for those items when Option is held which
instead target the tab that has keyboard focus. This allows the user to
perform those operations on a tab without having to activate it.

There are no key equivalents for these new options (yet?), but they are
still usable two ways:
1) By focusing a tab, then using Ctrl-F2 to move native focus to the
   system menu bar and navigating to the Tab menu,
2) By adding a user key equivalent corresponding to these items by name
   and invoking that at any time

The main implementation complexity in this CL is that TabStripModel
doesn't know about keyboard focus for tabs, and has no easy way of
finding out about it without depending on implementation details of the
TabStrip View. As such, this CL directly binds TabStrip (the View class)
to BrowserCommandController.

This change:
1) Has TabStrip (the Views View of the TabStripModel) observe its Tabs
   for keyboard focus changes and propagate these into the
   BrowserCommandController.
2) Adds new menu items to the MainMenu builder as alternates to the
   existing commands in the Tab menu.
3) Adds implementations of these commands in browser_commands.

Bug: 818261
Change-Id: Ia222e412c53e19dde3cb19f38b18a8507f11f7e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1829804
Commit-Queue: Elly Fong-Jones <[email protected]>
Reviewed-by: Greg Thompson <[email protected]>
Reviewed-by: Peter Boström <[email protected]>
Reviewed-by: Taylor Bergquist <[email protected]>
Reviewed-by: Robert Sesek <[email protected]>
Cr-Commit-Position: refs/heads/master@{#704878}
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 9fb35d8e..be4545a3 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -309,6 +309,11 @@
   UpdateCommandsForBookmarkEditing();
 }
 
+void BrowserCommandController::TabKeyboardFocusChangedTo(
+    base::Optional<int> index) {
+  UpdateCommandsForTabKeyboardFocus(index);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserCommandController, CommandUpdater implementation:
 
@@ -742,6 +747,15 @@
       ShowSingletonTab(browser_, GURL(kChromeUIManagementURL));
       break;
     }
+    case IDC_MUTE_TARGET_SITE:
+      MuteSiteForKeyboardFocusedTab(browser_);
+      break;
+    case IDC_PIN_TARGET_TAB:
+      PinKeyboardFocusedTab(browser_);
+      break;
+    case IDC_DUPLICATE_TARGET_TAB:
+      DuplicateKeyboardFocusedTab(browser_);
+      break;
     // Hosted App commands
     case IDC_COPY_URL:
       CopyURL(browser_);
@@ -1026,6 +1040,7 @@
   UpdateCommandsForContentRestrictionState();
   UpdateCommandsForBookmarkEditing();
   UpdateCommandsForIncognitoAvailability();
+  UpdateCommandsForTabKeyboardFocus(GetKeyboardFocusedTabIndex(browser_));
 }
 
 // static
@@ -1132,6 +1147,7 @@
   UpdateCommandsForMediaRouter();
   // Update the zoom commands when an active tab is selected.
   UpdateCommandsForZoomState();
+  UpdateCommandsForTabKeyboardFocus(GetKeyboardFocusedTabIndex(browser_));
 }
 
 void BrowserCommandController::UpdateCommandsForZoomState() {
@@ -1428,6 +1444,19 @@
                                         CanRouteMedia(browser_));
 }
 
+void BrowserCommandController::UpdateCommandsForTabKeyboardFocus(
+    base::Optional<int> target_index) {
+  command_updater_.UpdateCommandEnabled(
+      IDC_DUPLICATE_TARGET_TAB, !browser_->deprecated_is_app() &&
+                                    target_index.has_value() &&
+                                    CanDuplicateTabAt(browser_, *target_index));
+  const bool normal_window = browser_->is_type_normal();
+  command_updater_.UpdateCommandEnabled(
+      IDC_MUTE_TARGET_SITE, normal_window && target_index.has_value());
+  command_updater_.UpdateCommandEnabled(
+      IDC_PIN_TARGET_TAB, normal_window && target_index.has_value());
+}
+
 void BrowserCommandController::AddInterstitialObservers(WebContents* contents) {
   interstitial_observers_.push_back(new InterstitialObserver(this, contents));
 }