зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1298381: Implement TimeToFirstContentfulPaint behind a pref r=mattwoodrow,smaug
This commit is contained in:
Родитель
6183e66d60
Коммит
a37d80eed4
|
@ -52,6 +52,8 @@ nsDOMNavigationTiming::Clear()
|
|||
mDOMContentLoadedEventStart = TimeStamp();
|
||||
mDOMContentLoadedEventEnd = TimeStamp();
|
||||
mDOMComplete = TimeStamp();
|
||||
mContentfulPaint = TimeStamp();
|
||||
mNonBlankPaint = TimeStamp();
|
||||
|
||||
mDocShellHasBeenActiveSinceNavigationStart = false;
|
||||
}
|
||||
|
@ -308,7 +310,7 @@ nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer)
|
|||
{
|
||||
// Check TTI: see if it's been 5 seconds since the last Long Task
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
MOZ_RELEASE_ASSERT(!mNonBlankPaint.IsNull(), "TTI timeout with no non-blank-paint?");
|
||||
MOZ_RELEASE_ASSERT(!mContentfulPaint.IsNull(), "TTI timeout with no contentful-paint?");
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
TimeStamp lastLongTaskEnded;
|
||||
|
@ -323,11 +325,10 @@ nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer)
|
|||
return;
|
||||
}
|
||||
}
|
||||
// To correctly implement TTI/TTFI as proposed, we'd need to use
|
||||
// FirstContentfulPaint (FCP, which we have not yet implemented) instead
|
||||
// of FirstNonBlankPaing (FNBP) to start at, and not fire it until there
|
||||
// are no more than 2 network loads. By the proposed definition, without
|
||||
// that we're closer to TimeToFirstInteractive.
|
||||
// To correctly implement TTI/TTFI as proposed, we'd need to not
|
||||
// fire it until there are no more than 2 network loads. By the
|
||||
// proposed definition, without that we're closer to
|
||||
// TimeToFirstInteractive.
|
||||
|
||||
// XXX check number of network loads, and if > 2 mark to check if loads
|
||||
// decreases to 2 (or record that point and let the normal timer here
|
||||
|
@ -341,7 +342,7 @@ nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer)
|
|||
mTTFI = MaxWithinWindowBeginningAtMin(lastLongTaskEnded, mDOMContentLoadedEventEnd,
|
||||
TimeDuration::FromMilliseconds(TTI_WINDOW_SIZE_MS));
|
||||
if (mTTFI.IsNull()) {
|
||||
mTTFI = mNonBlankPaint;
|
||||
mTTFI = mContentfulPaint;
|
||||
}
|
||||
}
|
||||
// XXX Implement TTI via check number of network loads, and if > 2 mark
|
||||
|
@ -399,15 +400,6 @@ nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument()
|
|||
}
|
||||
#endif
|
||||
|
||||
if (!mTTITimer) {
|
||||
mTTITimer = NS_NewTimer();
|
||||
}
|
||||
|
||||
// TTI is first checked 5 seconds after the FCP (non-blank-paint is very close to FCP).
|
||||
mTTITimer->InitWithNamedFuncCallback(TTITimeoutCallback, this, TTI_WINDOW_SIZE_MS,
|
||||
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
|
||||
"nsDOMNavigationTiming::TTITimeout");
|
||||
|
||||
if (mDocShellHasBeenActiveSinceNavigationStart) {
|
||||
if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization(mNavigationStart)) {
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_NETOPT_MS,
|
||||
|
@ -425,6 +417,42 @@ nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyContentfulPaintForRootContentDocument()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mNavigationStart.IsNull());
|
||||
|
||||
if (!mContentfulPaint.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mContentfulPaint = TimeStamp::Now();
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (profiler_is_active()) {
|
||||
TimeDuration elapsed = mContentfulPaint - mNavigationStart;
|
||||
nsAutoCString spec;
|
||||
if (mLoadedURI) {
|
||||
mLoadedURI->GetSpec(spec);
|
||||
}
|
||||
nsPrintfCString marker("Contentful paint after %dms for URL %s, %s",
|
||||
int(elapsed.ToMilliseconds()), spec.get(),
|
||||
mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and first non-blank paint");
|
||||
profiler_add_marker(marker.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mTTITimer) {
|
||||
mTTITimer = NS_NewTimer();
|
||||
}
|
||||
|
||||
// TTI is first checked 5 seconds after the FCP (non-blank-paint is very close to FCP).
|
||||
mTTITimer->InitWithNamedFuncCallback(TTITimeoutCallback, this, TTI_WINDOW_SIZE_MS,
|
||||
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
|
||||
"nsDOMNavigationTiming::TTITimeout");
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyDOMContentFlushedForRootContentDocument()
|
||||
{
|
||||
|
|
|
@ -97,6 +97,10 @@ public:
|
|||
{
|
||||
return TimeStampToDOM(mNonBlankPaint);
|
||||
}
|
||||
DOMTimeMilliSec GetTimeToContentfulPaint() const
|
||||
{
|
||||
return TimeStampToDOM(mContentfulPaint);
|
||||
}
|
||||
DOMTimeMilliSec GetTimeToTTFI() const
|
||||
{
|
||||
return TimeStampToDOM(mTTFI);
|
||||
|
@ -174,6 +178,7 @@ public:
|
|||
|
||||
void NotifyLongTask(mozilla::TimeStamp aWhen);
|
||||
void NotifyNonBlankPaintForRootContentDocument();
|
||||
void NotifyContentfulPaintForRootContentDocument();
|
||||
void NotifyDOMContentFlushedForRootContentDocument();
|
||||
void NotifyDocShellStateChanged(DocShellState aDocShellState);
|
||||
|
||||
|
@ -209,6 +214,7 @@ private:
|
|||
DOMHighResTimeStamp mNavigationStartHighRes;
|
||||
mozilla::TimeStamp mNavigationStart;
|
||||
mozilla::TimeStamp mNonBlankPaint;
|
||||
mozilla::TimeStamp mContentfulPaint;
|
||||
mozilla::TimeStamp mDOMContentFlushed;
|
||||
|
||||
mozilla::TimeStamp mBeforeUnloadStart;
|
||||
|
|
|
@ -396,6 +396,7 @@ NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver)
|
|||
HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
|
||||
: nsGenericHTMLElement(std::move(aNodeInfo)),
|
||||
mResetLayer(true) ,
|
||||
mMaybeModified(false) ,
|
||||
mWriteOnly(false)
|
||||
{}
|
||||
|
||||
|
@ -1010,6 +1011,7 @@ HTMLCanvasElement::GetContext(const nsAString& aContextId,
|
|||
nsISupports** aContext)
|
||||
{
|
||||
ErrorResult rv;
|
||||
mMaybeModified = true; // For FirstContentfulPaint
|
||||
*aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
@ -1024,6 +1026,7 @@ HTMLCanvasElement::GetContext(JSContext* aCx,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
mMaybeModified = true; // For FirstContentfulPaint
|
||||
return CanvasRenderingContextHelper::GetContext(aCx, aContextId,
|
||||
aContextOptions.isObject() ? aContextOptions : JS::NullHandleValue,
|
||||
aRv);
|
||||
|
|
|
@ -349,6 +349,8 @@ public:
|
|||
|
||||
already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
|
||||
|
||||
bool MaybeModified() const { return mMaybeModified; };
|
||||
|
||||
protected:
|
||||
virtual ~HTMLCanvasElement();
|
||||
|
||||
|
@ -387,6 +389,7 @@ protected:
|
|||
AsyncCanvasRenderer* GetAsyncCanvasRenderer();
|
||||
|
||||
bool mResetLayer;
|
||||
bool mMaybeModified; // we fetched the context, so we may have written to the canvas
|
||||
RefPtr<HTMLCanvasElement> mOriginalCanvas;
|
||||
RefPtr<PrintCallback> mPrintCallback;
|
||||
RefPtr<HTMLCanvasPrintState> mPrintState;
|
||||
|
|
|
@ -440,6 +440,20 @@ public:
|
|||
mPerformance->GetRandomTimelineSeed());
|
||||
}
|
||||
|
||||
DOMTimeMilliSec TimeToContentfulPaint() const
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() ||
|
||||
nsContentUtils::ShouldResistFingerprinting()) {
|
||||
return 0;
|
||||
}
|
||||
if (mPerformance->IsSystemPrincipal()) {
|
||||
return GetDOMTiming()->GetTimeToContentfulPaint();
|
||||
}
|
||||
return nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
GetDOMTiming()->GetTimeToContentfulPaint(),
|
||||
mPerformance->GetRandomTimelineSeed());
|
||||
}
|
||||
|
||||
DOMTimeMilliSec TimeToDOMContentFlushed() const
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() ||
|
||||
|
|
|
@ -39,6 +39,10 @@ interface PerformanceTiming {
|
|||
[Pref="dom.performance.time_to_non_blank_paint.enabled"]
|
||||
readonly attribute unsigned long long timeToNonBlankPaint;
|
||||
|
||||
// Returns 0 if a contentful paint has not happened.
|
||||
[Pref="dom.performance.time_to_contentful_paint.enabled"]
|
||||
readonly attribute unsigned long long timeToContentfulPaint;
|
||||
|
||||
// This is a Mozilla proprietary extension and not part of the
|
||||
// performance/navigation timing specification. It marks the
|
||||
// completion of the first presentation flush after DOMContentLoaded.
|
||||
|
|
|
@ -251,7 +251,8 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
|
|||
mHasWarnedAboutTooLargeDashedOrDottedRadius(false),
|
||||
mQuirkSheetAdded(false),
|
||||
mNeedsPrefUpdate(false),
|
||||
mHadNonBlankPaint(false)
|
||||
mHadNonBlankPaint(false),
|
||||
mHadContentfulPaint(false)
|
||||
#ifdef DEBUG
|
||||
, mInitialized(false)
|
||||
#endif
|
||||
|
@ -2892,6 +2893,22 @@ nsPresContext::NotifyNonBlankPaint()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::NotifyContentfulPaint()
|
||||
{
|
||||
if (!mHadContentfulPaint) {
|
||||
mHadContentfulPaint = true;
|
||||
if (IsRootContentDocument()) {
|
||||
RefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
|
||||
if (timing) {
|
||||
timing->NotifyContentfulPaintForRootContentDocument();
|
||||
}
|
||||
|
||||
mFirstContentfulPaintTime = TimeStamp::Now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::NotifyDOMContentFlushed()
|
||||
{
|
||||
|
|
|
@ -1120,8 +1120,11 @@ public:
|
|||
bool HadNonBlankPaint() const {
|
||||
return mHadNonBlankPaint;
|
||||
}
|
||||
|
||||
bool HadContentfulPaint() const {
|
||||
return mHadContentfulPaint;
|
||||
}
|
||||
void NotifyNonBlankPaint();
|
||||
void NotifyContentfulPaint();
|
||||
void NotifyDOMContentFlushed();
|
||||
|
||||
bool UsesRootEMUnits() const {
|
||||
|
@ -1398,6 +1401,7 @@ protected:
|
|||
// Time of various first interaction types, used to report time from
|
||||
// first paint of the top level content pres shell to first interaction.
|
||||
mozilla::TimeStamp mFirstNonBlankPaintTime;
|
||||
mozilla::TimeStamp mFirstContentfulPaintTime;
|
||||
mozilla::TimeStamp mFirstClickTime;
|
||||
mozilla::TimeStamp mFirstKeyTime;
|
||||
mozilla::TimeStamp mFirstMouseMoveTime;
|
||||
|
@ -1474,6 +1478,8 @@ protected:
|
|||
|
||||
// Has NotifyNonBlankPaint been called on this PresContext?
|
||||
unsigned mHadNonBlankPaint : 1;
|
||||
// Has NotifyContentfulPaint been called on this PresContext?
|
||||
unsigned mHadContentfulPaint : 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
unsigned mInitialized : 1;
|
||||
|
|
|
@ -221,6 +221,16 @@ public:
|
|||
|
||||
return LAYER_INACTIVE;
|
||||
}
|
||||
|
||||
// FirstContentfulPaint is supposed to ignore "white" canvases. We use MaybeModified (if
|
||||
// GetContext() was called on the canvas) as a standin for "white"
|
||||
virtual bool IsContentful() const override
|
||||
{
|
||||
nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(Frame());
|
||||
HTMLCanvasElement* canvas =
|
||||
HTMLCanvasElement::FromNode(f->GetContent());
|
||||
return canvas->MaybeModified();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ enum
|
|||
|
||||
enum DisplayItemFlags
|
||||
{
|
||||
TYPE_RENDERS_NO_IMAGES = 1 << 0
|
||||
TYPE_RENDERS_NO_IMAGES = 1 << 0,
|
||||
TYPE_IS_CONTENTFUL = 1 << 1
|
||||
};
|
||||
|
||||
inline const char*
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
// IWYU pragma: private, include "nsDisplayList.h"
|
||||
DECLARE_DISPLAY_ITEM_TYPE(ALT_FEEDBACK, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(THEMED_BACKGROUND, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BLEND_CONTAINER, TYPE_RENDERS_NO_IMAGES)
|
||||
|
@ -15,18 +15,18 @@ DECLARE_DISPLAY_ITEM_TYPE(TABLE_BLEND_MODE, TYPE_RENDERS_NO_IMAGES)
|
|||
DECLARE_DISPLAY_ITEM_TYPE(BORDER, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_OUTER, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_INNER, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BULLET, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BORDER_BACKGROUND, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BOX_SHADOW_OUTER, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BUTTON_FOREGROUND, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BULLET, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BORDER_BACKGROUND, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BOX_SHADOW_OUTER, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(BUTTON_FOREGROUND, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CANVAS, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CANVAS_THEMED_BACKGROUND, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND_IMAGE, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CANVAS_THEMED_BACKGROUND, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND_IMAGE, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CANVAS_FOCUS, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CARET, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CHECKED_CHECKBOX, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CHECKED_RADIOBUTTON, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CARET, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CHECKED_CHECKBOX, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CHECKED_RADIOBUTTON, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(CLEAR_BACKGROUND, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(COLUMN_RULE, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(COMBOBOX_FOCUS, TYPE_RENDERS_NO_IMAGES)
|
||||
|
@ -38,7 +38,7 @@ DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITION, TYPE_RENDERS_NO_IMAGES)
|
|||
DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BORDER, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BLANK, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(HEADER_FOOTER, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(IMAGE, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(IMAGE, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(LIST_FOCUS, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(OPACITY, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(OPTION_EVENT_GRABBER, TYPE_RENDERS_NO_IMAGES)
|
||||
|
@ -58,23 +58,23 @@ DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT, TYPE_RENDERS_NO_IMAGES)
|
|||
DECLARE_DISPLAY_ITEM_TYPE(MASK, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(FILTER, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_CHAR_CLIP, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_CHAR_CLIP, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_WRAPPER, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(FOREIGN_OBJECT, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(FOREIGN_OBJECT, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_BACKGROUND, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_SELECTION, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_COLLAPSE, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_IMAGE, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_THEMED_BACKGROUND_IMAGE, 0)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_IMAGE, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_THEMED_BACKGROUND_IMAGE, TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_FIXED_POSITION, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TEXT, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TEXT, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TRANSFORM, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(PERSPECTIVE, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(VIDEO, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(VIDEO, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(WRAP_LIST, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(ZOOM, TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(GENERIC, TYPE_RENDERS_NO_IMAGES)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "gfxContext.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
@ -1447,6 +1448,40 @@ DisplayListIsNonBlank(nsDisplayList* aList)
|
|||
return false;
|
||||
}
|
||||
|
||||
// A contentful paint is a paint that does contains DOM content (text,
|
||||
// images, non-blank canvases, SVG): "First Contentful Paint entry
|
||||
// contains a DOMHighResTimeStamp reporting the time when the browser
|
||||
// first rendered any text, image (including background images),
|
||||
// non-white canvas or SVG. This excludes any content of iframes, but
|
||||
// includes text with pending webfonts. This is the first time users
|
||||
// could start consuming page content."
|
||||
static bool
|
||||
DisplayListIsContentful(nsDisplayList* aList)
|
||||
{
|
||||
for (nsDisplayItem* i = aList->GetBottom(); i != nullptr; i = i->GetAbove()) {
|
||||
DisplayItemType type = i->GetType();
|
||||
nsDisplayList* children = i->GetChildren();
|
||||
|
||||
switch (type) {
|
||||
case DisplayItemType::TYPE_SUBDOCUMENT: // iframes are ignored
|
||||
break;
|
||||
// CANVASes check if they may have been modified (as a stand-in
|
||||
// actually tracking all modifications)
|
||||
default:
|
||||
if (i->IsContentful()) {
|
||||
return true;
|
||||
}
|
||||
if (children) {
|
||||
if (DisplayListIsContentful(children)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
|
||||
nsDisplayList* aPaintedContents)
|
||||
|
@ -1455,7 +1490,7 @@ nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
|
|||
aReferenceFrame->PresShell(),
|
||||
"Presshell mismatch");
|
||||
|
||||
if (mIsPaintingToWindow) {
|
||||
if (mIsPaintingToWindow && aPaintedContents) {
|
||||
nsPresContext* pc = aReferenceFrame->PresContext();
|
||||
if (!pc->HadNonBlankPaint()) {
|
||||
if (!CurrentPresShellState()->mIsBackgroundOnly &&
|
||||
|
@ -1463,6 +1498,12 @@ nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
|
|||
pc->NotifyNonBlankPaint();
|
||||
}
|
||||
}
|
||||
if (!pc->HadContentfulPaint()) {
|
||||
if (!CurrentPresShellState()->mIsBackgroundOnly &&
|
||||
DisplayListIsContentful(aPaintedContents)) {
|
||||
pc->NotifyContentfulPaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResetMarkedFramesForDisplayList(aReferenceFrame);
|
||||
|
|
|
@ -2411,7 +2411,9 @@ public:
|
|||
*/
|
||||
virtual uint32_t GetPerFrameKey() const { return uint32_t(GetType()); }
|
||||
|
||||
uint8_t GetFlags() { return GetDisplayItemFlagsForType(GetType()); }
|
||||
uint8_t GetFlags() const { return GetDisplayItemFlagsForType(GetType()); }
|
||||
|
||||
virtual bool IsContentful() const { return GetFlags() & TYPE_IS_CONTENTFUL; }
|
||||
|
||||
/**
|
||||
* This is called after we've constructed a display list for event handling.
|
||||
|
|
|
@ -179,6 +179,9 @@ pref("dom.permissions.revoke.enable", false);
|
|||
// Enable exposing timeToNonBlankPaint
|
||||
pref("dom.performance.time_to_non_blank_paint.enabled", false);
|
||||
|
||||
// Enable exposing timeToContentfulPaint
|
||||
pref("dom.performance.time_to_contentful_paint.enabled", false);
|
||||
|
||||
// Enable exposing timeToDOMContentFlushed
|
||||
pref("dom.performance.time_to_dom_content_flushed.enabled", false);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче