mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 06:43:32 +00:00
Bug 1927094 - optimize lineScrollAmount so it doesn't iterate over all tabs, r=mconley,dao
Differential Revision: https://phabricator.services.mozilla.com/D226907
This commit is contained in:
parent
49a0a41b4b
commit
f979fd2d7e
@ -41,6 +41,8 @@
|
||||
|
||||
#maxTabsPerRow;
|
||||
#dragOverCreateGroupTimer;
|
||||
#mustUpdateTabMinHeight = false;
|
||||
#tabMinHeight = 36;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -92,6 +94,18 @@
|
||||
return (!tab.pinned || !arePositioningPinnedTabs()) && tab.visible;
|
||||
};
|
||||
|
||||
// Override for performance reasons. This is the size of a single element
|
||||
// that can be scrolled when using mouse wheel scrolling. If we don't do
|
||||
// this then arrowscrollbox computes this value by calling
|
||||
// _getScrollableElements and dividing the box size by that number.
|
||||
// However in the tabstrip case we already know the answer to this as,
|
||||
// when we're overflowing, it is always the same as the tab min width or
|
||||
// height.
|
||||
Object.defineProperty(this.arrowScrollbox, "lineScrollAmount", {
|
||||
get: () =>
|
||||
this.verticalMode ? this.#tabMinHeight : this._tabMinWidthPref,
|
||||
});
|
||||
|
||||
this.baseConnect();
|
||||
|
||||
this._blockDblClick = false;
|
||||
@ -163,6 +177,7 @@
|
||||
}
|
||||
);
|
||||
this.#updateTabMinWidth(this._tabMinWidthPref);
|
||||
this.#updateTabMinHeight();
|
||||
|
||||
CustomizableUI.addListener(this);
|
||||
this._updateNewTabVisibility();
|
||||
@ -202,6 +217,7 @@
|
||||
this._positionPinnedTabs();
|
||||
|
||||
this.#updateTabMinWidth();
|
||||
this.#updateTabMinHeight();
|
||||
|
||||
let indicatorTabs = gBrowser.visibleTabs.filter(tab => {
|
||||
return (
|
||||
@ -1529,7 +1545,11 @@
|
||||
node = this.arrowScrollbox.lastChild;
|
||||
}
|
||||
|
||||
return node.before(tab);
|
||||
node.before(tab);
|
||||
|
||||
if (this.#mustUpdateTabMinHeight) {
|
||||
this.#updateTabMinHeight();
|
||||
}
|
||||
}
|
||||
|
||||
#updateTabMinWidth(val) {
|
||||
@ -1544,6 +1564,53 @@
|
||||
}
|
||||
}
|
||||
|
||||
#updateTabMinHeight() {
|
||||
if (!this.verticalMode || !window.toolbar.visible) {
|
||||
this.#mustUpdateTabMinHeight = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find at least one tab we can scroll to.
|
||||
let firstScrollableTab = this.visibleTabs.find(
|
||||
this.arrowScrollbox._canScrollToElement
|
||||
);
|
||||
|
||||
if (!firstScrollableTab) {
|
||||
// If not, we're in a pickle. We should never get here except if we
|
||||
// also don't use the outcome of this work (because there's nothing to
|
||||
// scroll so we don't care about the scrollbox size).
|
||||
// So just set a flag so we re-run once we do have a new tab.
|
||||
this.#mustUpdateTabMinHeight = true;
|
||||
return;
|
||||
}
|
||||
|
||||
let { height } =
|
||||
window.windowUtils.getBoundsWithoutFlushing(firstScrollableTab);
|
||||
|
||||
// Use the current known height or a sane default.
|
||||
this.#tabMinHeight = height || 36;
|
||||
|
||||
// The height we got may be incorrect if a flush is pending so re-check it after
|
||||
// a flush completes.
|
||||
window
|
||||
.promiseDocumentFlushed(() => {})
|
||||
.then(
|
||||
() => {
|
||||
height =
|
||||
window.windowUtils.getBoundsWithoutFlushing(
|
||||
firstScrollableTab
|
||||
).height;
|
||||
|
||||
if (height) {
|
||||
this.#tabMinHeight = height;
|
||||
}
|
||||
},
|
||||
() => {
|
||||
/* ignore errors */
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
get _isCustomizing() {
|
||||
return document.documentElement.hasAttribute("customizing");
|
||||
}
|
||||
@ -1791,6 +1858,7 @@
|
||||
uiDensityChanged() {
|
||||
this._positionPinnedTabs();
|
||||
this._updateCloseButtons();
|
||||
this.#updateTabMinHeight();
|
||||
this._handleTabSelect(true);
|
||||
}
|
||||
|
||||
|
@ -321,6 +321,8 @@ support-files = ["tab_that_opens_dialog.html"]
|
||||
["browser_restore_isAppTab.js"]
|
||||
run-if = ["crashreporter"] # test requires crashreporter due to 1536221
|
||||
|
||||
["browser_scroll_size_determination.js"]
|
||||
|
||||
["browser_selectTabAtIndex.js"]
|
||||
|
||||
["browser_switch_by_scrolling.js"]
|
||||
|
@ -0,0 +1,96 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Check that when opening a new window with vertical tabs turned
|
||||
* on/off, wheel events with DOM_DELTA_LINE deltaMode successfully
|
||||
* scroll the tabstrip.
|
||||
*/
|
||||
async function scrolling_works(useVerticalTabs, uiDensity) {
|
||||
info(`Testing UI density ${uiDensity}`);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["sidebar.revamp", useVerticalTabs],
|
||||
["sidebar.verticalTabs", useVerticalTabs],
|
||||
],
|
||||
});
|
||||
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
win.gUIDensity.update(win.gUIDensity[uiDensity]);
|
||||
|
||||
await BrowserTestUtils.overflowTabs(registerCleanupFunction, win, {
|
||||
overflowAtStart: false,
|
||||
overflowTabFactor: 3,
|
||||
});
|
||||
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return Array.from(win.gBrowser.tabs).every(tab => tab._fullyOpen);
|
||||
});
|
||||
|
||||
win.gBrowser.pinTab(win.gBrowser.tabs[0]);
|
||||
|
||||
let firstScrollableTab = win.gBrowser.tabs[1];
|
||||
|
||||
// Scroll back to start.
|
||||
win.gBrowser.selectedTab = firstScrollableTab;
|
||||
await TestUtils.waitForTick();
|
||||
await win.promiseDocumentFlushed(() => {});
|
||||
|
||||
// Check we're scrolled so the first scrollable tab is at the top.
|
||||
let { arrowScrollbox } = win.gBrowser.tabContainer;
|
||||
let side = useVerticalTabs ? "top" : "left";
|
||||
let boxStart = arrowScrollbox.getBoundingClientRect()[side];
|
||||
let firstPoint = boxStart + 5;
|
||||
Assert.equal(
|
||||
gBrowser.tabs.indexOf(arrowScrollbox._elementFromPoint(firstPoint)),
|
||||
gBrowser.tabs.indexOf(firstScrollableTab),
|
||||
"First tab should be scrolled into view."
|
||||
);
|
||||
|
||||
// Scroll.
|
||||
EventUtils.synthesizeWheel(
|
||||
arrowScrollbox,
|
||||
10,
|
||||
10,
|
||||
{
|
||||
wheel: true,
|
||||
deltaY: 1,
|
||||
deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
},
|
||||
win
|
||||
);
|
||||
|
||||
// Check that some other tab is scrolled into view.
|
||||
try {
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return arrowScrollbox._elementFromPoint(firstPoint) != firstScrollableTab;
|
||||
});
|
||||
} catch (ex) {
|
||||
Assert.ok(false, `Failed to see scroll, error: ${ex}`);
|
||||
}
|
||||
Assert.notEqual(
|
||||
win.gBrowser.tabs.indexOf(arrowScrollbox._elementFromPoint(firstPoint)),
|
||||
win.gBrowser.tabs.indexOf(firstScrollableTab),
|
||||
"First tab should be scrolled out of view."
|
||||
);
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
|
||||
add_task(async function test_vertical_scroll() {
|
||||
for (let density of ["MODE_NORMAL", "MODE_COMPACT", "MODE_TOUCH"]) {
|
||||
await scrolling_works(true, density);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_horizontal_scroll() {
|
||||
for (let density of ["MODE_NORMAL", "MODE_COMPACT", "MODE_TOUCH"]) {
|
||||
await scrolling_works(false, density);
|
||||
}
|
||||
});
|
@ -1928,8 +1928,11 @@ export var BrowserTestUtils = {
|
||||
if (!params.hasOwnProperty("overflowTabFactor")) {
|
||||
params.overflowTabFactor = 1.1;
|
||||
}
|
||||
let index = params.overflowAtStart ? 0 : undefined;
|
||||
let { gBrowser } = win;
|
||||
let overflowDirection = gBrowser.tabContainer.verticalMode
|
||||
? "height"
|
||||
: "width";
|
||||
let index = params.overflowAtStart ? 0 : undefined;
|
||||
let arrowScrollbox = gBrowser.tabContainer.arrowScrollbox;
|
||||
if (arrowScrollbox.hasAttribute("overflowing")) {
|
||||
return;
|
||||
@ -1949,12 +1952,12 @@ export var BrowserTestUtils = {
|
||||
arrowScrollbox.smoothScroll = originalSmoothScroll;
|
||||
});
|
||||
|
||||
let width = ele => ele.getBoundingClientRect().width;
|
||||
let tabMinWidth = parseInt(
|
||||
win.getComputedStyle(gBrowser.selectedTab).minWidth
|
||||
);
|
||||
let size = ele => ele.getBoundingClientRect()[overflowDirection];
|
||||
let tabMinSize = gBrowser.tabContainer.verticalMode
|
||||
? size(gBrowser.selectedTab)
|
||||
: parseInt(win.getComputedStyle(gBrowser.selectedTab).minWidth);
|
||||
let tabCountForOverflow = Math.ceil(
|
||||
(width(arrowScrollbox) / tabMinWidth) * params.overflowTabFactor
|
||||
(size(arrowScrollbox) / tabMinSize) * params.overflowTabFactor
|
||||
);
|
||||
while (gBrowser.tabs.length < tabCountForOverflow) {
|
||||
promises.push(
|
||||
|
Loading…
Reference in New Issue
Block a user