Bug 1891335 - Compute EffectInfo updates at IntersectionObserver time. r=smaug,hiro

What goes on here is that there's a couple of unfortunate style change
sequences which end up making us not do the EffectsInfo dance correctly.

Twitter uses (maybe didn't use to, which would explain the regression) a
visibility: hidden, out-of-flow iframe for a bit (which we correctly
throttle). But then they switch to an in-flow, visible, zero-height
iframe. That we should _not_ throttle. However, we end up not getting to
the display list code at all, because nsBlockFrame decides that we don't
need to descend into an empty line[1].

It seems less error prone to re-use the IntersectionObserver timing and
computation to determine whether the iframe is visible. That completely
matches in-process iframes, too.

Removing the empty frame border and putting them on an empty line in
dom/base/test/test_bug1639328.html is enough to reproduce the issue
without this patch.

[1]: https://searchfox.org/mozilla-central/rev/fe2743c6c5c708061c7f6504b26958fcc815bb4a/layout/generic/nsBlockFrame.cpp#7569-7579

Differential Revision: https://phabricator.services.mozilla.com/D207479
This commit is contained in:
Emilio Cobos Álvarez
2024-09-05 17:16:12 +00:00
parent d1c713eb50
commit f20aebf2fc
16 changed files with 162 additions and 174 deletions

View File

@@ -165,6 +165,21 @@ static LengthPercentage PrefMargin(float aValue, bool aIsPercentage) {
: LengthPercentage::FromPixels(aValue);
}
StyleRect<LengthPercentage> DOMIntersectionObserver::LazyLoadingRootMargin() {
StyleRect<LengthPercentage> margin;
#define SET_MARGIN(side_, side_lower_) \
margin.Get(eSide##side_) = PrefMargin( \
StaticPrefs::dom_image_lazy_loading_root_margin_##side_lower_(), \
StaticPrefs:: \
dom_image_lazy_loading_root_margin_##side_lower_##_percentage());
SET_MARGIN(Top, top);
SET_MARGIN(Right, right);
SET_MARGIN(Bottom, bottom);
SET_MARGIN(Left, left);
#undef SET_MARGIN
return margin;
}
DOMIntersectionObserver::DOMIntersectionObserver(Document& aDocument,
NativeCallback aCallback)
: mOwner(aDocument.GetInnerWindow()),
@@ -176,18 +191,7 @@ DOMIntersectionObserver::CreateLazyLoadObserver(Document& aDocument) {
RefPtr<DOMIntersectionObserver> observer =
new DOMIntersectionObserver(aDocument, LazyLoadCallback);
observer->mThresholds.AppendElement(0.0f);
#define SET_MARGIN(side_, side_lower_) \
observer->mRootMargin.Get(eSide##side_) = PrefMargin( \
StaticPrefs::dom_image_lazy_loading_root_margin_##side_lower_(), \
StaticPrefs:: \
dom_image_lazy_loading_root_margin_##side_lower_##_percentage());
SET_MARGIN(Top, top);
SET_MARGIN(Right, right);
SET_MARGIN(Bottom, bottom);
SET_MARGIN(Left, left);
#undef SET_MARGIN
observer->mRootMargin = LazyLoadingRootMargin();
return observer.forget();
}
@@ -324,7 +328,8 @@ static const Document* GetTopLevelContentDocumentInThisProcess(
// In case of out-of-process document, aRemoteDocumentVisibleRect is a rectangle
// in the out-of-process document's coordinate system.
static Maybe<nsRect> ComputeTheIntersection(
nsIFrame* aTarget, nsIFrame* aRoot, const nsRect& aRootBounds,
nsIFrame* aTarget, const nsRect& aTargetRectRelativeToTarget,
nsIFrame* aRoot, const nsRect& aRootBounds,
const Maybe<nsRect>& aRemoteDocumentVisibleRect,
DOMIntersectionObserver::IsForProximityToViewport
aIsForProximityToViewport) {
@@ -333,21 +338,7 @@ static Maybe<nsRect> ComputeTheIntersection(
// getBoundingClientRect() algorithm on the target.
//
// `intersectionRect` is kept relative to `target` during the loop.
auto inflowRect = nsLayoutUtils::GetAllInFlowRectsUnion(
target, target,
nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms);
// For content-visibility, we need to observe the overflow clip edge,
// https://drafts.csswg.org/css-contain-2/#close-to-the-viewport
if (aIsForProximityToViewport ==
DOMIntersectionObserver::IsForProximityToViewport::Yes) {
const auto& disp = *target->StyleDisplay();
auto clipAxes = target->ShouldApplyOverflowClipping(&disp);
if (!clipAxes.isEmpty()) {
inflowRect = OverflowAreas::GetOverflowClipRect(
inflowRect, inflowRect, clipAxes,
target->OverflowClipMargin(clipAxes));
}
}
auto inflowRect = aTargetRectRelativeToTarget;
Maybe<nsRect> intersectionRect = Some(inflowRect);
// 2. Let container be the containing block of the target.
@@ -633,7 +624,7 @@ IntersectionInput DOMIntersectionObserver::ComputeInput(
// https://w3c.github.io/IntersectionObserver/#update-intersection-observations-algo
// (steps 2.1 - 2.5)
IntersectionOutput DOMIntersectionObserver::Intersect(
const IntersectionInput& aInput, const Element& aTarget,
const IntersectionInput& aInput, const Element& aTarget, BoxToUse aBoxToUse,
IsForProximityToViewport aIsForProximityToViewport) {
const bool isSimilarOrigin = SimilarOrigin(aTarget, aInput.mRootNode) ==
BrowsingContextOrigin::Similar;
@@ -681,24 +672,39 @@ IntersectionOutput DOMIntersectionObserver::Intersect(
}
// 2.4. Set targetRect to the DOMRectReadOnly obtained by running the
// getBoundingClientRect() algorithm on target.
nsRect targetRect = targetFrame->GetBoundingClientRect();
// For content-visibility, we need to observe the overflow clip edge,
// https://drafts.csswg.org/css-contain-2/#close-to-the-viewport
if (aIsForProximityToViewport == IsForProximityToViewport::Yes) {
// getBoundingClientRect() algorithm on target. We compute the box relative to
// self first, then transform.
nsLayoutUtils::GetAllInFlowRectsFlags flags{
nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms};
if (aBoxToUse == BoxToUse::Content) {
flags += nsLayoutUtils::GetAllInFlowRectsFlag::UseContentBox;
}
nsRect targetRectRelativeToTarget =
nsLayoutUtils::GetAllInFlowRectsUnion(targetFrame, targetFrame, flags);
if (aBoxToUse == BoxToUse::OverflowClip) {
const auto& disp = *targetFrame->StyleDisplay();
auto clipAxes = targetFrame->ShouldApplyOverflowClipping(&disp);
if (!clipAxes.isEmpty()) {
targetRect = OverflowAreas::GetOverflowClipRect(
targetRect, targetRect, clipAxes,
targetRectRelativeToTarget = OverflowAreas::GetOverflowClipRect(
targetRectRelativeToTarget, targetRectRelativeToTarget, clipAxes,
targetFrame->OverflowClipMargin(clipAxes));
}
}
auto targetRect = nsLayoutUtils::TransformFrameRectToAncestor(
targetFrame, targetRectRelativeToTarget,
nsLayoutUtils::GetContainingBlockForClientRect(targetFrame));
// For content-visibility, we need to observe the overflow clip edge,
// https://drafts.csswg.org/css-contain-2/#close-to-the-viewport
MOZ_ASSERT_IF(aIsForProximityToViewport == IsForProximityToViewport::Yes,
aBoxToUse == BoxToUse::OverflowClip);
// 2.5. Let intersectionRect be the result of running the compute the
// intersection algorithm on target and observers intersection root.
Maybe<nsRect> intersectionRect = ComputeTheIntersection(
targetFrame, aInput.mRootFrame, rootBounds,
targetFrame, targetRectRelativeToTarget, aInput.mRootFrame, rootBounds,
aInput.mRemoteDocumentVisibleRect, aIsForProximityToViewport);
return {isSimilarOrigin, rootBounds, targetRect, intersectionRect};

View File

@@ -148,13 +148,20 @@ class DOMIntersectionObserver final : public nsISupports,
void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal);
static StyleRect<LengthPercentage> LazyLoadingRootMargin();
static IntersectionInput ComputeInput(
const Document& aDocument, const nsINode* aRoot,
const StyleRect<LengthPercentage>* aRootMargin);
enum class IsForProximityToViewport : bool { No, Yes };
enum class BoxToUse : uint8_t {
Content,
Border,
OverflowClip,
};
static IntersectionOutput Intersect(
const IntersectionInput&, const Element&,
const IntersectionInput&, const Element&, BoxToUse = BoxToUse::Border,
IsForProximityToViewport = IsForProximityToViewport::No);
// Intersects with a given rect, already relative to the root frame.
static IntersectionOutput Intersect(const IntersectionInput&, const nsRect&);

View File

@@ -215,6 +215,7 @@
#include "mozilla/dom/ProcessingInstruction.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/RemoteBrowser.h"
#include "mozilla/dom/ResizeObserver.h"
#include "mozilla/dom/RustTypes.h"
#include "mozilla/dom/SVGElement.h"
@@ -431,6 +432,7 @@
#include "nsStyleSheetService.h"
#include "nsStyleStruct.h"
#include "nsTextControlFrame.h"
#include "nsSubDocumentFrame.h"
#include "nsTextNode.h"
#include "nsUnicharUtils.h"
#include "nsWrapperCache.h"
@@ -7376,14 +7378,15 @@ bool Document::ShouldThrottleFrameRequests() const {
}
// Note that because we have to scroll this document into view at least once
// to unthrottle it, we will drop one requestAnimationFrame frame when a
// to un-throttle it, we will drop one requestAnimationFrame frame when a
// document that previously wasn't visible scrolls into view. This is
// acceptable / unlikely to be human-perceivable, though we could improve on
// it if needed by adding an intersection margin or something of that sort.
auto margin = DOMIntersectionObserver::LazyLoadingRootMargin();
const IntersectionInput input = DOMIntersectionObserver::ComputeInput(
*el->OwnerDoc(), /* aRoot = */ nullptr, /* aRootMargin = */ nullptr);
const IntersectionOutput output =
DOMIntersectionObserver::Intersect(input, *el);
*el->OwnerDoc(), /* aRoot = */ nullptr, &margin);
const IntersectionOutput output = DOMIntersectionObserver::Intersect(
input, *el, DOMIntersectionObserver::BoxToUse::Content);
return !output.Intersects();
}
@@ -16843,6 +16846,66 @@ void Document::UpdateIntersections(TimeStamp aNowTime) {
});
}
void Document::UpdateRemoteFrameEffects() {
if (auto* wc = GetWindowContext(); wc && !wc->Children().IsEmpty()) {
auto margin = DOMIntersectionObserver::LazyLoadingRootMargin();
const IntersectionInput input = DOMIntersectionObserver::ComputeInput(
*this, /* aRoot = */ nullptr, &margin);
for (const RefPtr<BrowsingContext>& child : wc->Children()) {
Element* el = child->GetEmbedderElement();
if (!el) {
continue;
}
auto* rb = RemoteBrowser::GetFrom(el);
if (!rb) {
continue;
}
EffectsInfo info = [&] {
if (Hidden()) {
// If we're in the background, then the child frame should be hidden
// as well.
return EffectsInfo::FullyHidden();
}
const IntersectionOutput output = DOMIntersectionObserver::Intersect(
input, *el, DOMIntersectionObserver::BoxToUse::Content);
if (!output.Intersects()) {
// XXX do we want to pass the scale and such down even if out of the
// viewport?
return EffectsInfo::FullyHidden();
}
auto* frame = el->GetPrimaryFrame();
MOZ_ASSERT(frame, "How do we intersect with no frame?");
MOZ_ASSERT(frame->IsSubDocumentFrame(), "Hm?");
Maybe<nsRect> visibleRect;
gfx::MatrixScales rasterScale;
if (nsSubDocumentFrame* f = do_QueryFrame(frame)) {
visibleRect = f->GetVisibleRect();
if (!visibleRect) {
// If we have no visible rect (e.g., because we are zero-sized) we
// still want to provide the intersection rect in order to get the
// right throttling behavior.
visibleRect.emplace(*output.mIntersectionRect -
output.mTargetRect.TopLeft());
}
rasterScale = f->GetRasterScale();
}
ParentLayerToScreenScale2D transformToAncestorScale =
ParentLayerToParentLayerScale(
frame->PresShell()->GetCumulativeResolution()) *
nsLayoutUtils::
GetTransformToAncestorScaleCrossProcessForFrameMetrics(frame);
return EffectsInfo::VisibleWithinRect(visibleRect, rasterScale,
transformToAncestorScale);
}();
rb->UpdateEffects(std::move(info));
}
}
EnumerateSubDocuments([](Document& aDoc) {
aDoc.UpdateRemoteFrameEffects();
return CallState::Continue;
});
}
void Document::NotifyIntersectionObservers() {
const auto observers = ToTArray<nsTArray<RefPtr<DOMIntersectionObserver>>>(
mIntersectionObservers);

View File

@@ -3753,6 +3753,8 @@ class Document : public nsINode,
// Update intersection observers in this document and all
// same-process subdocuments.
void UpdateIntersections(TimeStamp aNowTime);
// Update the EffectsInfo of remote browsers.
void UpdateRemoteFrameEffects();
MOZ_CAN_RUN_SCRIPT void NotifyIntersectionObservers();
DOMIntersectionObserver* GetLazyLoadObserver() { return mLazyLoadObserver; }

View File

@@ -1158,6 +1158,10 @@ void nsFrameLoader::Hide() {
return;
}
if (mRemoteBrowser) {
mRemoteBrowser->UpdateEffects(EffectsInfo::FullyHidden());
}
if (!GetDocShell()) {
return;
}

View File

@@ -10,20 +10,24 @@
height: 10px;
}
iframe[id^=zero-size] {
border: none;
width: 0;
height: 0;
}
</style>
<iframe id="http" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="http" src="http://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="https" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="same-origin" src="file_bug1639328.html"></iframe>
<iframe id="zero-size-http" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<br>
<iframe id="zero-size-http" src="http://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="zero-size-https" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="zero-size-same-origin" src="file_bug1639328.html"></iframe>
<iframe id="display-none-http" style="display: none" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<br>
<iframe id="display-none-http" style="display: none" src="http://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="display-none-https" style="display: none" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="display-none-same-origin" style="display: none" src="file_bug1639328.html"></iframe>
<iframe id="vis-hidden-http" style="visibility: hidden" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<br>
<iframe id="vis-hidden-http" style="visibility: hidden" src="http://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="vis-hidden-https" style="visibility: hidden" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
<iframe id="vis-hidden-same-origin" style="visibility: hidden" src="file_bug1639328.html"></iframe>
<script>

View File

@@ -408,16 +408,6 @@ ImageContainer* WebRenderCanvasData::GetImageContainer() {
void WebRenderCanvasData::ClearImageContainer() { mContainer = nullptr; }
WebRenderRemoteData::WebRenderRemoteData(RenderRootStateManager* aManager,
nsDisplayItem* aItem)
: WebRenderUserData(aManager, aItem) {}
WebRenderRemoteData::~WebRenderRemoteData() {
if (mRemoteBrowser) {
mRemoteBrowser->UpdateEffects(mozilla::dom::EffectsInfo::FullyHidden());
}
}
void DestroyWebRenderUserDataTable(WebRenderUserDataTable* aTable) {
for (const auto& value : aTable->Values()) {
value->RemoveFromTable();

View File

@@ -13,7 +13,6 @@
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/AnimationInfo.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/dom/RemoteBrowser.h"
#include "mozilla/UniquePtr.h"
#include "nsIFrame.h"
#include "nsRefPtrHashtable.h"
@@ -307,22 +306,6 @@ class WebRenderCanvasData : public WebRenderUserData {
RefPtr<ImageContainer> mContainer;
};
class WebRenderRemoteData : public WebRenderUserData {
public:
WebRenderRemoteData(RenderRootStateManager* aManager, nsDisplayItem* aItem);
virtual ~WebRenderRemoteData();
UserDataType GetType() override { return UserDataType::eRemote; }
static UserDataType Type() { return UserDataType::eRemote; }
void SetRemoteBrowser(dom::RemoteBrowser* aBrowser) {
mRemoteBrowser = aBrowser;
}
protected:
RefPtr<dom::RemoteBrowser> mRemoteBrowser;
};
class WebRenderMaskData : public WebRenderUserData {
public:
explicit WebRenderMaskData(RenderRootStateManager* aManager,

View File

@@ -12228,7 +12228,7 @@ PresShell::ProximityToViewportResult PresShell::DetermineProximityToViewport() {
// 14.2.3.2
bool intersects =
DOMIntersectionObserver::Intersect(
input, *element,
input, *element, DOMIntersectionObserver::BoxToUse::OverflowClip,
DOMIntersectionObserver::IsForProximityToViewport::Yes)
.Intersects();
element->SetVisibleForContentVisibility(intersects);

View File

@@ -2700,17 +2700,6 @@ void PrintHitTestInfoStats(nsDisplayList* aList) {
}
#endif
// Apply a batch of effects updates generated during a paint to their
// respective remote browsers.
static void ApplyEffectsUpdates(
const nsTHashMap<nsPtrHashKey<RemoteBrowser>, EffectsInfo>& aUpdates) {
for (const auto& entry : aUpdates) {
auto* browser = entry.GetKey();
const auto& update = entry.GetData();
browser->UpdateEffects(update);
}
}
static void DumpBeforePaintDisplayList(UniquePtr<std::stringstream>& aStream,
nsDisplayListBuilder* aBuilder,
nsDisplayList* aList,
@@ -3231,11 +3220,6 @@ void nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
}
}
// Apply effects updates if we were actually painting
if (isForPainting) {
ApplyEffectsUpdates(builder->GetEffectUpdates());
}
builder->Check();
{

View File

@@ -2258,6 +2258,10 @@ void nsRefreshDriver::UpdateIntersectionObservations(TimeStamp aNowTime) {
mNeedToUpdateIntersectionObservations = false;
}
void nsRefreshDriver::UpdateRemoteFrameEffects() {
mPresContext->Document()->UpdateRemoteFrameEffects();
}
void nsRefreshDriver::UpdateRelevancyOfContentVisibilityAutoFrames() {
if (!mNeedToUpdateContentRelevancy) {
return;
@@ -2886,6 +2890,10 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime,
mCompositionPayloads.Clear();
}
// This needs to happen after DL building since we rely on the raster scales
// being stored in nsSubDocumentFrame.
UpdateRemoteFrameEffects();
#ifndef ANDROID /* bug 1142079 */
double totalMs = (TimeStamp::Now() - mTickStart).ToMilliseconds();
mozilla::Telemetry::Accumulate(mozilla::Telemetry::REFRESH_DRIVER_TICK,

View File

@@ -500,6 +500,7 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
void RunFrameRequestCallbacks(const nsTArray<RefPtr<mozilla::dom::Document>>&,
mozilla::TimeStamp aNowTime);
void UpdateIntersectionObservations(mozilla::TimeStamp aNowTime);
void UpdateRemoteFrameEffects();
void UpdateRelevancyOfContentVisibilityAutoFrames();
void PerformPendingViewTransitionOperations();
MOZ_CAN_RUN_SCRIPT void

View File

@@ -21,6 +21,7 @@
#include "mozilla/dom/HTMLFrameElement.h"
#include "mozilla/dom/ImageDocument.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/RemoteBrowser.h"
#include "nsCOMPtr.h"
#include "nsGenericHTMLElement.h"
@@ -1298,57 +1299,19 @@ bool nsDisplayRemote::CreateWebRenderCommands(
return true;
}
nsPresContext* pc = mFrame->PresContext();
nsFrameLoader* fl = GetFrameLoader();
auto* subDocFrame = static_cast<nsSubDocumentFrame*>(mFrame);
nsRect destRect = subDocFrame->GetDestRect();
if (RefPtr<RemoteBrowser> remoteBrowser = fl->GetRemoteBrowser()) {
if (pc->GetPrintSettings()) {
// HACK(emilio): Usually we update sizing/positioning from
// ReflowFinished(). Print documents have no incremental reflow at all
// though, so we can't rely on it firing after a frame becomes remote.
// Thus, if we're painting a remote frame, update its sizing and position
// now.
//
// UpdatePositionAndSize() can cause havoc for non-remote frames but
// luckily we don't care about those, so this is fine.
fl->UpdatePositionAndSize(subDocFrame);
}
// Adjust mItemVisibleRect, which is relative to the reference frame, to be
// relative to this frame.
if (aDisplayListBuilder->IsForPainting()) {
subDocFrame->SetRasterScale(aSc.GetInheritedScale());
const nsRect buildingRect = GetBuildingRect() - ToReferenceFrame();
Maybe<nsRect> visibleRect =
buildingRect.EdgeInclusiveIntersection(destRect);
if (visibleRect) {
*visibleRect -= destRect.TopLeft();
}
// Generate an effects update notifying the browser it is visible
MatrixScales scale = aSc.GetInheritedScale();
ParentLayerToScreenScale2D transformToAncestorScale =
ParentLayerToParentLayerScale(
pc->GetPresShell() ? pc->GetPresShell()->GetCumulativeResolution()
: 1.f) *
nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
mFrame);
aDisplayListBuilder->AddEffectUpdate(
remoteBrowser, EffectsInfo::VisibleWithinRect(
visibleRect, scale, transformToAncestorScale));
// Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
// longer visible
RefPtr<WebRenderRemoteData> userData =
aManager->CommandBuilder()
.CreateOrRecycleWebRenderUserData<WebRenderRemoteData>(this,
nullptr);
userData->SetRemoteBrowser(remoteBrowser);
subDocFrame->SetVisibleRect(visibleRect);
}
nscoord auPerDevPixel = pc->AppUnitsPerDevPixel();
nscoord auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
nsPoint layerOffset =
aDisplayListBuilder->ToReferenceFrame(mFrame) + destRect.TopLeft();
mOffset = LayoutDevicePoint::FromAppUnits(layerOffset, auPerDevPixel);

View File

@@ -8,6 +8,7 @@
#define NSSUBDOCUMENTFRAME_H_
#include "mozilla/Attributes.h"
#include "mozilla/gfx/Matrix.h"
#include "nsDisplayList.h"
#include "nsAtomicContainerFrame.h"
#include "nsIReflowCallback.h"
@@ -140,6 +141,15 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame,
RemoteFramePaintData GetRemotePaintData() const;
bool HasRetainedPaintData() const { return mRetainedRemoteFrame.isSome(); }
const mozilla::gfx::MatrixScales& GetRasterScale() const {
return mRasterScale;
}
void SetRasterScale(const mozilla::gfx::MatrixScales& aScale) {
mRasterScale = aScale;
}
const Maybe<nsRect>& GetVisibleRect() const { return mVisibleRect; }
void SetVisibleRect(const Maybe<nsRect>& aRect) { mVisibleRect = aRect; }
protected:
friend class AsyncFrameInit;
@@ -167,6 +177,11 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame,
// one.
Maybe<RemoteFramePaintData> mRetainedRemoteFrame;
// The raster scale from our last paint.
mozilla::gfx::MatrixScales mRasterScale;
// The visible rect from our last paint.
Maybe<nsRect> mVisibleRect;
bool mIsInline : 1;
bool mPostedReflowCallback : 1;
bool mDidCreateDoc : 1;

View File

@@ -763,40 +763,11 @@ void nsDisplayListBuilder::BeginFrame() {
mSyncDecodeImages = false;
}
void nsDisplayListBuilder::AddEffectUpdate(dom::RemoteBrowser* aBrowser,
const dom::EffectsInfo& aUpdate) {
dom::EffectsInfo update = aUpdate;
// For printing we create one display item for each page that an iframe
// appears on, the proper visible rect is the union of all the visible rects
// we get from each display item.
nsPresContext* pc =
mReferenceFrame ? mReferenceFrame->PresContext() : nullptr;
if (pc && pc->Type() != nsPresContext::eContext_Galley) {
Maybe<dom::EffectsInfo> existing = mEffectsUpdates.MaybeGet(aBrowser);
if (existing) {
// Only the visible rect should differ, the scales should match.
MOZ_ASSERT(existing->mRasterScale == aUpdate.mRasterScale &&
existing->mTransformToAncestorScale ==
aUpdate.mTransformToAncestorScale);
if (existing->mVisibleRect) {
if (update.mVisibleRect) {
update.mVisibleRect =
Some(update.mVisibleRect->Union(*existing->mVisibleRect));
} else {
update.mVisibleRect = existing->mVisibleRect;
}
}
}
}
mEffectsUpdates.InsertOrUpdate(aBrowser, update);
}
void nsDisplayListBuilder::EndFrame() {
NS_ASSERTION(!mInInvalidSubtree,
"Someone forgot to cleanup mInInvalidSubtree!");
mCurrentContainerASR = nullptr;
mActiveScrolledRoots.Clear();
mEffectsUpdates.Clear();
FreeClipChains();
FreeTemporaryItems();
nsCSSRendering::EndFrameTreesLocked();
@@ -1795,7 +1766,6 @@ void nsDisplayListBuilder::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const {
MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
n += mDocumentWillChangeBudgets.ShallowSizeOfExcludingThis(mallocSizeOf);
n += mFrameWillChangeBudgets.ShallowSizeOfExcludingThis(mallocSizeOf);
n += mEffectsUpdates.ShallowSizeOfExcludingThis(mallocSizeOf);
n += mRetainedWindowDraggingRegion.SizeOfExcludingThis(mallocSizeOf);
n += mRetainedWindowNoDraggingRegion.SizeOfExcludingThis(mallocSizeOf);
n += mRetainedWindowOpaqueRegion.SizeOfExcludingThis(mallocSizeOf);

View File

@@ -37,7 +37,6 @@
#include "mozilla/TemplateLib.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/EffectsInfo.h"
#include "mozilla/gfx/UserData.h"
#include "mozilla/layers/BSPTree.h"
#include "mozilla/layers/ScrollableLayerGuid.h"
@@ -880,14 +879,6 @@ class nsDisplayListBuilder {
void RemoveModifiedWindowRegions();
void ClearRetainedWindowRegions();
const nsTHashMap<nsPtrHashKey<dom::RemoteBrowser>, dom::EffectsInfo>&
GetEffectUpdates() const {
return mEffectsUpdates;
}
void AddEffectUpdate(dom::RemoteBrowser* aBrowser,
const dom::EffectsInfo& aUpdate);
/**
* Invalidates the caret frames from previous paints, if they have changed.
*/
@@ -1794,9 +1785,6 @@ class nsDisplayListBuilder {
nsTHashMap<nsPtrHashKey<const nsIFrame>, FrameWillChangeBudget>
mFrameWillChangeBudgets;
nsTHashMap<nsPtrHashKey<dom::RemoteBrowser>, dom::EffectsInfo>
mEffectsUpdates;
nsTHashSet<nsCString> mDestinations; // Destination names emitted.
// Stores reusable items collected during display list preprocessing.