mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1862939 - Part 1: Add LCP to nsDOMNavigationTiming. r=sefeng
Differential Revision: https://phabricator.services.mozilla.com/D192689
This commit is contained in:
parent
f0bf641c7b
commit
c5c5d07e9f
@ -57,6 +57,7 @@ void nsDOMNavigationTiming::Clear() {
|
||||
mDOMContentLoadedEventEnd = TimeStamp();
|
||||
mDOMComplete = TimeStamp();
|
||||
mContentfulComposite = TimeStamp();
|
||||
mLargestContentfulRender = TimeStamp();
|
||||
mNonBlankPaint = TimeStamp();
|
||||
|
||||
mDocShellHasBeenActiveSinceNavigationStart = false;
|
||||
@ -478,6 +479,16 @@ void nsDOMNavigationTiming::NotifyContentfulCompositeForRootContentDocument(
|
||||
}
|
||||
}
|
||||
|
||||
void nsDOMNavigationTiming::NotifyLargestContentfulRenderForRootContentDocument(
|
||||
const DOMHighResTimeStamp& aRenderTime) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mNavigationStart.IsNull());
|
||||
|
||||
// This can get called multiple times and updates over time.
|
||||
mLargestContentfulRender =
|
||||
mNavigationStart + TimeDuration::FromMilliseconds(aRenderTime);
|
||||
}
|
||||
|
||||
void nsDOMNavigationTiming::NotifyDOMContentFlushedForRootContentDocument() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mNavigationStart.IsNull());
|
||||
|
@ -71,6 +71,10 @@ class nsDOMNavigationTiming final : public mozilla::RelativeTimeline {
|
||||
return mContentfulComposite;
|
||||
}
|
||||
|
||||
mozilla::TimeStamp GetLargestContentfulRenderTimeStamp() const {
|
||||
return mLargestContentfulRender;
|
||||
}
|
||||
|
||||
DOMTimeMilliSec GetUnloadEventStart() {
|
||||
return TimeStampToDOM(GetUnloadEventStartTimeStamp());
|
||||
}
|
||||
@ -104,6 +108,9 @@ class nsDOMNavigationTiming final : public mozilla::RelativeTimeline {
|
||||
DOMTimeMilliSec GetTimeToContentfulComposite() const {
|
||||
return TimeStampToDOM(mContentfulComposite);
|
||||
}
|
||||
DOMTimeMilliSec GetTimeToLargestContentfulRender() const {
|
||||
return TimeStampToDOM(mLargestContentfulRender);
|
||||
}
|
||||
DOMTimeMilliSec GetTimeToTTFI() const { return TimeStampToDOM(mTTFI); }
|
||||
DOMTimeMilliSec GetTimeToDOMContentFlushed() const {
|
||||
return TimeStampToDOM(mDOMContentFlushed);
|
||||
@ -172,6 +179,8 @@ class nsDOMNavigationTiming final : public mozilla::RelativeTimeline {
|
||||
void NotifyNonBlankPaintForRootContentDocument();
|
||||
void NotifyContentfulCompositeForRootContentDocument(
|
||||
const mozilla::TimeStamp& aCompositeEndTime);
|
||||
void NotifyLargestContentfulRenderForRootContentDocument(
|
||||
const DOMHighResTimeStamp& aRenderTime);
|
||||
void NotifyDOMContentFlushedForRootContentDocument();
|
||||
void NotifyDocShellStateChanged(DocShellState aDocShellState);
|
||||
|
||||
@ -230,6 +239,7 @@ class nsDOMNavigationTiming final : public mozilla::RelativeTimeline {
|
||||
mozilla::TimeStamp mNavigationStart;
|
||||
mozilla::TimeStamp mNonBlankPaint;
|
||||
mozilla::TimeStamp mContentfulComposite;
|
||||
mozilla::TimeStamp mLargestContentfulRender;
|
||||
mozilla::TimeStamp mDOMContentFlushed;
|
||||
|
||||
mozilla::TimeStamp mBeforeUnloadStart;
|
||||
|
@ -45,7 +45,7 @@ perf:
|
||||
unit: ms
|
||||
fcp_time:
|
||||
description:
|
||||
"Time between firstContentfulPaint and naviationStart, in ms."
|
||||
"Time between firstContentfulPaint and navigationStart, in ms."
|
||||
type: quantity
|
||||
unit: ms
|
||||
js_exec_time:
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "PerformanceMainThread.h"
|
||||
#include "LargestContentfulPaint.h"
|
||||
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/DOMIntersectionObserver.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
@ -54,12 +55,14 @@ LargestContentfulPaint::LargestContentfulPaint(
|
||||
PerformanceMainThread* aPerformance, const DOMHighResTimeStamp aRenderTime,
|
||||
const DOMHighResTimeStamp aLoadTime, const unsigned long aSize,
|
||||
nsIURI* aURI, Element* aElement,
|
||||
const Maybe<const LCPImageEntryKey>& aLCPImageEntryKey)
|
||||
const Maybe<const LCPImageEntryKey>& aLCPImageEntryKey,
|
||||
bool aShouldExposeRenderTime)
|
||||
: PerformanceEntry(aPerformance->GetParentObject(), u""_ns,
|
||||
kLargestContentfulPaintName),
|
||||
mPerformance(aPerformance),
|
||||
mRenderTime(aRenderTime),
|
||||
mLoadTime(aLoadTime),
|
||||
mShouldExposeRenderTime(aShouldExposeRenderTime),
|
||||
mSize(aSize),
|
||||
mURI(aURI),
|
||||
mElement(aElement),
|
||||
@ -187,24 +190,11 @@ void LargestContentfulPaint::MaybeProcessImageForElementTiming(
|
||||
DOMHighResTimeStamp nowTime =
|
||||
performance->TimeStampToDOMHighResForRendering(TimeStamp::Now());
|
||||
|
||||
if (!request->IsData() && !request->ShouldReportRenderTimeForLCP()) {
|
||||
// https://wicg.github.io/element-timing/#report-image-element-timing
|
||||
LOG(" Added a pending image rendering (TAO FAILED)");
|
||||
// For TAO failed requests, the renderTime is exposed as 0 for
|
||||
// security reasons.
|
||||
LCPHelpers::CreateLCPEntryForImage(performance, aElement, aRequest, nowTime,
|
||||
0 /* aRenderTime */, entryKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, add the triple (element, imageRequest, now) to root’s images
|
||||
// pending rendering.
|
||||
//
|
||||
// At this point, the loadTime of the image is known, but
|
||||
// the renderTime is unknown, so it's added to ImagesPendingRendering
|
||||
// as a placeholder, and the corresponding LCP entry will be created
|
||||
// when the renderTime is known.
|
||||
LOG(" Added a pending image rendering (TAO PASSED)");
|
||||
LOG(" Added a pending image rendering");
|
||||
performance->AddImagesPendingRendering(
|
||||
ImagePendingRendering{entryKey, nowTime});
|
||||
}
|
||||
@ -270,6 +260,9 @@ void LCPHelpers::FinalizeLCPEntryForImage(
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp LargestContentfulPaint::RenderTime() const {
|
||||
if (!mShouldExposeRenderTime) {
|
||||
return 0;
|
||||
}
|
||||
return nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
mRenderTime, mPerformance->GetRandomTimelineSeed(),
|
||||
mPerformance->GetRTPCallerType());
|
||||
@ -282,7 +275,8 @@ DOMHighResTimeStamp LargestContentfulPaint::LoadTime() const {
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp LargestContentfulPaint::StartTime() const {
|
||||
DOMHighResTimeStamp startTime = !mRenderTime ? mLoadTime : mRenderTime;
|
||||
DOMHighResTimeStamp startTime =
|
||||
mShouldExposeRenderTime ? mRenderTime : mLoadTime;
|
||||
return nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
startTime, mPerformance->GetRandomTimelineSeed(),
|
||||
mPerformance->GetRTPCallerType());
|
||||
@ -299,6 +293,8 @@ Element* LargestContentfulPaint::GetContainingBlockForTextFrame(
|
||||
void LargestContentfulPaint::QueueEntry() {
|
||||
LOG("QueueEntry entry=%p", this);
|
||||
mPerformance->QueueLargestContentfulPaintEntry(this);
|
||||
|
||||
ReportLCPToNavigationTimings();
|
||||
}
|
||||
|
||||
void LargestContentfulPaint::GetUrl(nsAString& aUrl) {
|
||||
@ -469,11 +465,20 @@ void LCPHelpers::CreateLCPEntryForImage(
|
||||
nsCOMPtr<nsIURI> requestURI;
|
||||
aRequestProxy->GetURI(getter_AddRefs(requestURI));
|
||||
|
||||
imgRequest* request = aRequestProxy->GetOwner();
|
||||
// We should never get here unless request is valid.
|
||||
MOZ_ASSERT(request);
|
||||
|
||||
bool taoPassed = request->IsData() || request->ShouldReportRenderTimeForLCP();
|
||||
// https://wicg.github.io/element-timing/#report-image-element-timing
|
||||
// For TAO failed requests, the renderTime is exposed as 0 for
|
||||
// security reasons.
|
||||
//
|
||||
// At this point, we have all the information about the entry
|
||||
// except the size.
|
||||
RefPtr<LargestContentfulPaint> entry =
|
||||
new LargestContentfulPaint(aPerformance, aRenderTime, aLoadTime, 0,
|
||||
requestURI, aElement, Some(aImageEntryKey));
|
||||
RefPtr<LargestContentfulPaint> entry = new LargestContentfulPaint(
|
||||
aPerformance, aRenderTime, aLoadTime, 0, requestURI, aElement,
|
||||
Some(aImageEntryKey), taoPassed);
|
||||
|
||||
LOG(" Upsert a LargestContentfulPaint entry=%p to LCPEntryMap.",
|
||||
entry.get());
|
||||
@ -496,8 +501,9 @@ void LCPHelpers::FinalizeLCPEntryForText(
|
||||
|
||||
aContainingBlock->SetFlags(ELEMENT_PROCESSED_BY_LCP_FOR_TEXT);
|
||||
|
||||
RefPtr<LargestContentfulPaint> entry = new LargestContentfulPaint(
|
||||
aPerformance, aRenderTime, 0, 0, nullptr, aContainingBlock, Nothing());
|
||||
RefPtr<LargestContentfulPaint> entry =
|
||||
new LargestContentfulPaint(aPerformance, aRenderTime, 0, 0, nullptr,
|
||||
aContainingBlock, Nothing(), true);
|
||||
|
||||
entry->UpdateSize(aContainingBlock, aTargetRectRelativeToSelf, aPerformance,
|
||||
false);
|
||||
@ -512,4 +518,31 @@ void LCPHelpers::FinalizeLCPEntryForText(
|
||||
}
|
||||
entry->QueueEntry();
|
||||
}
|
||||
|
||||
void LargestContentfulPaint::ReportLCPToNavigationTimings() {
|
||||
const Document* document = mElement->OwnerDoc();
|
||||
|
||||
MOZ_ASSERT(document);
|
||||
|
||||
nsDOMNavigationTiming* timing = document->GetNavigationTiming();
|
||||
|
||||
if (MOZ_UNLIKELY(!timing)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (document->IsResourceDoc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (BrowsingContext* browsingContext = document->GetBrowsingContext()) {
|
||||
if (browsingContext->GetEmbeddedInContentDocument()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!document->IsTopLevelContentDocument()) {
|
||||
return;
|
||||
}
|
||||
timing->NotifyLargestContentfulRenderForRootContentDocument(mRenderTime);
|
||||
}
|
||||
} // namespace mozilla::dom
|
||||
|
@ -168,12 +168,13 @@ class LargestContentfulPaint final : public PerformanceEntry {
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(LargestContentfulPaint,
|
||||
PerformanceEntry)
|
||||
|
||||
LargestContentfulPaint(
|
||||
PerformanceMainThread* aPerformance,
|
||||
const DOMHighResTimeStamp aRenderTime,
|
||||
const DOMHighResTimeStamp aLoadTime, const unsigned long aSize,
|
||||
nsIURI* aURI, Element* aElement,
|
||||
const Maybe<const LCPImageEntryKey>& aLCPImageEntryKey);
|
||||
LargestContentfulPaint(PerformanceMainThread* aPerformance,
|
||||
const DOMHighResTimeStamp aRenderTime,
|
||||
const DOMHighResTimeStamp aLoadTime,
|
||||
const unsigned long aSize, nsIURI* aURI,
|
||||
Element* aElement,
|
||||
const Maybe<const LCPImageEntryKey>& aLCPImageEntryKey,
|
||||
bool aShouldExposeRenderTime);
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
@ -212,10 +213,17 @@ class LargestContentfulPaint final : public PerformanceEntry {
|
||||
private:
|
||||
~LargestContentfulPaint() = default;
|
||||
|
||||
void ReportLCPToNavigationTimings();
|
||||
|
||||
RefPtr<PerformanceMainThread> mPerformance;
|
||||
|
||||
// This is always set but only exposed to web content if
|
||||
// mShouldExposeRenderTime is true.
|
||||
DOMHighResTimeStamp mRenderTime;
|
||||
DOMHighResTimeStamp mLoadTime;
|
||||
// This is set to false when for security reasons web content it not allowed
|
||||
// to see the RenderTime.
|
||||
const bool mShouldExposeRenderTime;
|
||||
unsigned long mSize;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user