Bug 1358443 - remove reflows from adjustHeight itself, r=mak,florian

This goes back to relying on rows being the same height.
Places where we replace the popup will likely not use the richlistbox,
and we no longer have code that changes the height or exceeds the maximum
number of visible children with a scrollbar, so we should be OK.

To determine the padding on the richlistbox and the height of the initial
row, I've used a promiseDocumentFlushed callback. It's possible this causes
flicker the first time the popup opens. I can't see any, but it's quite
possible I'm missing something.

Differential Revision: https://phabricator.services.mozilla.com/D2242

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Gijs Kruitbosch 2018-07-26 13:17:41 +00:00
parent 4f0be13f9c
commit 5c512f312d
5 changed files with 89 additions and 97 deletions

View File

@ -799,7 +799,6 @@
autocompletesearchparam="enable-actions"
autocompletepopup="PopupAutoCompleteRichResult"
completeselectedindex="true"
shrinkdelay="250"
tabscrolling="true"
newlines="stripsurroundingwhitespace"
ontextentered="this.handleCommand(param);"

View File

@ -30,22 +30,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
],
},
{
stack: [
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
"onxblpopupshown@chrome://global/content/bindings/autocomplete.xml"
],
maxCount: 5, // This number should only ever go down - never up.
},
{
stack: [
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
"_invalidate/this._adjustHeightTimeout<@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 51, // This number should only ever go down - never up.
},
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",

View File

@ -30,22 +30,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
],
},
{
stack: [
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
"onxblpopupshown@chrome://global/content/bindings/autocomplete.xml"
],
maxCount: 5, // This number should only ever go down - never up.
},
{
stack: [
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
"_invalidate/this._adjustHeightTimeout<@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 6, // This number should only ever go down - never up.
},
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
@ -83,22 +67,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
/* These reflows happen everytime the awesomebar panel opens. */
const EXPECTED_REFLOWS_SECOND_OPEN = [
{
stack: [
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
"onxblpopupshown@chrome://global/content/bindings/autocomplete.xml"
],
maxCount: 3, // This number should only ever go down - never up.
},
{
stack: [
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
"_invalidate/this._adjustHeightTimeout<@chrome://global/content/bindings/autocomplete.xml",
],
maxCount: 6, // This number should only ever go down - never up.
},
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",

View File

@ -1911,6 +1911,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
document.getAnonymousElementByAttribute(this, "anonid", "footer");
</field>
<field name="shrinkDelay" readonly="true">
250
</field>
<field name="oneOffSearchButtons" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid",
"one-off-search-buttons");
@ -2195,6 +2199,83 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
]]></body>
</method>
<method name="adjustHeight">
<body>
<![CDATA[
// If we were going to shrink later, cancel that for now:
if (this._shrinkTimeout) {
clearTimeout(this._shrinkTimeout);
this._shrinkTimeout = null;
}
let lastRowCount = this._lastRowCount;
// Figure out how many rows to show
let rows = this.richlistbox.childNodes;
this._lastRowCount = rows.length;
let numRows = Math.min(this.matchCount, this.maxRows, rows.length);
// If we're going from 0 to non-0 rows, we might need to remove
// the height attribute to allow the popup to size. The attribute
// is set from XUL popup management code.
if (!lastRowCount && rows.length) {
this.removeAttribute("height");
}
// Default the height to 0 if we have no rows to show
let height = 0;
if (numRows) {
if (!this._rowHeight) {
window.promiseDocumentFlushed(() => {
if (window.closed) {
return;
}
this._rowHeight = rows[0].getBoundingClientRect().height;
let style = window.getComputedStyle(this.richlistbox);
let paddingTop = parseInt(style.paddingTop) || 0;
let paddingBottom = parseInt(style.paddingBottom) || 0;
this._rlbPadding = paddingTop + paddingBottom;
// Then re-run - but don't dirty layout from inside this callback.
window.requestAnimationFrame(() => this.adjustHeight());
});
return;
}
// Calculate the height to have the first row to last row shown
height = (this._rowHeight * numRows) + this._rlbPadding;
}
let animate = this.getAttribute("dontanimate") != "true";
let currentHeight =
parseFloat(this.richlistbox.getAttribute("height"), 10) ||
parseFloat(this.richlistbox.style.height, 10) ||
0; // It's possible we get here when we haven't set height on the richlistbox
// yet, which means parseFloat will return NaN. It should return 0 instead.
if (height > currentHeight) {
// Grow immediately.
if (animate) {
this.richlistbox.removeAttribute("height");
this.richlistbox.style.height = height + "px";
} else {
this.richlistbox.style.removeProperty("height");
this.richlistbox.height = height;
}
} else if (height < currentHeight) { // Don't shrink if height matches exactly
// Delay shrinking to avoid flicker.
this._shrinkTimeout = setTimeout(() => {
this._collapseUnusedItems();
if (animate) {
this.richlistbox.removeAttribute("height");
this.richlistbox.style.height = height + "px";
} else {
this.richlistbox.style.removeProperty("height");
this.richlistbox.height = height;
}
}, this.shrinkDelay);
}
]]>
</body>
</method>
<method name="_showSearchSuggestionsNotification">
<parameter name="whichNotification"/>
<parameter name="popupDirection"/>

