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:
@@ -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 observer’s intersection root.
|
||||
Maybe<nsRect> intersectionRect = ComputeTheIntersection(
|
||||
targetFrame, aInput.mRootFrame, rootBounds,
|
||||
targetFrame, targetRectRelativeToTarget, aInput.mRootFrame, rootBounds,
|
||||
aInput.mRemoteDocumentVisibleRect, aIsForProximityToViewport);
|
||||
|
||||
return {isSimilarOrigin, rootBounds, targetRect, intersectionRect};
|
||||
|
||||
@@ -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&);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -1158,6 +1158,10 @@ void nsFrameLoader::Hide() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRemoteBrowser) {
|
||||
mRemoteBrowser->UpdateEffects(EffectsInfo::FullyHidden());
|
||||
}
|
||||
|
||||
if (!GetDocShell()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user