New issue
Advanced search Search tips

Issue 826287 link

Starred by 4 users

Issue metadata

Status: Fixed
Owner:
Closed: May 2018
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Mac
Pri: 1
Type: Bug



Sign in to add a comment

MacViewsBrowser: Closing a window is über-janky

Project Member Reported by rsesek@chromium.org, Mar 27 2018

Issue description

Chrome Version: 67.0.3381.0
OS: macOS 10.13.3

What steps will reproduce the problem?
(1) --enable-features=ViewsBrowserWindows
(2) Open a new window with lots of tabs
(3) Close the window

What is the expected result?
The window closes quickly.

What happens instead?
The window cycles through each tab before it actually closes.

Please use labels and text to provide additional information.


For graphics-related bugs, please copy/paste the contents of the about:gpu
page at the end of this report.

 
close-window-jank.mov
496 KB View Download
Labels: M-68 Target-68
Owner: erikc...@chromium.org
Status: Assigned (was: Untriaged)
MacViews triage: targeting for M68.

Comment 2 by gov...@chromium.org, Mar 29 2018

** Bulk Edit **

FYI: Starting 04/13 M68 will be in canary, M68 Dev promotion will be on 04/26.

Grabbed a sample.

Looks like we're doing a lot of unnecessary layout in either InfoBarContainer::ChangeInfoBarManager or BrowserView::ToolbarSizeChanged or BrowserView::MaybeShowBookmarkBar.

"""
   + !                         :             | +   !           : |       + !       : 1113 TabStripModel::InternalCloseTabs(base::span<content::WebContents* const>, unsigned int)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x464a39f  [tab_strip_model.cc:1151]
    + !                         :             | +   !           : |       + !       :   1040 CloseWebContentses(WebContentsCloseDelegate*, base::span<content::WebContents* const>, unsigned int)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x4650098  [vector:639]
    + !                         :             | +   !           : |       + !       :   | 1040 <name omitted>  (in Google Chrome Framework)  load address 0x1012c0000 + 0xe0aafe  [web_contents_impl.cc:546]
    + !                         :             | +   !           : |       + !       :   |   1030 content::WebContentsImpl::~WebContentsImpl()  (in Google Chrome Framework)  load address 0x1012c0000 + 0xe0a231  [weak_ptr.h:243]
    + !                         :             | +   !           : |       + !       :   |   + 991 TabStripModel::DetachWebContentsAt(int)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x4647e26  [tab_strip_model.cc:321]
    + !                         :             | +   !           : |       + !       :   |   + ! 991 TabStripModel::NotifyIfActiveTabChanged(content::WebContents*, TabStripModel::Notify)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x46494ff  [weak_ptr.h:243]
    + !                         :             | +   !           : |       + !       :   |   + !   882 Browser::ActiveTabChanged(content::WebContents*, content::WebContents*, int, int)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x460989e  [memory:2603]
    + !                         :             | +   !           : |       + !       :   |   + !   : 712 BrowserView::OnActiveTabChanged(content::WebContents*, content::WebContents*, int, int)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x48b18c7  [browser_view.cc:2437]
    + !                         :             | +   !           : |       + !       :   |   + !   : | 712 infobars::InfoBarContainer::ChangeInfoBarManager(infobars::InfoBarManager*)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x39e3602  [vector:633]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   698 BrowserView::ToolbarSizeChanged(bool)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x48b2366  [browser_view.cc:2442]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + 674 BrowserView::MaybeShowBookmarkBar(content::WebContents*)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x48b12c4  [browser_view.cc:0]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! 672 views::View::AddChildViewAt(views::View*, int)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x38dfdf5  [view.cc:2724]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! : 672 views::View::PropagateAddNotifications(views::View::ViewHierarchyChangedDetails const&, bool)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x38e0da7  [view.cc:2168]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :   672 views::View::ViewHierarchyChangedImpl(bool, views::View::ViewHierarchyChangedDetails const&)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x38e0ce5  [view.cc:2197]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :     672 BookmarkBarView::ViewHierarchyChanged(views::View::ViewHierarchyChangedDetails const&)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x4892653  [bookmark_bar_view.cc:1026]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :       672 BookmarkBarView::UpdateAppearanceForTheme()  (in Google Chrome Framework)  load address 0x1012c0000 + 0x48926f2  [bookmark_bar_view.cc:2052]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         557 BookmarkBarView::ConfigureButton(bookmarks::BookmarkNode const*, views::LabelButton*)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x48956c4  [view.h:562]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         | 557 views::View::NotifyAccessibilityEvent(ax::mojom::Event, bool)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x38e2cb2  [view.cc:1461]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         |   557 views::NativeViewAccessibilityBase::NotifyAccessibilityEvent(ax::mojom::Event)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x38fe927  [native_view_accessibility_base.cc:141]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         |     557 ui::AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x338c401  [ax_platform_node_mac.mm:870]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         |       557 non-virtual thunk to views::NativeViewAccessibilityBase::GetData() const  (in Google Chrome Framework)  load address 0x1012c0000 + 0x38fed30  [native_view_accessibility_base.cc:0]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         |         557 views::NativeViewAccessibilityBase::GetData() const  (in Google Chrome Framework)  load address 0x1012c0000 + 0x38feca8  [view_accessibility.h:67]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         |           555 views::ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData*) const  (in Google Chrome Framework)  load address 0x1012c0000 + 0x3869ffa  [view_accessibility.cc:78]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         |           + 555 (anonymous namespace)::BookmarkButton::GetTooltipText(gfx::Point const&, std::__1::basic_string<unsigned short, base::string16_internals::string16_char_traits, std::__1::allocator<unsigned short> >*) const  (in Google Chrome Framework)  load address 0x1012c0000 + 0x4897a1e  [string:2884]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         |           +   530 BookmarkBarView::CreateToolTipForURLAndTitle(int, gfx::FontList const&, GURL const&, std::__1::basic_string<unsigned short, base::string16_internals::string16_char_traits, std::__1::allocator<unsigned short> > const&)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x4891b68  [bookmark_bar_view.cc:788]
    + !                         :             | +   !           : |       + !       :   |   + !   : |   + ! :         |           +   ! 115 url_formatter::ElideUrl(GURL const&, gfx::FontList const&, float, gfx::Typesetter)  (in Google Chrome Framework)  load address 0x1012c0000 + 0x355e363  [elide_url.cc:176]

"""
sample.rtf
2.6 MB Download
Project Member

