Bug 1690433. Create a minimal display port type. r=botond

We introduce a new type of display port, a minimal display port. It is controlled via a property on the content element. When the property is present any other display port specified on the element is ignored and instead the display port rect is computed by assuming 0 display port margins and no alignment (this reuses the existing code for display port suppression).

We then add code to set a minimal display port on every scroll frame that is painted that has WantAsyncScroll() when certain prefs are set (the prefs are disabled as of this patch though).

We then need to manage removing the minimal display port property when, before this patch, we would have created a regular display port. As well we need to add the minimal display port property when, before this patch, we would have removed a regular display port.

In order to do this I audited all sites where we set the display port rect and display port margins property. The changes to the code for handling the removal display ports happens in a later patch.

My audit found that all of the places we set a display port want to clear the minimal display port property except:
-UpdateSub/RootFrame in APZCCallbackHelper
-UpdateDisplayPortMarginsForPendingMetrics in DisplayPortUtils

UpdateDisplayPortMarginsForPendingMetrics is basically a fast path of the UpdateSub/RootFrame code. These are the places where we handle calls to RequestContentRepaint from apz. By adding an assert and running it through try server I found that UpdateSub/RootFrame can create a display port in the following cases:
-a scroll info layer
-a scroll frame with !WantAsyncScroll() (the main thread never creates a display port for a scroll frame with !WantAsyncScroll()) (for example if the main thread creates a scroll id and sends over metadata via nsLayoutUtils::GetRootMetaData, and then the scroll rect changes, that will cause a RequestContentRepaint call)
-a few instances that don't fall into the above that happened on try server but didn't reproduce for me locally, so I don't know more about them.
It's not very important whether we clear the minimal display port property for these cases or not (the first two cases we don't async scroll the scroll frame at all, the last case seems quite rare).

Note that we intentionally do not change the existing behaviour of zero margin display ports set via SetZeroMarginDisplayPortOnAsyncScrollableAncestors as we are aiming for no behaviour changes with this patch (until we flip the pref). A later patch in a different bug handles changing these display ports over to minimal display ports.

Differential Revision: https://phabricator.services.mozilla.com/D103855
This commit is contained in:
Timothy Nikkel 2021-02-04 11:16:44 +00:00
Родитель 8373d6cfc5
Коммит e2f27ec58a
8 изменённых файлов: 100 добавлений и 18 удалений

Просмотреть файл

@ -506,6 +506,7 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
nsPresContext::CSSPixelsToAppUnits(aWidthPx),
nsPresContext::CSSPixelsToAppUnits(aHeightPx));
aElement->RemoveProperty(nsGkAtoms::MinimalDisplayPort);
aElement->SetProperty(
nsGkAtoms::DisplayPort,
new DisplayPortPropertyData(displayport, aPriority, wasPainted),
@ -564,7 +565,8 @@ nsDOMWindowUtils::SetDisplayPortMarginsForElement(
DisplayPortUtils::SetDisplayPortMargins(
aElement, presShell,
DisplayPortMargins::ForContent(aElement, displayportMargins), aPriority);
DisplayPortMargins::ForContent(aElement, displayportMargins),
DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, aPriority);
return NS_OK;
}

Просмотреть файл

@ -264,8 +264,11 @@ static void SetDisplayPortMargins(PresShell* aPresShell, nsIContent* aContent,
ToString(aDisplayPortMargins).c_str(), viewID));
}
}
DisplayPortUtils::SetDisplayPortMargins(aContent, aPresShell,
aDisplayPortMargins, 0);
DisplayPortUtils::SetDisplayPortMargins(
aContent, aPresShell, aDisplayPortMargins,
hadDisplayPort ? DisplayPortUtils::ClearMinimalDisplayPortProperty::No
: DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes,
0);
if (!hadDisplayPort) {
DisplayPortUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
aContent->GetPrimaryFrame());
@ -441,7 +444,8 @@ void APZCCallbackHelper::InitializeRootDisplayport(PresShell* aPresShell) {
// Note that we also set the base rect that goes with these margins in
// nsRootBoxFrame::BuildDisplayList.
DisplayPortUtils::SetDisplayPortMargins(
content, aPresShell, DisplayPortMargins::Empty(content), 0);
content, aPresShell, DisplayPortMargins::Empty(content),
DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, 0);
DisplayPortUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
content->GetPrimaryFrame());
}

Просмотреть файл

@ -341,7 +341,8 @@ static nsRect GetDisplayPortFromMarginsData(
ScreenMargin margins = aMarginsData->mMargins.GetRelativeToLayoutViewport(
aOptions.mGeometryType, scrollableFrame);
if (presShell->IsDisplayportSuppressed()) {
if (presShell->IsDisplayportSuppressed() ||
aContent->GetProperty(nsGkAtoms::MinimalDisplayPort)) {
alignment = ScreenSize(1, 1);
} else if (useWebRender) {
// Moving the displayport is relatively expensive with WR so we use a larger
@ -550,7 +551,8 @@ static bool GetDisplayPortImpl(nsIContent* aContent, nsRect* aResult,
if (rectData) {
result = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
} else if (isDisplayportSuppressed ||
nsLayoutUtils::ShouldDisableApzForElement(aContent)) {
nsLayoutUtils::ShouldDisableApzForElement(aContent) ||
aContent->GetProperty(nsGkAtoms::MinimalDisplayPort)) {
// Make a copy of the margins data but set the margins to empty.
// Do not create a new DisplayPortMargins object with
// DisplayPortMargins::Empty(), because that will record the visual
@ -700,11 +702,11 @@ void DisplayPortUtils::InvalidateForDisplayPortChange(
}
}
bool DisplayPortUtils::SetDisplayPortMargins(nsIContent* aContent,
PresShell* aPresShell,
const DisplayPortMargins& aMargins,
uint32_t aPriority,
RepaintMode aRepaintMode) {
bool DisplayPortUtils::SetDisplayPortMargins(
nsIContent* aContent, PresShell* aPresShell,
const DisplayPortMargins& aMargins,
ClearMinimalDisplayPortProperty aClearMinimalDisplayPortProperty,
uint32_t aPriority, RepaintMode aRepaintMode) {
MOZ_ASSERT(aContent);
MOZ_ASSERT(aContent->GetComposedDoc() == aPresShell->GetDocument());
@ -744,6 +746,21 @@ bool DisplayPortUtils::SetDisplayPortMargins(nsIContent* aContent,
new DisplayPortMarginsPropertyData(aMargins, aPriority, wasPainted),
nsINode::DeleteProperty<DisplayPortMarginsPropertyData>);
if (aClearMinimalDisplayPortProperty ==
ClearMinimalDisplayPortProperty::Yes) {
if (MOZ_LOG_TEST(sDisplayportLog, LogLevel::Debug) &&
aContent->GetProperty(nsGkAtoms::MinimalDisplayPort)) {
mozilla::layers::ScrollableLayerGuid::ViewID viewID =
mozilla::layers::ScrollableLayerGuid::NULL_SCROLL_ID;
nsLayoutUtils::FindIDFor(aContent, &viewID);
MOZ_LOG(sDisplayportLog, LogLevel::Debug,
("SetDisplayPortMargins removing MinimalDisplayPort prop on "
"scrollId=%" PRIu64 "\n",
viewID));
}
aContent->RemoveProperty(nsGkAtoms::MinimalDisplayPort);
}
nsIScrollableFrame* scrollableFrame =
scrollFrame ? scrollFrame->GetScrollTargetFrame() : nullptr;
if (!scrollableFrame) {
@ -912,7 +929,9 @@ bool DisplayPortUtils::CalculateAndSetDisplayPortMargins(
aScrollFrame, displayportMargins,
Some(metrics.DisplayportPixelsPerCSSPixel()));
return SetDisplayPortMargins(content, presShell, margins, 0, aRepaintMode);
return SetDisplayPortMargins(content, presShell, margins,
ClearMinimalDisplayPortProperty::Yes, 0,
aRepaintMode);
}
bool DisplayPortUtils::MaybeCreateDisplayPort(nsDisplayListBuilder* aBuilder,
@ -979,7 +998,8 @@ void DisplayPortUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
if (nsLayoutUtils::AsyncPanZoomEnabled(frame) &&
!HasDisplayPort(frame->GetContent())) {
SetDisplayPortMargins(frame->GetContent(), frame->PresShell(),
DisplayPortMargins::Empty(frame->GetContent()), 0,
DisplayPortMargins::Empty(frame->GetContent()),
ClearMinimalDisplayPortProperty::Yes, 0,
RepaintMode::Repaint);
}
}
@ -1118,7 +1138,7 @@ static void UpdateDisplayPortMarginsForPendingMetrics(
DisplayPortMargins::FromAPZ(
aMetrics.GetDisplayPortMargins(), aMetrics.GetVisualScrollOffset(),
frameScrollOffset, aMetrics.DisplayportPixelsPerCSSPixel()),
0);
DisplayPortUtils::ClearMinimalDisplayPortProperty::No, 0);
}
/* static */

Просмотреть файл

@ -230,10 +230,13 @@ class DisplayPortUtils {
* @param aRepaintMode whether to schedule a paint after setting the margins
* @return true if the new margins were applied.
*/
enum class ClearMinimalDisplayPortProperty { No, Yes };
static bool SetDisplayPortMargins(
nsIContent* aContent, PresShell* aPresShell,
const DisplayPortMargins& aMargins, uint32_t aPriority = 0,
RepaintMode aRepaintMode = RepaintMode::Repaint);
const DisplayPortMargins& aMargins,
ClearMinimalDisplayPortProperty aClearMinimalDisplayPortProperty,
uint32_t aPriority = 0, RepaintMode aRepaintMode = RepaintMode::Repaint);
/**
* Set the display port base rect for given element to be used with display

Просмотреть файл

@ -8,6 +8,7 @@
#include "nsGfxScrollFrame.h"
#include "nsIXULRuntime.h"
#include "ActiveLayerTracker.h"
#include "base/compiler_specific.h"
#include "DisplayItemClip.h"
@ -2232,7 +2233,8 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, bool aIsRoot)
// when scrolling.
DisplayPortUtils::SetDisplayPortMargins(
mOuter->GetContent(), mOuter->PresShell(),
DisplayPortMargins::Empty(mOuter->GetContent()), 0);
DisplayPortMargins::Empty(mOuter->GetContent()),
DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, 0);
DisplayPortUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
mOuter);
}
@ -3938,7 +3940,8 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// to be disabled on the next paint.
DisplayPortUtils::SetDisplayPortMargins(
mOuter->GetContent(), mOuter->PresShell(),
DisplayPortMargins::Empty(mOuter->GetContent()), 0,
DisplayPortMargins::Empty(mOuter->GetContent()),
DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, 0,
DisplayPortUtils::RepaintMode::DoNotRepaint);
// Call DecideScrollableLayer to recompute mWillBuildScrollableLayer
// and recompute the current animated geometry root if needed. It's
@ -4246,6 +4249,18 @@ nsRect ScrollFrameHelper::RestrictToRootDisplayPort(
return aDisplayportBase.Intersect(rootDisplayPort);
}
/* static */ bool ScrollFrameHelper::ShouldActivateAllScrollFrames() {
if (gfxVars::UseWebRender()) {
return (StaticPrefs::apz_wr_activate_all_scroll_frames() ||
(StaticPrefs::apz_wr_activate_all_scroll_frames_when_fission() &&
FissionAutostart()));
} else {
return (StaticPrefs::apz_nonwr_activate_all_scroll_frames() ||
(StaticPrefs::apz_nonwr_activate_all_scroll_frames_when_fission() &&
FissionAutostart()));
}
}
bool ScrollFrameHelper::DecideScrollableLayer(
nsDisplayListBuilder* aBuilder, nsRect* aVisibleRect, nsRect* aDirtyRect,
bool aSetBase, bool* aDirtyRectHasBeenOverriden) {
@ -4253,6 +4268,22 @@ bool ScrollFrameHelper::DecideScrollableLayer(
bool oldWillBuildScrollableLayer = mWillBuildScrollableLayer;
nsIContent* content = mOuter->GetContent();
// For hit testing purposes with fission we want to create a
// minimal display port for every scroll frame that could be active. (We only
// do this when aSetBase is true because we only want to do this the first
// time this function is called for the same scroll frame.)
if (ShouldActivateAllScrollFrames() &&
!DisplayPortUtils::HasDisplayPort(content) &&
nsLayoutUtils::AsyncPanZoomEnabled(mOuter) && WantAsyncScroll() &&
aBuilder->IsPaintingToWindow() && aSetBase) {
DisplayPortUtils::SetDisplayPortMargins(
content, mOuter->PresShell(), DisplayPortMargins::Empty(content),
DisplayPortUtils::ClearMinimalDisplayPortProperty::No, 0,
DisplayPortUtils::RepaintMode::DoNotRepaint);
content->SetProperty(nsGkAtoms::MinimalDisplayPort,
reinterpret_cast<void*>(true));
}
bool usingDisplayPort = DisplayPortUtils::HasDisplayPort(content);
if (aBuilder->IsPaintingToWindow()) {
if (aSetBase) {

Просмотреть файл

@ -442,6 +442,7 @@ class ScrollFrameHelper : public nsIReflowCallback {
ScrollSnapInfo GetScrollSnapInfo(
const mozilla::Maybe<nsPoint>& aDestination) const;
static bool ShouldActivateAllScrollFrames();
nsRect RestrictToRootDisplayPort(const nsRect& aDisplayportBase);
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aVisibleRect, nsRect* aDirtyRect,

Просмотреть файл

@ -243,6 +243,26 @@
# The apz prefs are explained in AsyncPanZoomController.cpp
#---------------------------------------------------------------------------
- name: apz.wr.activate_all_scroll_frames
type: RelaxedAtomicBool
value: false
mirror: always
- name: apz.wr.activate_all_scroll_frames_when_fission
type: RelaxedAtomicBool
value: false
mirror: always
- name: apz.nonwr.activate_all_scroll_frames
type: RelaxedAtomicBool
value: false
mirror: always
- name: apz.nonwr.activate_all_scroll_frames_when_fission
type: RelaxedAtomicBool
value: false
mirror: always
- name: apz.allow_double_tap_zooming
type: RelaxedAtomicBool
value: true

Просмотреть файл

@ -2187,6 +2187,7 @@ STATIC_ATOMS = [
Atom("DisplayPort", "_displayport"),
Atom("DisplayPortMargins", "_displayportmargins"),
Atom("DisplayPortBase", "_displayportbase"),
Atom("MinimalDisplayPort", "_minimaldisplayport"),
Atom("forcemessagemanager", "forcemessagemanager"),
Atom("preloadedState", "preloadedState"),
Atom("initialBrowsingContextGroupId", "initialBrowsingContextGroupId"),