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
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_
6 #define CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <map>
12 #include <memory>
13 #include <vector>
14 
15 #include "base/containers/span.h"
16 #include "base/gtest_prod_util.h"
17 #include "base/macros.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/observer_list.h"
20 #include "base/optional.h"
21 #include "base/scoped_observer.h"
22 #include "base/strings/string16.h"
23 #include "base/time/time.h"
24 #include "base/timer/timer.h"
25 #include "build/build_config.h"
26 #include "chrome/browser/ui/tabs/tab_group_controller.h"
27 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
28 #include "chrome/browser/ui/tabs/tab_switch_event_latency_recorder.h"
29 #include "components/tab_groups/tab_group_id.h"
30 #include "components/tab_groups/tab_group_visual_data.h"
31 #include "ui/base/models/list_selection_model.h"
32 #include "ui/base/page_transition_types.h"
33 
34 #if defined(OS_ANDROID)
35 #error This file should only be included on desktop.
36 #endif
37 
38 class Profile;
39 class TabGroupModel;
40 class TabStripModelDelegate;
41 class TabStripModelObserver;
42 
43 namespace content {
44 class WebContents;
45 }
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 //
49 // TabStripModel
50 //
51 // A model & low level controller of a Browser Window tabstrip. Holds a vector
52 // of WebContentses, and provides an API for adding, removing and
53 // shuffling them, as well as a higher level API for doing specific Browser-
54 // related tasks like adding new Tabs from just a URL, etc.
55 //
56 // Each tab may be pinned. Pinned tabs are locked to the left side of the tab
57 // strip and rendered differently (small tabs with only a favicon). The model
58 // makes sure all pinned tabs are at the beginning of the tab strip. For
59 // example, if a non-pinned tab is added it is forced to be with non-pinned
60 // tabs. Requests to move tabs outside the range of the tab type are ignored.
61 // For example, a request to move a pinned tab after non-pinned tabs is ignored.
62 //
63 // A TabStripModel has one delegate that it relies on to perform certain tasks
64 // like creating new TabStripModels (probably hosted in Browser windows) when
65 // required. See TabStripDelegate above for more information.
66 //
67 // A TabStripModel also has N observers (see TabStripModelObserver above),
68 // which can be registered via Add/RemoveObserver. An Observer is notified of
69 // tab creations, removals, moves, and other interesting events. The
70 // TabStrip implements this interface to know when to create new tabs in
71 // the View, and the Browser object likewise implements to be able to update
72 // its bookkeeping when such events happen.
73 //
74 // This implementation of TabStripModel is not thread-safe and should only be
75 // accessed on the UI thread.
76 //
77 ////////////////////////////////////////////////////////////////////////////////
78 class TabStripModel : public TabGroupController {
79  public:
80   // Used to specify what should happen when the tab is closed.
81   enum CloseTypes {
82     CLOSE_NONE                     = 0,
83 
84     // Indicates the tab was closed by the user. If true,
85     // WebContents::SetClosedByUserGesture(true) is invoked.
86     CLOSE_USER_GESTURE             = 1 << 0,
87 
88     // If true the history is recorded so that the tab can be reopened later.
89     // You almost always want to set this.
90     CLOSE_CREATE_HISTORICAL_TAB    = 1 << 1,
91   };
92 
93   // Constants used when adding tabs.
94   enum AddTabTypes {
95     // Used to indicate nothing special should happen to the newly inserted tab.
96     ADD_NONE = 0,
97 
98     // The tab should be active.
99     ADD_ACTIVE = 1 << 0,
100 
101     // The tab should be pinned.
102     ADD_PINNED = 1 << 1,
103 
104     // If not set the insertion index of the WebContents is left up to the Order
105     // Controller associated, so the final insertion index may differ from the
106     // specified index. Otherwise the index supplied is used.
107     ADD_FORCE_INDEX = 1 << 2,
108 
109     // If set the newly inserted tab's opener is set to the active tab. If not
110     // set the tab may still inherit the opener under certain situations.
111     ADD_INHERIT_OPENER = 1 << 3,
112   };
113 
114   // Enumerates different ways to open a new tab. Does not apply to opening
115   // existing links or searches in a new tab, only to brand new empty tabs.
116   // KEEP IN SYNC WITH THE NewTabType ENUM IN enums.xml.
117   // NEW VALUES MUST BE APPENDED AND AVOID CHANGING ANY PRE-EXISTING VALUES.
118   enum NewTab {
119     // New tab was opened using the new tab button on the tab strip.
120     NEW_TAB_BUTTON = 0,
121 
122     // New tab was opened using the menu command - either through the keyboard
123     // shortcut, or by opening the menu and selecting the command. Applies to
124     // both app menu and the menu bar's File menu (on platforms that have one).
125     NEW_TAB_COMMAND = 1,
126 
127     // New tab was opened through the context menu on the tab strip.
128     NEW_TAB_CONTEXT_MENU = 2,
129 
130     // New tab was opened through the new tab button in the toolbar for the
131     // WebUI touch-optimized tab strip.
132     NEW_TAB_BUTTON_IN_TOOLBAR_FOR_TOUCH = 3,
133 
134     // New tab was opened through the new tab button inside of the WebUI tab
135     // strip.
136     NEW_TAB_BUTTON_IN_WEBUI_TAB_STRIP = 4,
137 
138     // Number of enum entries, used for UMA histogram reporting macros.
139     NEW_TAB_ENUM_COUNT = 5,
140   };
141 
142   static constexpr int kNoTab = -1;
143 
144   // Construct a TabStripModel with a delegate to help it do certain things
145   // (see the TabStripModelDelegate documentation). |delegate| cannot be NULL.
146   explicit TabStripModel(TabStripModelDelegate* delegate, Profile* profile);
147   ~TabStripModel() override;
148 
149   // Retrieves the TabStripModelDelegate associated with this TabStripModel.
delegate()150   TabStripModelDelegate* delegate() const { return delegate_; }
151 
152   // Sets the TabStripModelObserver used by the UI showing the tabs. As other
153   // observers may query the UI for state, the UI's observer must be first.
154   void SetTabStripUI(TabStripModelObserver* observer);
155 
156   // Add and remove observers to changes within this TabStripModel.
157   void AddObserver(TabStripModelObserver* observer);
158   void RemoveObserver(TabStripModelObserver* observer);
159 
160   // Retrieve the number of WebContentses/emptiness of the TabStripModel.
count()161   int count() const { return static_cast<int>(contents_data_.size()); }
empty()162   bool empty() const { return contents_data_.empty(); }
163 
164   // Retrieve the Profile associated with this TabStripModel.
profile()165   Profile* profile() const { return profile_; }
166 
167   // Retrieve the index of the currently active WebContents. This will be
168   // ui::ListSelectionModel::kUnselectedIndex if no tab is currently selected
169   // (this happens while the tab strip is being initialized or is empty).
active_index()170   int active_index() const { return selection_model_.active(); }
171 
172   // Returns true if the tabstrip is currently closing all open tabs (via a
173   // call to CloseAllTabs). As tabs close, the selection in the tabstrip
174   // changes which notifies observers, which can use this as an optimization to
175   // avoid doing meaningless or unhelpful work.
closing_all()176   bool closing_all() const { return closing_all_; }
177 
178   // Basic API /////////////////////////////////////////////////////////////////
179 
180   // Determines if the specified index is contained within the TabStripModel.
181   bool ContainsIndex(int index) const;
182 
183   // Adds the specified WebContents in the default location. Tabs opened
184   // in the foreground inherit the opener of the previously active tab.
185   void AppendWebContents(std::unique_ptr<content::WebContents> contents,
186                          bool foreground);
187 
188   // Adds the specified WebContents at the specified location.
189   // |add_types| is a bitmask of AddTabTypes; see it for details.
190   //
191   // All append/insert methods end up in this method.
192   //
193   // NOTE: adding a tab using this method does NOT query the order controller,
194   // as such the ADD_FORCE_INDEX AddTabTypes is meaningless here. The only time
195   // the |index| is changed is if using the index would result in breaking the
196   // constraint that all pinned tabs occur before non-pinned tabs. It returns
197   // the index the web contents is actually inserted to. See also
198   // AddWebContents.
199   int InsertWebContentsAt(
200       int index,
201       std::unique_ptr<content::WebContents> contents,
202       int add_types,
203       base::Optional<tab_groups::TabGroupId> group = base::nullopt);
204   // Closes the WebContents at the specified index. This causes the
205   // WebContents to be destroyed, but it may not happen immediately.
206   // |close_types| is a bitmask of CloseTypes. Returns true if the
207   // WebContents was closed immediately, false if it was not closed (we
208   // may be waiting for a response from an onunload handler, or waiting for the
209   // user to confirm closure).
210   bool CloseWebContentsAt(int index, uint32_t close_types);
211 
212   // Replaces the WebContents at |index| with |new_contents|. The
213   // WebContents that was at |index| is returned and its ownership returns
214   // to the caller.
215   std::unique_ptr<content::WebContents> ReplaceWebContentsAt(
216       int index,
217       std::unique_ptr<content::WebContents> new_contents);
218 
219   // Detaches the WebContents at the specified index from this strip. The
220   // WebContents is not destroyed, just removed from display. The caller
221   // is responsible for doing something with it (e.g. stuffing it into another
222   // strip). Returns the detached WebContents.
223   std::unique_ptr<content::WebContents> DetachWebContentsAt(int index);
224 
225   // User gesture type that triggers ActivateTabAt. kNone indicates that it was
226   // not triggered by a user gesture, but by a by-product of some other action.
227   enum class GestureType {
228     kMouse,
229     kTouch,
230     kWheel,
231     kKeyboard,
232     kOther,
233     kTabMenu,
234     kNone
235   };
236 
237   // Encapsulates user gesture information for tab activation
238   struct UserGestureDetails {
239     UserGestureDetails(GestureType type,
240                        base::TimeTicks time_stamp = base::TimeTicks::Now())
typeUserGestureDetails241         : type(type), time_stamp(time_stamp) {}
242 
243     GestureType type;
244     base::TimeTicks time_stamp;
245   };
246 
247   // Makes the tab at the specified index the active tab. |gesture_detail.type|
248   // contains the gesture type that triggers the tab activation.
249   // |gesture_detail.time_stamp| contains the timestamp of the user gesture, if
250   // any.
251   void ActivateTabAt(int index,
252                      UserGestureDetails gesture_detail =
253                          UserGestureDetails(GestureType::kNone));
254 
255   // Report histogram metrics for the number of tabs 'scrubbed' within a given
256   // interval of time. Scrubbing is considered to be a tab activated for <= 1.5
257   // seconds for this metric.
258   void RecordTabScrubbingMetrics();
259 
260   // Move the WebContents at the specified index to another index. This
261   // method does NOT send Detached/Attached notifications, rather it moves the
262   // WebContents inline and sends a Moved notification instead.
263   // EnsureGroupContiguity() is called after the move, so this will never result
264   // in non-contiguous group (though the moved tab's group may change).
265   // If |select_after_move| is false, whatever tab was selected before the move
266   // will still be selected, but its index may have incremented or decremented
267   // one slot. It returns the index the web contents is actually moved to.
268   int MoveWebContentsAt(int index, int to_position, bool select_after_move);
269 
270   // Moves the selected tabs to |index|. |index| is treated as if the tab strip
271   // did not contain any of the selected tabs. For example, if the tabstrip
272   // contains [A b c D E f] (upper case selected) and this is invoked with 1 the
273   // result is [b A D E c f].
274   // This method maintains that all pinned tabs occur before non-pinned tabs.
275   // When pinned tabs are selected the move is processed in two chunks: first
276   // pinned tabs are moved, then non-pinned tabs are moved. If the index is
277   // after (pinned-tab-count - selected-pinned-tab-count), then the index the
278   // non-pinned selected tabs are moved to is (index +
279   // selected-pinned-tab-count). For example, if the model consists of
280   // [A b c D E f] (A b c are pinned) and this is invoked with 2, the result is
281   // [b c A D E f]. In this example nothing special happened because the target
282   // index was <= (pinned-tab-count - selected-pinned-tab-count). If the target
283   // index were 3, then the result would be [b c A f D F]. A, being pinned, can
284   // move no further than index 2. The non-pinned tabs are moved to the target
285   // index + selected-pinned tab-count (3 + 1).
286   void MoveSelectedTabsTo(int index);
287 
288   // Moves all tabs in |group| to |to_index|. This has no checks to make sure
289   // the position is valid for a group to move to.
290   void MoveGroupTo(const tab_groups::TabGroupId& group, int to_index);
291 
292   // Returns the currently active WebContents, or NULL if there is none.
293   content::WebContents* GetActiveWebContents() const;
294 
295   // Returns the WebContents at the specified index, or NULL if there is
296   // none.
297   content::WebContents* GetWebContentsAt(int index) const override;
298 
299   // Returns the index of the specified WebContents, or TabStripModel::kNoTab
300   // if the WebContents is not in this TabStripModel.
301   int GetIndexOfWebContents(const content::WebContents* contents) const;
302 
303   // Notify any observers that the WebContents at the specified index has
304   // changed in some way. See TabChangeType for details of |change_type|.
305   void UpdateWebContentsStateAt(int index, TabChangeType change_type);
306 
307   // Cause a tab to display a UI indication to the user that it needs their
308   // attention.
309   void SetTabNeedsAttentionAt(int index, bool attention);
310 
311   // Close all tabs at once. Code can use closing_all() above to defer
312   // operations that might otherwise by invoked by the flurry of detach/select
313   // notifications this method causes.
314   void CloseAllTabs();
315 
316   // Returns true if there are any WebContentses that are currently loading.
317   bool TabsAreLoading() const;
318 
319   // Returns the WebContents that opened the WebContents at |index|, or NULL if
320   // there is no opener on record.
321   content::WebContents* GetOpenerOfWebContentsAt(int index);
322 
323   // Changes the |opener| of the WebContents at |index|.
324   // Note: |opener| must be in this tab strip. Also a tab must not be its own
325   // opener.
326   void SetOpenerOfWebContentsAt(int index, content::WebContents* opener);
327 
328   // Returns the index of the last WebContents in the model opened by the
329   // specified opener, starting at |start_index|.
330   int GetIndexOfLastWebContentsOpenedBy(const content::WebContents* opener,
331                                         int start_index) const;
332 
333   // To be called when a navigation is about to occur in the specified
334   // WebContents. Depending on the tab, and the transition type of the
335   // navigation, the TabStripModel may adjust its selection behavior and opener
336   // inheritance.
337   void TabNavigating(content::WebContents* contents,
338                      ui::PageTransition transition);
339 
340   // Changes the blocked state of the tab at |index|.
341   void SetTabBlocked(int index, bool blocked);
342 
343   // Changes the pinned state of the tab at |index|. See description above
344   // class for details on this.
345   void SetTabPinned(int index, bool pinned);
346 
347   // Returns true if the tab at |index| is pinned.
348   // See description above class for details on pinned tabs.
349   bool IsTabPinned(int index) const;
350 
351   bool IsTabCollapsed(int index) const;
352 
353   bool IsGroupCollapsed(const tab_groups::TabGroupId& group) const;
354 
355   // Returns true if the tab at |index| is blocked by a tab modal dialog.
356   bool IsTabBlocked(int index) const;
357 
358   // Returns the group that contains the tab at |index|, or nullopt if the tab
359   // index is invalid or not grouped.
360   base::Optional<tab_groups::TabGroupId> GetTabGroupForTab(
361       int index) const override;
362 
363   // If a tab inserted at |index| would be within a tab group, return that
364   // group's ID. Otherwise, return nullopt. If |index| points to the first tab
365   // in a group, it will return nullopt since a new tab would be either between
366   // two different groups or just after a non-grouped tab.
367   base::Optional<tab_groups::TabGroupId> GetSurroundingTabGroup(
368       int index) const;
369 
370   // Returns the index of the first tab that is not a pinned tab. This returns
371   // |count()| if all of the tabs are pinned tabs, and 0 if none of the tabs are
372   // pinned tabs.
373   int IndexOfFirstNonPinnedTab() const;
374 
375   // Extends the selection from the anchor to |index|.
376   void ExtendSelectionTo(int index);
377 
378   // Toggles the selection at |index|. This does nothing if |index| is selected
379   // and there are no other selected tabs.
380   void ToggleSelectionAt(int index);
381 
382   // Makes sure the tabs from the anchor to |index| are selected. This only
383   // adds to the selection.
384   void AddSelectionFromAnchorTo(int index);
385 
386   // Returns true if the tab at |index| is selected.
387   bool IsTabSelected(int index) const;
388 
389   // Sets the selection to match that of |source|.
390   void SetSelectionFromModel(ui::ListSelectionModel source);
391 
392   const ui::ListSelectionModel& selection_model() const;
393 
394   // Command level API /////////////////////////////////////////////////////////
395 
396   // Adds a WebContents at the best position in the TabStripModel given
397   // the specified insertion index, transition, etc. |add_types| is a bitmask of
398   // AddTabTypes; see it for details. This method ends up calling into
399   // InsertWebContentsAt to do the actual insertion. Pass kNoTab for |index| to
400   // append the contents to the end of the tab strip.
401   void AddWebContents(
402       std::unique_ptr<content::WebContents> contents,
403       int index,
404       ui::PageTransition transition,
405       int add_types,
406       base::Optional<tab_groups::TabGroupId> group = base::nullopt);
407 
408   // Closes the selected tabs.
409   void CloseSelectedTabs();
410 
411   // Select adjacent tabs
412   void SelectNextTab(
413       UserGestureDetails detail = UserGestureDetails(GestureType::kOther));
414   void SelectPreviousTab(
415       UserGestureDetails detail = UserGestureDetails(GestureType::kOther));
416 
417   // Selects the last tab in the tab strip.
418   void SelectLastTab(
419       UserGestureDetails detail = UserGestureDetails(GestureType::kOther));
420 
421   // Moves the active in the specified direction. Respects group boundaries.
422   void MoveTabNext();
423   void MoveTabPrevious();
424 
425   // Create a new tab group and add the set of tabs pointed to be |indices| to
426   // it. Pins all of the tabs if any of them were pinned, and reorders the tabs
427   // so they are contiguous and do not split an existing group in half. Returns
428   // the new group. |indices| must be sorted in ascending order.
429   tab_groups::TabGroupId AddToNewGroup(const std::vector<int>& indices);
430 
431   // Add the set of tabs pointed to by |indices| to the given tab group |group|.
432   // The tabs take on the pinnedness of the tabs already in the group, and are
433   // moved to immediately follow the tabs already in the group. |indices| must
434   // be sorted in ascending order.
435   void AddToExistingGroup(const std::vector<int>& indices,
436                           const tab_groups::TabGroupId& group);
437 
438   // Moves the set of tabs indicated by |indices| to precede the tab at index
439   // |destination_index|, maintaining their order and the order of tabs not
440   // being moved, and adds them to the tab group |group|.
441   void MoveTabsAndSetGroup(const std::vector<int>& indices,
442                            int destination_index,
443                            base::Optional<tab_groups::TabGroupId> group);
444 
445   // Similar to AddToExistingGroup(), but creates a group with id |group| if it
446   // doesn't exist. This is only intended to be called from session restore
447   // code.
448   void AddToGroupForRestore(const std::vector<int>& indices,
449                             const tab_groups::TabGroupId& group);
450 
451   // Updates the tab group of the tab at |index|. If |group| is nullopt, the tab
452   // will be removed from the current group. If |group| does not exist, it will
453   // create the group then add the tab to the group.
454   void UpdateGroupForDragRevert(
455       int index,
456       base::Optional<tab_groups::TabGroupId> group_id,
457       base::Optional<tab_groups::TabGroupVisualData> group_data);
458 
459   // Removes the set of tabs pointed to by |indices| from the the groups they
460   // are in, if any. The tabs are moved out of the group if necessary. |indices|
461   // must be sorted in ascending order.
462   void RemoveFromGroup(const std::vector<int>& indices);
463 
group_model()464   TabGroupModel* group_model() const { return group_model_.get(); }
465 
466   // Returns true if one or more of the tabs pointed to by |indices| are
467   // supported by read later.
468   bool IsReadLaterSupportedForAny(const std::vector<int> indices);
469 
470   // Saves tabs with url supported by Read Later.
471   void AddToReadLater(const std::vector<int>& indices);
472 
473   // TabGroupController:
474   void CreateTabGroup(const tab_groups::TabGroupId& group) override;
475   void OpenTabGroupEditor(const tab_groups::TabGroupId& group) override;
476   void ChangeTabGroupContents(const tab_groups::TabGroupId& group) override;
477   void ChangeTabGroupVisuals(const tab_groups::TabGroupId& group) override;
478   void MoveTabGroup(const tab_groups::TabGroupId& group) override;
479   void CloseTabGroup(const tab_groups::TabGroupId& group) override;
480   // The same as count(), but overridden for TabGroup to access.
481   int GetTabCount() const override;
482 
483   // View API //////////////////////////////////////////////////////////////////
484 
485   // Context menu functions. Tab groups uses command ids following CommandLast
486   // for entries in the 'Add to existing group' submenu.
487   enum ContextMenuCommand {
488     CommandFirst,
489     CommandNewTabToRight,
490     CommandReload,
491     CommandDuplicate,
492     CommandCloseTab,
493     CommandCloseOtherTabs,
494     CommandCloseTabsToRight,
495     CommandTogglePinned,
496     CommandToggleGrouped,
497     CommandFocusMode,
498     CommandToggleSiteMuted,
499     CommandSendTabToSelf,
500     CommandSendTabToSelfSingleTarget,
501     CommandAddToReadLater,
502     CommandAddToNewGroup,
503     CommandAddToExistingGroup,
504     CommandRemoveFromGroup,
505     CommandMoveToExistingWindow,
506     CommandMoveTabsToNewWindow,
507     CommandLast
508   };
509 
510   // Returns true if the specified command is enabled. If |context_index| is
511   // selected the response applies to all selected tabs.
512   bool IsContextMenuCommandEnabled(int context_index,
513                                    ContextMenuCommand command_id) const;
514 
515   // Performs the action associated with the specified command for the given
516   // TabStripModel index |context_index|.  If |context_index| is selected the
517   // command applies to all selected tabs.
518   void ExecuteContextMenuCommand(int context_index,
519                                  ContextMenuCommand command_id);
520 
521   // Adds the tab at |context_index| to the given tab group |group|. If
522   // |context_index| is selected the command applies to all selected tabs.
523   void ExecuteAddToExistingGroupCommand(int context_index,
524                                         const tab_groups::TabGroupId& group);
525 
526   // Adds the tab at |context_index| to the browser window at |browser_index|.
527   // If |context_index| is selected the command applies to all selected tabs.
528   void ExecuteAddToExistingWindowCommand(int context_index, int browser_index);
529 
530   // Get the list of existing windows that tabs can be moved to.
531   std::vector<base::string16> GetExistingWindowsForMoveMenu();
532 
533   // Returns true if 'CommandToggleSiteMuted' will mute. |index| is the
534   // index supplied to |ExecuteContextMenuCommand|.
535   bool WillContextMenuMuteSites(int index);
536 
537   // Returns true if 'CommandTogglePinned' will pin. |index| is the index
538   // supplied to |ExecuteContextMenuCommand|.
539   bool WillContextMenuPin(int index);
540 
541   // Returns true if 'CommandToggleGrouped' will group. |index| is the index
542   // supplied to |ExecuteContextMenuCommand|.
543   bool WillContextMenuGroup(int index);
544 
545   // Convert a ContextMenuCommand into a browser command. Returns true if a
546   // corresponding browser command exists, false otherwise.
547   static bool ContextMenuCommandToBrowserCommand(int cmd_id, int* browser_cmd);
548 
549   // Access the order controller. Exposed only for unit tests.
order_controller()550   TabStripModelOrderController* order_controller() const {
551     return order_controller_.get();
552   }
553 
554   // Returns the index of the next WebContents in the sequence of WebContentses
555   // spawned by the specified WebContents after |start_index|.
556   int GetIndexOfNextWebContentsOpenedBy(const content::WebContents* opener,
557                                         int start_index) const;
558 
559   // Finds the next available tab to switch to as the active tab starting at
560   // |index|. This method will check the indices to the right of |index| before
561   // checking the indices to the left of |index|. |index| cannot be returned.
562   // |collapsing_group| is optional and used in cases where the group is
563   // collapsing but not yet reflected in the model. Returns base::nullopt if
564   // there are no valid tabs.
565   base::Optional<int> GetNextExpandedActiveTab(
566       int index,
567       base::Optional<tab_groups::TabGroupId> collapsing_group) const;
568 
569   // Forget all opener relationships, to reduce unpredictable tab switching
570   // behavior in complex session states. The exact circumstances under which
571   // this method is called are left up to TabStripModelOrderController.
572   void ForgetAllOpeners();
573 
574   // Forgets the opener relationship of the specified WebContents.
575   void ForgetOpener(content::WebContents* contents);
576 
577   // Returns true if the opener relationships present for |contents| should be
578   // reset when _any_ active tab change occurs (rather than just one outside the
579   // current tree of openers).
580   bool ShouldResetOpenerOnActiveTabChange(content::WebContents* contents) const;
581 
582  private:
583   FRIEND_TEST_ALL_PREFIXES(TabStripModelTest, GetIndicesClosedByCommand);
584 
585   class WebContentsData;
586   struct DetachedWebContents;
587   struct DetachNotifications;
588 
589   // Performs all the work to detach a WebContents instance but avoids sending
590   // most notifications. TabClosingAt() and TabDetachedAt() are sent because
591   // observers are reliant on the selection model being accurate at the time
592   // that TabDetachedAt() is called.
593   std::unique_ptr<content::WebContents> DetachWebContentsImpl(
594       int index,
595       bool create_historical_tab,
596       bool will_delete);
597 
598   // We batch send notifications. This has two benefits:
599   //   1) This allows us to send the minimal number of necessary notifications.
600   //   This is important because some notifications cause the main thread to
601   //   synchronously communicate with the GPU process and cause jank.
602   //   https://crbug.com/826287.
603   //   2) This allows us to avoid some problems caused by re-entrancy [e.g.
604   //   using destroyed WebContents instances]. Ideally, this second check
605   //   wouldn't be necessary because we would enforce that there is no
606   //   re-entrancy in the TabStripModel, but that condition is currently
607   //   violated in tests [and possibly in the wild as well].
608   void SendDetachWebContentsNotifications(DetachNotifications* notifications);
609 
610   bool RunUnloadListenerBeforeClosing(content::WebContents* contents);
611   bool ShouldRunUnloadListenerBeforeClosing(content::WebContents* contents);
612 
613   int ConstrainInsertionIndex(int index, bool pinned_tab) const;
614 
615   int ConstrainMoveIndex(int index, bool pinned_tab) const;
616 
617   // If |index| is selected all the selected indices are returned, otherwise a
618   // vector with |index| is returned. This is used when executing commands to
619   // determine which indices the command applies to. Indices are sorted in
620   // increasing order.
621   std::vector<int> GetIndicesForCommand(int index) const;
622 
623   // Returns a vector of indices of the tabs that will close when executing the
624   // command |id| for the tab at |index|. The returned indices are sorted in
625   // descending order.
626   std::vector<int> GetIndicesClosedByCommand(int index,
627                                              ContextMenuCommand id) const;
628 
629   // Returns true if the specified WebContents is a New Tab at the end of
630   // the tabstrip. We check for this because opener relationships are _not_
631   // forgotten for the New Tab page opened as a result of a New Tab gesture
632   // (e.g. Ctrl+T, etc) since the user may open a tab transiently to look up
633   // something related to their current activity.
634   bool IsNewTabAtEndOfTabStrip(content::WebContents* contents) const;
635 
636   // Adds the specified WebContents at the specified location.
637   // |add_types| is a bitmask of AddTabTypes; see it for details.
638   //
639   // All append/insert methods end up in this method.
640   //
641   // NOTE: adding a tab using this method does NOT query the order controller,
642   // as such the ADD_FORCE_INDEX AddTabTypes is meaningless here. The only time
643   // the |index| is changed is if using the index would result in breaking the
644   // constraint that all pinned tabs occur before non-pinned tabs. It returns
645   // the index the web contents is actually inserted to. See also
646   // AddWebContents.
647   int InsertWebContentsAtImpl(int index,
648                               std::unique_ptr<content::WebContents> contents,
649                               int add_types,
650                               base::Optional<tab_groups::TabGroupId> group);
651 
652   // Closes the WebContentses at the specified indices. This causes the
653   // WebContentses to be destroyed, but it may not happen immediately. If
654   // the page in question has an unload event the WebContents will not be
655   // destroyed until after the event has completed, which will then call back
656   // into this method.
657   //
658   // Returns true if the WebContentses were closed immediately, false if we
659   // are waiting for the result of an onunload handler.
660   bool InternalCloseTabs(base::span<content::WebContents* const> items,
661                          uint32_t close_types);
662 
663   // |close_types| is a bitmask of the types in CloseTypes.
664   // Returns true if all the tabs have been deleted. A return value of false
665   // means some portion (potentially none) of the WebContents were deleted.
666   // WebContents not deleted by this function are processing unload handlers
667   // which may eventually be deleted based on the results of the unload handler.
668   // Additionally processing the unload handlers may result in needing to show
669   // UI for the WebContents. See UnloadController for details on how unload
670   // handlers are processed.
671   bool CloseWebContentses(base::span<content::WebContents* const> items,
672                           uint32_t close_types);
673 
674   // Gets the WebContents at an index. Does no bounds checking.
675   content::WebContents* GetWebContentsAtImpl(int index) const;
676 
677   // Returns the WebContentses at the specified indices. This does no checking
678   // of the indices, it is assumed they are valid.
679   std::vector<content::WebContents*> GetWebContentsesByIndices(
680       const std::vector<int>& indices);
681 
682   // Sets the selection to |new_model| and notifies any observers.
683   // Note: This function might end up sending 0 to 3 notifications in the
684   // following order: TabDeactivated, ActiveTabChanged, TabSelectionChanged.
685   // |selection| will be filled with information corresponding to 3 notification
686   // above. When it's |triggered_by_other_operation|, This won't notify
687   // observers that selection was changed. Callers should notify it by
688   // themselves.
689   TabStripSelectionChange SetSelection(
690       ui::ListSelectionModel new_model,
691       TabStripModelObserver::ChangeReason reason,
692       bool triggered_by_other_operation);
693 
694   // Selects either the next tab (|forward| is true), or the previous tab
695   // (|forward| is false).
696   void SelectRelativeTab(bool forward, UserGestureDetails detail);
697 
698   // Moves the active tabs into the next slot (|forward| is true), or the
699   // previous slot (|forward| is false). Respects group boundaries and creates
700   // movement slots into and out of groups.
701   void MoveTabRelative(bool forward);
702 
703   // Does the work of MoveWebContentsAt. This has no checks to make sure the
704   // position is valid, those are done in MoveWebContentsAt.
705   void MoveWebContentsAtImpl(int index,
706                              int to_position,
707                              bool select_after_move);
708 
709   // Implementation of MoveSelectedTabsTo. Moves |length| of the selected tabs
710   // starting at |start| to |index|. See MoveSelectedTabsTo for more details.
711   void MoveSelectedTabsToImpl(int index, size_t start, size_t length);
712 
713   // Adds tabs to newly-allocated group id |new_group|. This group must be new
714   // and have no tabs in it.
715   void AddToNewGroupImpl(const std::vector<int>& indices,
716                          const tab_groups::TabGroupId& new_group);
717 
718   // Adds tabs to existing group |group|. This group must have been initialized
719   // by a previous call to |AddToNewGroupImpl()|.
720   void AddToExistingGroupImpl(const std::vector<int>& indices,
721                               const tab_groups::TabGroupId& group);
722 
723   // Implementation of MoveTabsAndSetGroupImpl. Moves the set of tabs in
724   // |indices| to the |destination_index| and updates the tabs to the
725   // appropriate |group|.
726   void MoveTabsAndSetGroupImpl(const std::vector<int>& indices,
727                                int destination_index,
728                                base::Optional<tab_groups::TabGroupId> group);
729 
730   // Moves the tab at |index| to |new_index| and sets its group to |new_group|.
731   // Notifies any observers that group affiliation has changed for the tab.
732   void MoveAndSetGroup(int index,
733                        int new_index,
734                        base::Optional<tab_groups::TabGroupId> new_group);
735 
736   void AddToReadLaterImpl(const std::vector<int>& indices);
737 
738   // Helper function for MoveAndSetGroup. Removes the tab at |index| from the
739   // group that contains it, if any. Also deletes that group, if it now contains
740   // no tabs. Returns that group.
741   base::Optional<tab_groups::TabGroupId> UngroupTab(int index);
742 
743   // Helper function for MoveAndSetGroup. Adds the tab at |index| to |group|.
744   void GroupTab(int index, const tab_groups::TabGroupId& group);
745 
746   // Changes the pinned state of the tab at |index|.
747   void SetTabPinnedImpl(int index, bool pinned);
748 
749   // Ensures all tabs indicated by |indices| are pinned, moving them in the
750   // process if necessary. Returns the new locations of all of those tabs.
751   std::vector<int> SetTabsPinned(const std::vector<int>& indices, bool pinned);
752 
753   // Sets the sound content setting for each site at the |indices|.
754   void SetSitesMuted(const std::vector<int>& indices, bool mute) const;
755 
756   // Sets the opener of any tabs that reference the tab at |index| to that tab's
757   // opener or null if there's a cycle.
758   void FixOpeners(int index);
759 
760   // Makes sure the tab at |index| is not causing a group contiguity error. Will
761   // make the minimum change to ensure that the tab's group is not non-
762   // contiguous as well as ensuring that it is not breaking up a non-contiguous
763   // group, possibly by setting or clearing its group.
764   void EnsureGroupContiguity(int index);
765 
766   // The WebContents data currently hosted within this TabStripModel. This must
767   // be kept in sync with |selection_model_|.
768   std::vector<std::unique_ptr<WebContentsData>> contents_data_;
769 
770   // The model for tab groups hosted within this TabStripModel.
771   std::unique_ptr<TabGroupModel> group_model_;
772 
773   TabStripModelDelegate* delegate_;
774 
775   bool tab_strip_ui_was_set_ = false;
776 
777   base::ObserverList<TabStripModelObserver>::Unchecked observers_;
778 
779   // A profile associated with this TabStripModel.
780   Profile* profile_;
781 
782   // True if all tabs are currently being closed via CloseAllTabs.
783   bool closing_all_ = false;
784 
785   // An object that determines where new Tabs should be inserted and where
786   // selection should move when a Tab is closed.
787   std::unique_ptr<TabStripModelOrderController> order_controller_;
788 
789   // This must be kept in sync with |contents_data_|.
790   ui::ListSelectionModel selection_model_;
791 
792   // TabStripModel is not re-entrancy safe. This member is used to guard public
793   // methods that mutate state of |selection_model_| or |contents_data_|.
794   bool reentrancy_guard_ = false;
795 
796   // A recorder for recording tab switching input latency to UMA
797   TabSwitchEventLatencyRecorder tab_switch_event_latency_recorder_;
798 
799   // Timer used to mark intervals for metric collection on how many tabs are
800   // scrubbed over a certain interval of time.
801   base::RepeatingTimer tab_scrubbing_interval_timer_;
802   // Timestamp marking the last time a tab was activated by mouse press. This is
803   // used in determining how long a tab was active for metrics.
804   base::TimeTicks last_tab_switch_timestamp_ = base::TimeTicks();
805   // Counter used to keep track of tab scrubs during intervals set by
806   // |tab_scrubbing_interval_timer_|.
807   size_t tabs_scrubbed_by_mouse_press_count_ = 0;
808   // Counter used to keep track of tab scrubs during intervals set by
809   // |tab_scrubbing_interval_timer_|.
810   size_t tabs_scrubbed_by_key_press_count_ = 0;
811 
812   base::WeakPtrFactory<TabStripModel> weak_factory_{this};
813 
814   DISALLOW_IMPLICIT_CONSTRUCTORS(TabStripModel);
815 };
816 
817 // Forbid construction of ScopedObserver with TabStripModel:
818 // TabStripModelObserver already implements ScopedObserver's functionality
819 // natively.
820 template <>
821 class ScopedObserver<TabStripModel, TabStripModelObserver> {
822  public:
823   // Deleting the constructor gives a clear error message traceable back to here.
824   explicit ScopedObserver(TabStripModelObserver* observer) = delete;
825 };
826 
827 #endif  // CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_
828