Comment 4 by bugdroid1@chromium.org, Mar 31 2018

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/df82d0ab2a5e7e59a446f3c925d21ce992b18046

commit df82d0ab2a5e7e59a446f3c925d21ce992b18046
Author: erikchen <erikchen@chromium.org>
Date: Sat Mar 31 00:44:51 2018

Don't relayout InfobarContainer if there are no changes.

When closing a Window on MacViews, this logic would needlessly trigger relayouts
for every tab close, causing massive jank.

Bug:  826287 
Change-Id: I30bac1e8c12eb16305be8c7630082adbeae54c6d
Reviewed-on: https://chromium-review.googlesource.com/988853
Reviewed-by: Erik Chen <erikchen@chromium.org>
Reviewed-by: Peter Kasting <pkasting@chromium.org>
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#547339}
[modify] https://crrev.com/df82d0ab2a5e7e59a446f3c925d21ce992b18046/components/infobars/core/infobar_container.cc

Cc: vamshi.kommuri@chromium.org
Labels: Needs-Feedback
We are unable to verify the fix on 67.0.3386.0 Using Mac 10.13.1 i.e., we are able to see window cycling through each tab before it's actually closed.

@erikchen: Could you please let us know if there are any fixes to be landed.

Thanks!
Status: Started (was: Assigned)
The behavior is better than before but there are still improvements to be made. Here's the relevant sample from latest Canary:

"""
   +                                                                               2301 TabStripModel::CloseAllTabs()  (in Google Chrome Framework)  load address 0x10dda1000 + 0x466f3ef  [vector:439]
    +                                                                                 2301 TabStripModel::InternalCloseTabs(base::span<content::WebContents* const>, unsigned int)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x466f5df  [tab_strip_model.cc:1151]
    +                                                                                   2301 CloseWebContentses(WebContentsCloseDelegate*, base::span<content::WebContents* const>, unsigned int)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x46752d8  [vector:639]
    +                                                                                     2301 <name omitted>  (in Google Chrome Framework)  load address 0x10dda1000 + 0xe0d23e  [web_contents_impl.cc:546]
    +                                                                                       2225 content::WebContentsImpl::~WebContentsImpl()  (in Google Chrome Framework)  load address 0x10dda1000 + 0xe0c971  [weak_ptr.h:243]
    +                                                                                       ! 2158 TabStripModel::DetachWebContentsAt(int)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x466d066  [tab_strip_model.cc:321]
    +                                                                                       ! : 2158 TabStripModel::NotifyIfActiveTabChanged(content::WebContents*, TabStripModel::Notify)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x466e73f  [weak_ptr.h:243]
    +                                                                                       ! :   1965 Browser::ActiveTabChanged(content::WebContents*, content::WebContents*, int, int)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x46298ce  [memory:2603]
    +                                                                                       ! :   | 1816 BrowserView::OnActiveTabChanged(content::WebContents*, content::WebContents*, int, int)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x48c3720  [web_contents_user_data.h:47]
    +                                                                                       ! :   | + 1816 views::WebView::SetWebContents(content::WebContents*)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x495b9eb  [webview.cc:366]
    +                                                                                       ! :   | +   1809 views::WebView::AttachWebContents()  (in Google Chrome Framework)  load address 0x10dda1000 + 0x495c499  [webview.cc:319]
    +                                                                                       ! :   | +   ! 1804 views::NativeViewHost::Attach(NSView*)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x38d0bdd  [native_view_host.cc:42]
    +                                                                                       ! :   | +   ! : 1804 views::NativeViewHost::Layout()  (in Google Chrome Framework)  load address 0x10dda1000 + 0x38d0de2  [native_view_host.cc:117]
    +                                                                                       ! :   | +   ! :   1804 views::NativeViewHostMac::ShowWidget(int, int, int, int, int, int)  (in Google Chrome Framework)  load address 0x10dda1000 + 0x38d1634  [native_view_host_mac.mm:140]
    +                                                                                       ! :   | +   ! :     1804 -[NSView(NSInternal) _setHidden:setNeedsDisplay:]  (in AppKit) + 326  [0x7fff2c3b6aa1]
    +                                                                                       ! :   | +   ! :       1803 -[NSView _recursiveLostHiddenAncestor]  (in AppKit) + 127  [0x7fff2c43dc59]
    +                                                                                       ! :   | +   ! :       | 1803 content::WebContentsImpl::WasShown()  (in Google Chrome Framework)  load address 0x10dda1000 + 0xe14535  [web_contents_impl.cc:1502]
    +                                                                                       ! :   | +   ! :       |   1799 content::RenderWidgetHostViewMac::Show()  (in Google Chrome Framework)  load address 0x10dda1000 + 0xd3a0bd  [memory:2603]
    +                                                                                       ! :   | +   ! :       |   + 1799 content::RenderWidgetHostImpl::PauseForPendingResizeOrRepaints()  (in Google Chrome Framework)  load address 0x10dda1000 + 
"""

Each time we are closing a tab, the destructor of WebContentsImpl is calling back into TabStripModel, which in turns needs to redraw the entire window + web contents. Updating the web contents synchronously waits for the GPU process to draw + update before returning, thus causing the observed behavior.
Cc: ellyjo...@chromium.org pkasting@chromium.org sky@chromium.org
+ sky, pkasting, ellyjones [as a subset of you will need to review the CL].

The root problem is that TabStripModel::InternalCloseTabs sends the ActiveTabChanged notification for every tab that is going to be closed. This results in a full layout/paint of both the browser and web contents. Painting web contents will synchronously block the browser main thread waiting for the GPU process.

Solution 1:
When closing multiple tabs, TabStripModel should send the minimal number of notifications necessary for correctness. e.g. If there are 5 tabs [numbered 1 through 5], and if we are trying to close 3, 4, and 5, then there should be a single ActiveTabChanged notification, indicating a switch from 5->2, rather than 3 notifications for: 5->4, 4->3 and 3->2.

Solution 2:
Add additional state that indicates that TabStripModel is batch closing tabs [or equivalent]. Expose this state to consumers of ActiveTabChanged notifications, and have them do less work. [e.g. redraw tab strip but not web contents].

Solution (2) allows for more custom behaviors at the expense of additional complexity. Solution (1) is simple and gets the job done. I prefer Solution (1). 
#7:

(1) sounds best to me, especially if closing all the tabs means we send zero ActiveTabChanged notifications :). I don't like (2) but I think it's similar to what the existing Cocoa code does with "rapid tab closure".
The correct solution will look something like this:

1) Figure out the tabs that are going to be closed. 
2) Send the minimal set of notifications that is still correct.
3) Perform the closes [delete WebContents, update internal state of the TabStripModel - WebContentsData].

(3) must follow (2) because the notifications include raw WebContents pointers to the WebContents that is about to be deleted/removed from the tab strip.

