Bug 1689156 - Don't generate first-contentful-paint if the paint doesn't come from Tick r=smaug

When a contentful paint occurs which doesn't come from Tick, we should
not generate a first-contentful-paint entry for it because
    1) It violates the spec
    2) It usually means some magical paints which we should not expose
    to the web.

So this patches stop generating a contentful paint entry for that,
instead asking the next tick to generate the entry.

Depends on D107858

Differential Revision: https://phabricator.services.mozilla.com/D107859
This commit is contained in:
Sean Feng 2021-03-22 20:49:05 +00:00
Родитель 706997d444
Коммит 2d171637c1
5 изменённых файлов: 71 добавлений и 25 удалений

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

@ -220,6 +220,7 @@ nsPresContext::nsPresContext(dom::Document* aDocument, nsPresContextType aType)
mQuirkSheetAdded(false),
mHadNonBlankPaint(false),
mHadContentfulPaint(false),
mHadNonTickContentfulPaint(false),
mHadContentfulPaintComposite(false)
#ifdef DEBUG
,
@ -2422,33 +2423,42 @@ void nsPresContext::NotifyNonBlankPaint() {
}
void nsPresContext::NotifyContentfulPaint() {
nsRootPresContext* rootPresContext = GetRootPresContext();
if (!rootPresContext) {
return;
}
if (!mHadContentfulPaint) {
#if defined(MOZ_WIDGET_ANDROID)
(new AsyncEventDispatcher(mDocument, u"MozFirstContentfulPaint"_ns,
CanBubble::eYes, ChromeOnlyDispatch::eYes))
->PostDOMEvent();
if (!mHadNonTickContentfulPaint) {
(new AsyncEventDispatcher(mDocument, u"MozFirstContentfulPaint"_ns,
CanBubble::eYes, ChromeOnlyDispatch::eYes))
->PostDOMEvent();
}
#endif
if (!rootPresContext->RefreshDriver()->IsInRefresh()) {
if (!mHadNonTickContentfulPaint) {
rootPresContext->RefreshDriver()
->AddForceNotifyContentfulPaintPresContext(this);
mHadNonTickContentfulPaint = true;
}
return;
}
mHadContentfulPaint = true;
if (nsRootPresContext* rootPresContext = GetRootPresContext()) {
mFirstContentfulPaintTransactionId =
Some(rootPresContext->mRefreshDriver->LastTransactionId().Next());
if (nsPIDOMWindowInner* innerWindow = mDocument->GetInnerWindow()) {
if (Performance* perf = innerWindow->GetPerformance()) {
TimeStamp nowTime =
rootPresContext->RefreshDriver()->MostRecentRefresh(
/* aEnsureTimerStarted */ false);
MOZ_ASSERT(
!nowTime.IsNull(),
"Most recent refresh timestamp should exist since we are in "
"a refresh driver tick");
MOZ_ASSERT(rootPresContext->RefreshDriver()->IsInRefresh(),
"We should only notify contentful paint during refresh "
"driver ticks");
RefPtr<PerformancePaintTiming> paintTiming =
new PerformancePaintTiming(perf, u"first-contentful-paint"_ns,
nowTime);
perf->SetFCPTimingEntry(paintTiming);
}
mFirstContentfulPaintTransactionId =
Some(rootPresContext->mRefreshDriver->LastTransactionId().Next());
if (nsPIDOMWindowInner* innerWindow = mDocument->GetInnerWindow()) {
if (Performance* perf = innerWindow->GetPerformance()) {
TimeStamp nowTime = rootPresContext->RefreshDriver()->MostRecentRefresh(
/* aEnsureTimerStarted */ false);
MOZ_ASSERT(!nowTime.IsNull(),
"Most recent refresh timestamp should exist since we are in "
"a refresh driver tick");
MOZ_ASSERT(rootPresContext->RefreshDriver()->IsInRefresh(),
"We should only notify contentful paint during refresh "
"driver ticks");
RefPtr<PerformancePaintTiming> paintTiming = new PerformancePaintTiming(
perf, u"first-contentful-paint"_ns, nowTime);
perf->SetFCPTimingEntry(paintTiming);
}
}
}
@ -2462,6 +2472,7 @@ void nsPresContext::NotifyPaintStatusReset() {
CanBubble::eYes, ChromeOnlyDispatch::eYes))
->PostDOMEvent();
#endif
mHadNonTickContentfulPaint = false;
}
void nsPresContext::NotifyDOMContentFlushed() {

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

@ -1331,6 +1331,11 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
unsigned mHadNonBlankPaint : 1;
// Has NotifyContentfulPaint been called on this PresContext?
unsigned mHadContentfulPaint : 1;
// True when a contentful paint has happened and this paint doesn't
// come from the regular tick process. Usually this means a
// contentful paint was triggered manually.
unsigned mHadNonTickContentfulPaint : 1;
// Has NotifyDidPaintForSubtree been called for a contentful paint?
unsigned mHadContentfulPaintComposite : 1;

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

@ -1355,6 +1355,21 @@ void nsRefreshDriver::RegisterCompositionPayload(
mCompositionPayloads.AppendElement(aPayload);
}
void nsRefreshDriver::AddForceNotifyContentfulPaintPresContext(
nsPresContext* aPresContext) {
mForceNotifyContentfulPaintPresContexts.AppendElement(aPresContext);
}
void nsRefreshDriver::FlushForceNotifyContentfulPaintPresContext() {
while (!mForceNotifyContentfulPaintPresContexts.IsEmpty()) {
WeakPtr<nsPresContext> presContext =
mForceNotifyContentfulPaintPresContexts.PopLastElement();
if (presContext) {
presContext->NotifyContentfulPaint();
}
}
}
void nsRefreshDriver::RunDelayedEventsSoon() {
// Place entries for delayed events into their corresponding normal list,
// and schedule a refresh. When these delayed events run, if their document
@ -2033,6 +2048,8 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime) {
DisplayPortUtils::UpdateDisplayPortMarginsFromPendingMessages();
}
FlushForceNotifyContentfulPaintPresContext();
AutoTArray<nsCOMPtr<nsIRunnable>, 16> earlyRunners = std::move(mEarlyRunners);
for (auto& runner : earlyRunners) {
runner->Run();

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

@ -407,6 +407,9 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
eHasVisualViewportScrollEvents = 1 << 5,
};
void AddForceNotifyContentfulPaintPresContext(nsPresContext* aPresContext);
void FlushForceNotifyContentfulPaintPresContext();
private:
typedef nsTArray<RefPtr<VVPResizeEvent>> VisualViewportResizeEventArray;
typedef nsTArray<RefPtr<mozilla::Runnable>> ScrollEventArray;
@ -588,6 +591,17 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
AutoTArray<mozilla::AnimationEventDispatcher*, 16>
mAnimationEventFlushObservers;
// nsPresContexts which `NotifyContentfulPaint` have been called,
// however the corresponding paint doesn't come from a regular
// rendering steps(aka tick).
//
// For these nsPresContexts, we invoke
// `FlushForceNotifyContentfulPaintPresContext` in the next tick
// to force notify contentful paint, regardless whether the tick paints
// or not.
nsTArray<mozilla::WeakPtr<nsPresContext>>
mForceNotifyContentfulPaintPresContexts;
void BeginRefreshingImages(RequestTable& aEntries,
mozilla::TimeStamp aDesired);

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

@ -1178,8 +1178,7 @@ void nsDisplayListBuilder::LeavePresShell(const nsIFrame* aReferenceFrame,
}
}
nsRootPresContext* rootPresContext = pc->GetRootPresContext();
if (!pc->HadContentfulPaint() && rootPresContext &&
rootPresContext->RefreshDriver()->IsInRefresh()) {
if (!pc->HadContentfulPaint() && rootPresContext) {
if (!CurrentPresShellState()->mIsBackgroundOnly) {
if (pc->HasEverBuiltInvisibleText() ||
DisplayListIsContentful(this, aPaintedContents)) {