1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
#define CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
#include <map>
#include <set>
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "base/scoped_observation.h"
#include "chrome/browser/extensions/api/tabs/tabs_api.h"
#include "chrome/browser/resource_coordinator/lifecycle_unit_observer.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/browser_tab_strip_tracker.h"
#include "chrome/browser/ui/browser_tab_strip_tracker_delegate.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "components/favicon/core/favicon_driver.h"
#include "components/favicon/core/favicon_driver_observer.h"
#include "components/performance_manager/public/decorators/page_live_state_decorator.h"
#include "components/zoom/zoom_observer.h"
#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/event_router.h"
namespace content {
class WebContents;
}
namespace resource_coordinator {
class TabLifecycleUnitSource;
}
namespace extensions {
// The TabsEventRouter listens to tab events and routes them to listeners inside
// extension process renderers.
// TabsEventRouter will only route events from windows/tabs within a profile to
// extension processes in the same profile.
class TabsEventRouter : public TabStripModelObserver,
public BrowserTabStripTrackerDelegate,
public BrowserListObserver,
public favicon::FaviconDriverObserver,
public zoom::ZoomObserver,
public resource_coordinator::LifecycleUnitObserver,
public performance_manager::PageLiveStateObserver {
public:
explicit TabsEventRouter(Profile* profile);
TabsEventRouter(const TabsEventRouter&) = delete;
TabsEventRouter& operator=(const TabsEventRouter&) = delete;
~TabsEventRouter() override;
// BrowserTabStripTrackerDelegate:
bool ShouldTrackBrowser(Browser* browser) override;
// BrowserListObserver:
void OnBrowserSetLastActive(Browser* browser) override;
// TabStripModelObserver:
void OnTabStripModelChanged(
TabStripModel* tab_strip_model,
const TabStripModelChange& change,
const TabStripSelectionChange& selection) override;
void TabChangedAt(content::WebContents* contents,
int index,
TabChangeType change_type) override;
void TabPinnedStateChanged(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index) override;
void TabGroupedStateChanged(TabStripModel* tab_strip_model,
std::optional<tab_groups::TabGroupId> old_group,
std::optional<tab_groups::TabGroupId> new_group,
tabs::TabInterface* tab,
int index) override;
void OnTabGroupChanged(const TabGroupChange& change) override;
// ZoomObserver:
void OnZoomControllerDestroyed(
zoom::ZoomController* zoom_controller) override;
void OnZoomChanged(
const zoom::ZoomController::ZoomChangedEventData& data) override;
// favicon::FaviconDriverObserver:
void OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
NotificationIconType notification_icon_type,
const GURL& icon_url,
bool icon_url_changed,
const gfx::Image& image) override;
// resource_coordinator::LifecycleUnitObserver:
void OnLifecycleUnitStateChanged(
resource_coordinator::LifecycleUnit* lifecycle_unit,
::mojom::LifecycleUnitState previous_state,
::mojom::LifecycleUnitStateChangeReason reason) override;
// performance_manager::PageLiveStateObserver:
void OnIsAutoDiscardableChanged(
const performance_manager::PageNode* page_node) override;
private:
// Methods called from OnTabStripModelChanged.
void DispatchTabInsertedAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index,
bool active);
void DispatchTabClosingAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index);
void DispatchTabDetachedAt(content::WebContents* contents,
int index,
bool was_active);
void DispatchActiveTabChanged(content::WebContents* old_contents,
content::WebContents* new_contents);
void DispatchTabSelectionChanged(TabStripModel* tab_strip_model,
const ui::ListSelectionModel& old_model);
void DispatchTabMoved(content::WebContents* contents,
int from_index,
int to_index);
void DispatchTabReplacedAt(content::WebContents* old_contents,
content::WebContents* new_contents,
int index);
// "Synthetic" event. Called from DispatchTabInsertedAt if new tab is
// detected.
void TabCreatedAt(content::WebContents* contents, int index, bool active);
// Internal processing of tab updated events. Intended to be called when
// there's any changed property.
class TabEntry;
void TabUpdated(TabEntry* entry,
std::set<std::string> changed_property_names);
// Triggers a tab updated event if the favicon URL changes.
void FaviconUrlUpdated(content::WebContents* contents);
// The DispatchEvent methods forward events to the `profile`'s event router.
// The TabsEventRouter listens to events for all profiles,
// so we avoid duplication by dropping events destined for other profiles.
void DispatchEvent(Profile* profile,
events::HistogramValue histogram_value,
const std::string& event_name,
base::Value::List args,
EventRouter::UserGestureState user_gesture);
// Packages `changed_property_names` as a tab updated event for the tab
// `contents` and dispatches the event to the extension.
void DispatchTabUpdatedEvent(content::WebContents* contents,
std::set<std::string> changed_property_names);
// Register ourselves to receive the various notifications we are interested
// in for a tab. Also create tab entry to observe web contents notifications.
void RegisterForTabNotifications(content::WebContents* contents);
// Removes notifications and tab entry added in RegisterForTabNotifications.
void UnregisterForTabNotifications(content::WebContents* contents);
// Maintain some information about known tabs, so we can:
//
// - distinguish between tab creation and tab insertion
// - not send tab-detached after tab-removed
// - reduce the "noise" of TabChangedAt() when sending events to extensions
// - remember last muted and audible states to know if there was a change
// - listen to WebContentsObserver notifications and forward them to the
// event router.
class TabEntry : public content::WebContentsObserver {
public:
// Create a TabEntry associated with, and tracking state changes to,
// `contents`.
TabEntry(TabsEventRouter* router, content::WebContents* contents);
TabEntry(const TabEntry&) = delete;
TabEntry& operator=(const TabEntry&) = delete;
// Indicate via a list of property names if a tab is loading based on its
// WebContents. Whether the state has changed or not is used to determine if
// events need to be sent to extensions during processing of TabChangedAt()
// If this method indicates that a tab should "hold" a state-change to
// "loading", the NavigationEntryCommitted() method should eventually send a
// similar message to undo it.
std::set<std::string> UpdateLoadState();
// Update the audible and muted states and return whether they were changed
bool SetAudible(bool new_val);
bool SetMuted(bool new_val);
// content::WebContentsObserver:
void NavigationEntryCommitted(
const content::LoadCommittedDetails& load_details) override;
void TitleWasSet(content::NavigationEntry* entry) override;
void WebContentsDestroyed() override;
private:
// Whether we are waiting to fire the 'complete' status change. This will
// occur the first time the WebContents stops loading after the
// NAV_ENTRY_COMMITTED was fired. The tab may go back into and out of the
// loading state subsequently, but we will ignore those changes.
bool complete_waiting_on_load_;
// Previous audible and muted states
bool was_audible_;
bool was_muted_;
GURL url_;
// Event router that the WebContents's noficiations are forwarded to.
raw_ptr<TabsEventRouter> router_;
};
// Gets the TabEntry for the given `contents`. Returns TabEntry* if found,
// nullptr if not.
TabEntry* GetTabEntry(content::WebContents* contents);
using TabEntryMap = std::map<int, std::unique_ptr<TabEntry>>;
TabEntryMap tab_entries_;
// The main profile that owns this event router.
raw_ptr<Profile> profile_;
base::ScopedMultiSourceObservation<favicon::FaviconDriver,
favicon::FaviconDriverObserver>
favicon_scoped_observations_{this};
base::ScopedMultiSourceObservation<zoom::ZoomController, zoom::ZoomObserver>
zoom_scoped_observations_{this};
BrowserTabStripTracker browser_tab_strip_tracker_;
base::ScopedObservation<resource_coordinator::TabLifecycleUnitSource,
resource_coordinator::LifecycleUnitObserver>
tab_source_scoped_observation_{this};
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
|