View File

@ -131,10 +131,6 @@
<property name="searchCount" readonly="true"
onget="this.initSearchNames(); return this.mSearchNames.length;"/>
<field name="shrinkDelay" readonly="true">
parseInt(this.getAttribute("shrinkdelay")) || 0
</field>
<property name="PrivateBrowsingUtils" readonly="true">
<getter><![CDATA[
let module = {};
@ -657,7 +653,6 @@
<field name="mInput">null</field>
<field name="mPopupOpen">false</field>
<field name="_currentIndex">0</field>
<field name="_rlbAnimated">false</field>
<!-- =================== nsIAutoCompletePopup =================== -->
@ -826,16 +821,14 @@
this.richlistbox.collapsed = (this.matchCount == 0);
// Update the richlistbox height.
if (this._adjustHeightTimeout) {
clearTimeout(this._adjustHeightTimeout);
}
if (this._shrinkTimeout) {
clearTimeout(this._shrinkTimeout);
if (this._adjustHeightRAFToken) {
cancelAnimationFrame(this._adjustHeightRAFToken);
this._adjustHeightRAFToken = null;
}
if (this.mPopupOpen) {
delete this._adjustHeightOnPopupShown;
this._adjustHeightTimeout = setTimeout(() => this.adjustHeight(), 0);
this._adjustHeightRAFToken = requestAnimationFrame(() => this.adjustHeight());
} else {
this._adjustHeightOnPopupShown = true;
}
@ -896,31 +889,17 @@
let rows = this.richlistbox.childNodes;
let numRows = Math.min(this.matchCount, this.maxRows, rows.length);
this.removeAttribute("height");
// Default the height to 0 if we have no rows to show
let height = 0;
if (numRows) {
let firstRowRect = rows[0].getBoundingClientRect();
if (this._rlbPadding == undefined) {
let style = window.getComputedStyle(this.richlistbox);
let transition = style.transitionProperty;
this._rlbAnimated = transition && transition != "none";
let paddingTop = parseInt(style.paddingTop) || 0;
let paddingBottom = parseInt(style.paddingBottom) || 0;
this._rlbPadding = paddingTop + paddingBottom;
}
if (numRows > this.maxRows) {
// Set a fixed max-height to avoid flicker when growing the panel.
let lastVisibleRowRect = rows[this.maxRows - 1].getBoundingClientRect();
let visibleHeight = lastVisibleRowRect.bottom - firstRowRect.top;
this.richlistbox.style.maxHeight =
visibleHeight + this._rlbPadding + "px";
}
// The class `forceHandleUnderflow` is for the item might need to
// handle OverUnderflow or Overflow when the height of an item will
// be changed dynamically.
@ -936,31 +915,12 @@
this._rlbPadding;
}
let animate = this._rlbAnimated &&
this.getAttribute("dontanimate") != "true";
let currentHeight = this.richlistbox.getBoundingClientRect().height;
if (height > currentHeight) {
// Grow immediately.
if (animate) {
this.richlistbox.removeAttribute("height");
this.richlistbox.style.height = height + "px";
} else {
this.richlistbox.style.removeProperty("height");
this.richlistbox.height = height;
}
} else {
// Delay shrinking to avoid flicker.
this._shrinkTimeout = setTimeout(() => {
this._collapseUnusedItems();
if (animate) {
this.richlistbox.removeAttribute("height");
this.richlistbox.style.height = height + "px";
} else {
this.richlistbox.style.removeProperty("height");
this.richlistbox.height = height;
}
}, this.mInput.shrinkDelay);
if (height <= currentHeight) {
this._collapseUnusedItems();
}
this.richlistbox.style.removeProperty("height");
this.richlistbox.height = height;
]]>
</body>
</method>