Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#ifndef mozilla_dom_LargestContentfulPaint_h___
#define mozilla_dom_LargestContentfulPaint_h___
#include "nsCycleCollectionParticipant.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PerformanceEntry.h"
#include "mozilla/dom/PerformanceLargestContentfulPaintBinding.h"
#include "imgRequestProxy.h"
class nsTextFrame;
namespace mozilla::dom {
static constexpr nsLiteralString kLargestContentfulPaintName =
class Performance;
class PerformanceMainThread;
struct LCPImageEntryKey {
LCPImageEntryKey(Element* aElement, imgRequestProxy* aImgRequestProxy)
: mElement(do_GetWeakReference(aElement)),
mImageRequestProxy(aImgRequestProxy) {
mHash = mozilla::HashGeneric(reinterpret_cast<uintptr_t>(aElement),
LCPImageEntryKey(const LCPImageEntryKey& aLCPImageEntryKey) {
mElement = aLCPImageEntryKey.mElement;
mImageRequestProxy = aLCPImageEntryKey.mImageRequestProxy;
mHash = aLCPImageEntryKey.mHash;
Element* GetElement() const {
nsCOMPtr<Element> element = do_QueryReferent(mElement);
return element;
imgRequestProxy* GetImgRequestProxy() const {
return static_cast<imgRequestProxy*>(mImageRequestProxy.get());
bool operator==(const LCPImageEntryKey& aOther) const {
imgRequestProxy* imgRequest = GetImgRequestProxy();
if (!imgRequest) {
return false;
imgRequestProxy* otherImgRequest = aOther.GetImgRequestProxy();
if (!otherImgRequest) {
return false;
Element* element = GetElement();
if (!element) {
return false;
Element* otherElement = aOther.GetElement();
if (!otherElement) {
return false;
return element == otherElement && imgRequest == otherImgRequest;
nsWeakPtr mElement;
WeakPtr<PreloaderBase> mImageRequestProxy;
PLDHashNumber mHash = 0;
~LCPImageEntryKey() = default;
struct LCPTextFrameHelper final {
static void MaybeUnionTextFrame(nsTextFrame* aTextFrame,
const nsRect& aRelativeToSelfRect);
class ImagePendingRendering final {
ImagePendingRendering(const LCPImageEntryKey& aLCPImageEntryKey,
const TimeStamp& aLoadTime);
Element* GetElement() const { return mLCPImageEntryKey.GetElement(); }
imgRequestProxy* GetImgRequestProxy() const {
return mLCPImageEntryKey.GetImgRequestProxy();
LCPImageEntryKey mLCPImageEntryKey;
TimeStamp mLoadTime;
class LCPEntryHashEntry : public PLDHashEntryHdr {
typedef const LCPImageEntryKey& KeyType;
typedef const LCPImageEntryKey* KeyTypePointer;
explicit LCPEntryHashEntry(KeyTypePointer aKey) : mKey(*aKey) {}
LCPEntryHashEntry(LCPEntryHashEntry&&) = default;
~LCPEntryHashEntry() = default;
bool KeyEquals(KeyTypePointer aKey) const { return mKey == *aKey; }
KeyType GetKey() const { return mKey; }
static KeyTypePointer KeyToPointer(KeyType& aKey) { return &aKey; }
static PLDHashNumber HashKey(KeyTypePointer aKey) { return aKey->mHash; }
enum { ALLOW_MEMMOVE = true };
LCPImageEntryKey mKey;
class LCPHelpers final {
// Creates the LCP Entry for images with all information except the size of
// the element. The size of the image is unknown at the moment. The entry is
// not going to be queued in this function.
static void CreateLCPEntryForImage(
PerformanceMainThread* aPerformance, Element* aElement,
imgRequestProxy* aRequestProxy, const TimeStamp& aLoadTime,
const TimeStamp& aRenderTime, const LCPImageEntryKey& aContentIdentifier);
// Called when the size of the image is known.
static void FinalizeLCPEntryForImage(Element* aContainingBlock,
imgRequestProxy* aImgRequestProxy,
const nsRect& aTargetRectRelativeToSelf);
static void FinalizeLCPEntryForText(PerformanceMainThread* aPerformance,
const TimeStamp& aRenderTime,
Element* aContainingBlock,
const nsRect& aTargetRectRelativeToSelf,
const nsPresContext* aPresContext);
static bool IsQualifiedImageRequest(imgRequest* aRequest,
Element* aContainingElement);
static bool CanFinalizeLCPEntry(const nsIFrame* aFrame);
class LargestContentfulPaint final : public PerformanceEntry {
LargestContentfulPaint(PerformanceMainThread* aPerformance,
const TimeStamp& aRenderTime,
const Maybe<TimeStamp>& 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;
DOMHighResTimeStamp RenderTime() const;
DOMHighResTimeStamp LoadTime() const;
DOMHighResTimeStamp StartTime() const override;
unsigned long Size() const { return mSize; }
void GetId(nsAString& aId) const {
if (mId) {
void GetUrl(nsAString& aUrl);
Element* GetElement() const;
static Element* GetContainingBlockForTextFrame(const nsTextFrame* aTextFrame);
void UpdateSize(const Element* aContainingBlock,
const nsRect& aTargetRectRelativeToSelf,
const PerformanceMainThread* aPerformance, bool aIsImage);
void BufferEntryIfNeeded() override;
static void MaybeProcessImageForElementTiming(imgRequestProxy* aRequest,
Element* aElement);
void QueueEntry();
Maybe<LCPImageEntryKey>& GetLCPImageEntryKey() { return mLCPImageEntryKey; }
~LargestContentfulPaint() = default;
void ReportLCPToNavigationTimings();
RefPtr<PerformanceMainThread> mPerformance;
// This is always set but only exposed to web content if
// mShouldExposeRenderTime is true.
const TimeStamp mRenderTime;
const Maybe<TimeStamp> 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;
nsWeakPtr mElement;
RefPtr<nsAtom> mId;
Maybe<LCPImageEntryKey> mLCPImageEntryKey;
} // namespace mozilla::dom