summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.h
blob: 14f37b6f53725c1cdeee5c8dc22209a092704daf (plain)
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
// Copyright 2013 The Chromium Authors. All rights reserved.
// 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/macros.h"
#include "base/scoped_observer.h"
#include "chrome/browser/extensions/api/tabs/tabs_api.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_observer.h"
#include "chrome/browser/resource_coordinator/tab_manager.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_observer.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 favicon {
class FaviconDriver;
}

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::TabLifecycleObserver {
 public:
  explicit TabsEventRouter(Profile* profile);
  ~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;

  // ZoomObserver:
  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::TabLifecycleObserver:
  void OnDiscardedStateChange(content::WebContents* contents,
                              ::mojom::LifecycleUnitDiscardReason reason,
                              bool is_discarded) override;
  void OnAutoDiscardableStateChange(content::WebContents* contents,
                                    bool is_auto_discardable) 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,
                                int index,
                                int reason);
  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,
                     std::unique_ptr<base::ListValue> 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,
      const 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);

    // 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.
    TabsEventRouter* router_;

    DISALLOW_COPY_AND_ASSIGN(TabEntry);
  };

  // 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.
  Profile* profile_;

  ScopedObserver<favicon::FaviconDriver, TabsEventRouter>
      favicon_scoped_observer_;

  BrowserTabStripTracker browser_tab_strip_tracker_;

  ScopedObserver<resource_coordinator::TabManager, TabsEventRouter>
      tab_manager_scoped_observer_;

  DISALLOW_COPY_AND_ASSIGN(TabsEventRouter);
};

}  // namespace extensions

#endif  // CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_