Unfortunately, the current logic is slightly broken. 

a) CloseWebContentses deletes the WebContents
b) Half way through the destructor of WebContents, TabStripModel gets an observer notification.
c) TabStripModel calls TabStripModel::DetachWebContentsAt to update internal state, and send notifications, using a half destructed WebContents.

The reason that (b) and (c) are inverted is that TabStripModel is trying to react to someone else deleting the WebContents out from under it. This is due to confusion in ownership semantics - who exactly owns the WebContents in the TabStripModel?

The public APIs all claim that the TabStripModel take ownership of the WebContents, so that's a good sign. There are two problems:
i) As indicated before, TabStripModel's implementation seems uncertain about ownership semantics.
ii) The destructor of TabStripModel does not destroy the WebContents it owns.

I've got a CL in progress which checks (i) - specifically, checking that no one is attempting to delete a WebContents out from under the TabStripModel: https://chromium-review.googlesource.com/c/chromium/src/+/1010521

Assuming that works out, I will fix TabStripModel to assume explicit ownership of the WebContents. I guess fixing (ii) in the process.


Labels: Sprint-1
Pls mark the bug as fixed if CL is landed in trunk and nothing else is pending. Thank you.
I've updated all non-test WebContents constructors to return unique_ptrs. I've got CLs in progress to use strong ownership semantics for all non-test consumers of WebContents [none of them are doing anything funky, the CLs are all just refactors to use unique_ptr]. 

GuestViews are the exception. The ownership semantics there are well-understood but difficult to convert to using unique_ptrs. I have a plan to do this, but it's not clear to me how difficult it will be to execute. Regardless, I've confirmed that it has no effect on TabStripModel. Happy to go into details if we deem that appropriate.

I have performed the following steps to confirm that there are no unexpected deletions of WebContents
  1) On macOS, Linux, CrOS, Windows:
  2) Make the destructor of WebContents protected.
  3) Add the statement "friend std::unique_ptr<WebContents>::deleter_type" to WebContents.
  4) Compile chrome


Project Member

Comment 13 by bugdroid1@chromium.org, May 5 2018

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/88ff8d7f13681a78d0bf927e46d1878af059e629

commit 88ff8d7f13681a78d0bf927e46d1878af059e629
Author: Erik Chen <erikchen@chromium.org>
Date: Sat May 05 01:55:31 2018

Move WebContentsCloser back into TabStripModel.

This CL is a refactor with no intended behavior change.

The logic was pulled out in a refactor
[https://chromium-review.googlesource.com/780143] to support the experimental
tab strip model. Since then, the experimental tab strip has been deleted.

Pulling the logic back into TabStripModel is the first step to improving the
performance of TabStripModel::InternalCloseTabs by reducing the number of
unnecessary notifications sent to observers.

Bug:  826287 
Change-Id: I371bd964d8ea6338d50454a0de329a70e5090fae
Reviewed-on: https://chromium-review.googlesource.com/1010642
Commit-Queue: Erik Chen <erikchen@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556289}
[modify] https://crrev.com/88ff8d7f13681a78d0bf927e46d1878af059e629/chrome/browser/ui/BUILD.gn
[modify] https://crrev.com/88ff8d7f13681a78d0bf927e46d1878af059e629/chrome/browser/ui/tabs/tab_strip_model.cc
[modify] https://crrev.com/88ff8d7f13681a78d0bf927e46d1878af059e629/chrome/browser/ui/tabs/tab_strip_model.h
[delete] https://crrev.com/e1b6426ea838e2c0dc2d2b1893c5873cce1e53ac/chrome/browser/ui/tabs/web_contents_closer.cc
[delete] https://crrev.com/e1b6426ea838e2c0dc2d2b1893c5873cce1e53ac/chrome/browser/ui/tabs/web_contents_closer.h

Can this be marked as fixed if nothing else is pending?
There are more CLs coming.
Project Member

Comment 16 by bugdroid1@chromium.org, May 11 2018

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/2969739effcde2fdba105d25d8db903bdfdb5db0

commit 2969739effcde2fdba105d25d8db903bdfdb5db0
Author: erikchen <erikchen@chromium.org>
Date: Fri May 11 16:54:23 2018

Explicit ownership semantics for TabStripModel.

This CL updates TabStripModel's internal implementation to:
  * Use strong ownership semantics for WebContents.
  * Batch tab-removal notifications.

This cannot be broken into two CLs because non-batched removal notifications
required unclear ownership of WebContents. More details to follow.

Previously, closing tabs was not safe for two reasons:
  * TabStripModelObserver callbacks were sending a half-destroyed WebContents
    instance to obsevers, which would then query internal state of the
    WebContents instance.
  * TabStripModelObserver callbacks could cause re-entrancy, which in turn led
    to internal state changes during observer list iteration!

Previous implementation details:
  * TabStripModel would potentially try to close many tabs at once.
  * In a loop [whose iterator would be dynamically modified via WebContents
    observers]
    * TabStripModel would delete the WebContents instance.
    * This triggered TabStripModel's own WebContents destruction observer.
    * Which in turn called TabStripModel::DetachWebContentsAt()
    * Which then sent callbacks to TabStripModel observers using a half-destroyed
      WebContents instance.
      * Some of these observers would then access state on the half-destroyed
        WebContents instance.
      * Other observers would call back into TabStripModel and perform state
        modifications [e.g. remove another tab].

By observing its own WebContents during callbacks to observers, TabStripModel
was able to react to some types of re-entrant behaviors during tab closure [e.g.
closing a tab]. However, it was not able to correctly react to other types of
re-entrant behaviors [e.g. adding a tab].

Furthermore, observers of TabStripModel needed to query internal state of
TabStripModel during observer callbacks. This meant that behavior was dependent
on observer ordering.

e.g. If there are two observers A and B, and A removes tabs on its observer
callback, and B checks for the currently selected index, then the ordering
between A and B will cause behavior differences for B.

This CL fixes both of these issues. Closing tabs now looks like this:
  * TabStripModel will potentially try to close many tabs at once.
  * TabStripModel updates its internal state to reflect this change. It is now
    in an internally consistent state [in case of re-entrancy from observers].
  * For each tab that was removed:
    * TabStripModel dispatches observer callbacks.
    * TabStripModel deletes the WebContents.

WebContents deletion now happens after observer callbacks, so there are no
issues with half-destroyed WebContents instances.

Tab closure is now re-entrant safe, since internal state is consistent before
sending any observer callbacks, and observer callbacks are not affected by
changing internal state.

This CL discovered several issues:
  * Several tests suites were failing to set an active tab before running test
    logic. This meant that they weren't testing real behavior of the
    TabStripModel.
  * Several observers of TabStripModel were relying on assumptions about the
    internal state of the TabStripModel at the time of the observer callback
    [e.g. if a selected tab was detached, then the index of the detached tab in
    TabDetachedAt() is *still* the currently active index of the TabStripModel.]
    This was not robust against earlier observers performing re-entrancy into
    the TabStripModel].
  * Several test suites were deleting WebContents owned by the TabStripModel.
  * Two tests in DetachToBrowserTabDragControllerTest were testing a condition
    that could never occur in the wild. They were testing that the TabStripModel
    behaves correctly if, halfway through a drag when a tab has been detached
    but not attached, the tab is deleted. With strong ownership semantics, the
    only way for a tab to be deleted is through TabStripModel APIs. Which means
    that in the brief period of time when a tab is not attached to any
    TabStripModel, it is not possible for the tab to be deleted. This behavior
    was previously true as well, it's just that it wasn't obvious that this
    condition couldn't occur.
  * Browser::TabClosingAt was unnecessarily calling SetDelegate(). That is also
    called by TabDetachedAtImpl().
  * There are several places in the code that relied on the assumption that the
    TabStripModel WebContentsDestroyed() callbacks would occur before their own
    WebContentsDestroyed() callbacks.

Bug:  826287 
Change-Id: Ia44ad3a405844174407ffddb66e3728bbba44515
Reviewed-on: https://chromium-review.googlesource.com/1045790
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Charlie Harrison <csharrison@chromium.org>
Commit-Queue: Erik Chen <erikchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#557906}
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/metrics/tab_stats_tracker_browsertest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/resource_coordinator/tab_activity_watcher_unittest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/resource_coordinator/tab_manager_unittest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/browser.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/tabs/tab_strip_model.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/tabs/tab_strip_model.h
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/tabs/tab_strip_model_observer.h
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/views/tabs/tab_strip.cc
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/chrome/browser/ui/views/tabs/tab_strip.h
[modify] https://crrev.com/2969739effcde2fdba105d25d8db903bdfdb5db0/components/web_modal/web_contents_modal_dialog_manager.h

Status: Fixed (was: Started)

Sign in to add a comment