Backed out changeset 20a5c1f3b35e (bug 1807253) for causing failures on content-visibility-continuations-crash.html. CLOSED TREE

This commit is contained in:
Natalia Csoregi 2023-11-22 16:12:27 +02:00
parent 5deef76f14
commit 17befdb121
13 changed files with 139 additions and 289 deletions

View file

@ -160,6 +160,20 @@ static void LazyLoadCallback(
}
}
static void ContentVisibilityCallback(
const Sequence<OwningNonNull<DOMIntersectionObserverEntry>>& aEntries) {
for (const auto& entry : aEntries) {
entry->Target()->SetVisibleForContentVisibility(entry->IsIntersecting());
if (RefPtr<Document> doc = entry->Target()->GetComposedDoc()) {
if (RefPtr<PresShell> presShell = doc->GetPresShell()) {
presShell->ScheduleContentRelevancyUpdate(
ContentRelevancyReason::Visible);
}
}
}
}
static LengthPercentage PrefMargin(float aValue, bool aIsPercentage) {
return aIsPercentage ? LengthPercentage::FromPercentage(aValue / 100.0f)
: LengthPercentage::FromPixels(aValue);
@ -191,6 +205,25 @@ DOMIntersectionObserver::CreateLazyLoadObserver(Document& aDocument) {
return observer.forget();
}
already_AddRefed<DOMIntersectionObserver>
DOMIntersectionObserver::CreateContentVisibilityObserver(Document& aDocument) {
RefPtr<DOMIntersectionObserver> observer =
new DOMIntersectionObserver(aDocument, ContentVisibilityCallback);
observer->mThresholds.AppendElement(0.0f);
auto margin = LengthPercentage::FromPercentage(
StaticPrefs::layout_css_content_visibility_relevant_content_margin() /
100.0f);
observer->mRootMargin.Get(eSideTop) = margin;
observer->mRootMargin.Get(eSideRight) = margin;
observer->mRootMargin.Get(eSideBottom) = margin;
observer->mRootMargin.Get(eSideLeft) = margin;
return observer.forget();
}
bool DOMIntersectionObserver::SetRootMargin(const nsACString& aString) {
return Servo_IntersectionObserverRootMargin_Parse(&aString, &mRootMargin);
}
@ -315,8 +348,8 @@ static const Document* GetTopLevelContentDocumentInThisProcess(
static Maybe<nsRect> ComputeTheIntersection(
nsIFrame* aTarget, nsIFrame* aRoot, const nsRect& aRootBounds,
const Maybe<nsRect>& aRemoteDocumentVisibleRect,
DOMIntersectionObserver::IsForProximityToViewport
aIsForProximityToViewport) {
DOMIntersectionObserver::IsContentVisibilityObserver
aIsContentVisibilityObserver) {
nsIFrame* target = aTarget;
// 1. Let intersectionRect be the result of running the
// getBoundingClientRect() algorithm on the target.
@ -326,8 +359,8 @@ static Maybe<nsRect> ComputeTheIntersection(
target, target, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
// 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) {
if (aIsContentVisibilityObserver ==
DOMIntersectionObserver::IsContentVisibilityObserver::Yes) {
const auto& disp = *target->StyleDisplay();
auto clipAxes = target->ShouldApplyOverflowClipping(&disp);
if (clipAxes != PhysicalAxes::None) {
@ -615,7 +648,7 @@ IntersectionInput DOMIntersectionObserver::ComputeInput(
// (steps 2.1 - 2.5)
IntersectionOutput DOMIntersectionObserver::Intersect(
const IntersectionInput& aInput, const Element& aTarget,
IsForProximityToViewport aIsForProximityToViewport) {
IsContentVisibilityObserver aIsContentVisibilityObserver) {
const bool isSimilarOrigin = SimilarOrigin(aTarget, aInput.mRootNode) ==
BrowsingContextOrigin::Similar;
nsIFrame* targetFrame = aTarget.GetPrimaryFrame();
@ -630,9 +663,9 @@ IntersectionOutput DOMIntersectionObserver::Intersect(
// https://drafts.csswg.org/css-contain/#cv-notes
//
// Skip the intersection if the element is hidden, unless this is the
// specifically to determine the proximity to the viewport for
// DOMIntersectionObserver used specifically to track the visibility of
// `content-visibility: auto` elements.
if (aIsForProximityToViewport == IsForProximityToViewport::No &&
if (aIsContentVisibilityObserver == IsContentVisibilityObserver::No &&
targetFrame->IsHiddenByContentVisibilityOnAnyAncestor()) {
return {isSimilarOrigin};
}
@ -666,7 +699,7 @@ IntersectionOutput DOMIntersectionObserver::Intersect(
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) {
if (aIsContentVisibilityObserver == IsContentVisibilityObserver::Yes) {
const auto& disp = *targetFrame->StyleDisplay();
auto clipAxes = targetFrame->ShouldApplyOverflowClipping(&disp);
if (clipAxes != PhysicalAxes::None) {
@ -680,7 +713,7 @@ IntersectionOutput DOMIntersectionObserver::Intersect(
// intersection algorithm on target and observers intersection root.
Maybe<nsRect> intersectionRect = ComputeTheIntersection(
targetFrame, aInput.mRootFrame, rootBounds,
aInput.mRemoteDocumentVisibleRect, aIsForProximityToViewport);
aInput.mRemoteDocumentVisibleRect, aIsContentVisibilityObserver);
return {isSimilarOrigin, rootBounds, targetRect, intersectionRect};
}
@ -704,11 +737,20 @@ void DOMIntersectionObserver::Update(Document& aDocument,
DOMHighResTimeStamp time) {
auto input = ComputeInput(aDocument, mRoot, &mRootMargin);
// If this observer is used to determine content relevancy for
// `content-visiblity: auto` content, then do not skip intersection
// for content that is hidden by `content-visibility: auto`.
IsContentVisibilityObserver isContentVisibilityObserver =
aDocument.GetContentVisibilityObserver() == this
? IsContentVisibilityObserver::Yes
: IsContentVisibilityObserver::No;
// 2. For each target in observers internal [[ObservationTargets]] slot,
// processed in the same order that observe() was called on each target:
for (Element* target : mObservationTargets) {
// 2.1 - 2.4.
IntersectionOutput output = Intersect(input, *target);
IntersectionOutput output =
Intersect(input, *target, isContentVisibilityObserver);
// 2.5. Let targetArea be targetRects area.
int64_t targetArea = (int64_t)output.mTargetRect.Width() *
@ -761,8 +803,16 @@ void DOMIntersectionObserver::Update(Document& aDocument,
}
}
// If descendantScrolledIntoView, it means the target is with c-v: auto, and
// the content relevancy value has been set to visible before
// scrollIntoView. Here, we need to generate entries for them, so that the
// content relevancy value could be checked in the callback.
const bool temporarilyVisibleForScrolledIntoView =
isContentVisibilityObserver == IsContentVisibilityObserver::Yes &&
target->TemporarilyVisibleForScrolledIntoViewDescendant();
// Steps 2.10 - 2.15.
if (target->UpdateIntersectionObservation(this, thresholdIndex)) {
if (target->UpdateIntersectionObservation(this, thresholdIndex) ||
temporarilyVisibleForScrolledIntoView) {
// See https://github.com/w3c/IntersectionObserver/issues/432 about
// why we use thresholdIndex > 0 rather than isIntersecting for the
// entry's isIntersecting value.
@ -771,6 +821,10 @@ void DOMIntersectionObserver::Update(Document& aDocument,
output.mIsSimilarOrigin ? Some(output.mRootBounds) : Nothing(),
output.mTargetRect, output.mIntersectionRect, thresholdIndex > 0,
intersectionRatio);
if (temporarilyVisibleForScrolledIntoView) {
target->SetTemporarilyVisibleForScrolledIntoViewDescendant(false);
}
}
}
}

View file

@ -152,10 +152,10 @@ class DOMIntersectionObserver final : public nsISupports,
const Document& aDocument, const nsINode* aRoot,
const StyleRect<LengthPercentage>* aRootMargin);
enum class IsForProximityToViewport : bool { No, Yes };
enum class IsContentVisibilityObserver : bool { No, Yes };
static IntersectionOutput Intersect(
const IntersectionInput&, const Element&,
IsForProximityToViewport = IsForProximityToViewport::No);
IsContentVisibilityObserver = IsContentVisibilityObserver::No);
// Intersects with a given rect, already relative to the root frame.
static IntersectionOutput Intersect(const IntersectionInput&, const nsRect&);
@ -165,6 +165,9 @@ class DOMIntersectionObserver final : public nsISupports,
static already_AddRefed<DOMIntersectionObserver> CreateLazyLoadObserver(
Document&);
static already_AddRefed<DOMIntersectionObserver>
CreateContentVisibilityObserver(Document&);
static Maybe<nsRect> EdgeInclusiveIntersection(const nsRect& aRect,
const nsRect& aOtherRect);

View file

@ -2520,6 +2520,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLazyLoadObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLastRememberedSizeObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentVisibilityObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOrientationPendingPromise)
@ -2636,6 +2637,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSecurityInfo)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLazyLoadObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContentVisibilityObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLastRememberedSizeObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle)
@ -16449,6 +16451,24 @@ DOMIntersectionObserver& Document::EnsureLazyLoadObserver() {
return *mLazyLoadObserver;
}
DOMIntersectionObserver& Document::EnsureContentVisibilityObserver() {
if (!mContentVisibilityObserver) {
mContentVisibilityObserver =
DOMIntersectionObserver::CreateContentVisibilityObserver(*this);
}
return *mContentVisibilityObserver;
}
void Document::ObserveForContentVisibility(Element& aElement) {
EnsureContentVisibilityObserver().Observe(aElement);
}
void Document::UnobserveForContentVisibility(Element& aElement) {
if (mContentVisibilityObserver) {
mContentVisibilityObserver->Unobserve(aElement);
}
}
ResizeObserver& Document::EnsureLastRememberedSizeObserver() {
if (!mLastRememberedSizeObserver) {
mLastRememberedSizeObserver =
@ -17161,42 +17181,18 @@ static void FlushLayoutForWholeBrowsingContextTree(Document& aDoc) {
}
}
bool Document::HasContentVisibilityAutoElements() const {
if (PresShell* presShell = GetPresShell()) {
return presShell->HasContentVisibilityAutoFrames();
void Document::NotifyResizeObservers() {
if (mResizeObservers.IsEmpty()) {
return;
}
return false;
}
void Document::DetermineProximityToViewportAndNotifyResizeObservers() {
uint32_t shallowestTargetDepth = 0;
bool initialResetOfScrolledIntoViewFlagsDone = false;
while (true) {
// Flush layout, so that any callback functions' style changes / resizes
// get a chance to take effect. The callback functions may do changes in its
// sub-documents or ancestors, so flushing layout for the whole browsing
// context tree makes sure we don't miss anyone.
FlushLayoutForWholeBrowsingContextTree(*this);
if (PresShell* presShell = GetPresShell()) {
auto result = presShell->DetermineProximityToViewport();
if (result.mHadInitialDetermination) {
continue;
}
if (result.mAnyScrollIntoViewFlag) {
// Not defined in the spec: It's possible that some elements with
// content-visibility: auto were forced to be visible in order to
// perform scrollIntoView() so clear their flags now and restart the
// loop.
// See https://github.com/w3c/csswg-drafts/issues/9337
presShell->ClearTemporarilyVisibleForScrolledIntoViewDescendantFlags();
presShell->ScheduleContentRelevancyUpdate(
ContentRelevancyReason::Visible);
if (!initialResetOfScrolledIntoViewFlagsDone) {
initialResetOfScrolledIntoViewFlagsDone = true;
continue;
}
}
}
// To avoid infinite resize loop, we only gather all active observations
// that have the depth of observed target element more than current
@ -17207,12 +17203,6 @@ void Document::DetermineProximityToViewportAndNotifyResizeObservers() {
break;
}
// nsIFrame::UpdateIsRelevantContent may call ObserveForLastRememberedSize()
// so update the relevancy after the observations are gathered, otherwise
// the last remembered size observation could be a skipped one.
if (PresShell* presShell = GetPresShell()) {
presShell->UpdateRelevancyOfContentVisibilityAutoFrames();
}
DebugOnly<uint32_t> oldShallowestTargetDepth = shallowestTargetDepth;
shallowestTargetDepth = BroadcastAllActiveResizeObservations();
NS_ASSERTION(oldShallowestTargetDepth < shallowestTargetDepth,

View file

@ -3708,6 +3708,13 @@ class Document : public nsINode,
DOMIntersectionObserver* GetLazyLoadObserver() { return mLazyLoadObserver; }
DOMIntersectionObserver& EnsureLazyLoadObserver();
DOMIntersectionObserver* GetContentVisibilityObserver() const {
return mContentVisibilityObserver;
}
DOMIntersectionObserver& EnsureContentVisibilityObserver();
void ObserveForContentVisibility(Element&);
void UnobserveForContentVisibility(Element&);
ResizeObserver* GetLastRememberedSizeObserver() {
return mLastRememberedSizeObserver;
}
@ -3754,16 +3761,7 @@ class Document : public nsINode,
* Returns whether there is any ResizeObserver that has skipped observations.
*/
bool HasAnySkippedResizeObservations() const;
/**
* Returns whether the document contains any content-visibility: auto element.
*/
bool HasContentVisibilityAutoElements() const;
/**
* Determine proximity to viewport for content-visibility: auto elements and
* notify resize observers.
*/
MOZ_CAN_RUN_SCRIPT void
DetermineProximityToViewportAndNotifyResizeObservers();
MOZ_CAN_RUN_SCRIPT void NotifyResizeObservers();
// Getter for PermissionDelegateHandler. Performs lazy initialization.
PermissionDelegateHandler* GetPermissionDelegateHandler();
@ -5121,6 +5119,10 @@ class Document : public nsINode,
RefPtr<DOMIntersectionObserver> mLazyLoadObserver;
// Used for detecting when `content-visibility: auto` elements are near
// or far from the viewport.
RefPtr<DOMIntersectionObserver> mContentVisibilityObserver;
// ResizeObserver for storing and removing the last remembered size.
// @see {@link https://drafts.csswg.org/css-sizing-4/#last-remembered}
RefPtr<ResizeObserver> mLastRememberedSizeObserver;

View file

@ -238,16 +238,12 @@ class FragmentOrElement : public nsIContent {
/**
* Whether the content of this element is relevant for the purposes
* of `content-visibility: auto.
* Reflects 'relevant to the user' concept, see
* https://drafts.csswg.org/css-contain/#relevant-to-the-user.
*/
Maybe<ContentRelevancy> mContentRelevancy;
/**
* Whether the content of this element is considered visible for
* the purposes of `content-visibility: auto.
* Reflects 'proximity to the viewport' concept, see
* https://drafts.csswg.org/css-contain/#proximity-to-the-viewport.
*/
Maybe<bool> mVisibleForContentVisibility;

View file

@ -68,7 +68,6 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/DOMIntersectionObserver.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/UserActivation.h"
@ -11961,62 +11960,6 @@ void PresShell::ScheduleContentRelevancyUpdate(ContentRelevancyReason aReason) {
}
}
PresShell::ProximityToViewportResult PresShell::DetermineProximityToViewport() {
ProximityToViewportResult result;
if (mContentVisibilityAutoFrames.IsEmpty()) {
return result;
}
auto margin = LengthPercentage::FromPercentage(
StaticPrefs::layout_css_content_visibility_relevant_content_margin() /
100.0f);
auto rootMargin = StyleRect<LengthPercentage>::WithAllSides(margin);
auto input = DOMIntersectionObserver::ComputeInput(
*mDocument, /* aRoot = */ nullptr, &rootMargin);
for (nsIFrame* frame : mContentVisibilityAutoFrames) {
auto* element = frame->GetContent()->AsElement();
result.mAnyScrollIntoViewFlag |=
element->TemporarilyVisibleForScrolledIntoViewDescendant();
// 14.2.3.1
Maybe<bool> oldVisibility = element->GetVisibleForContentVisibility();
bool checkForInitialDetermination =
oldVisibility.isNothing() &&
(element->GetContentRelevancy().isNothing() ||
element->GetContentRelevancy()->isEmpty());
// 14.2.3.2
bool intersects =
DOMIntersectionObserver::Intersect(
input, *element,
DOMIntersectionObserver::IsForProximityToViewport::Yes)
.Intersects();
element->SetVisibleForContentVisibility(intersects);
if (oldVisibility.isNothing() || *oldVisibility != intersects) {
ScheduleContentRelevancyUpdate(ContentRelevancyReason::Visible);
}
// 14.2.3.3
if (checkForInitialDetermination && intersects) {
result.mHadInitialDetermination = true;
}
}
return result;
}
void PresShell::ClearTemporarilyVisibleForScrolledIntoViewDescendantFlags()
const {
for (nsIFrame* frame : mContentVisibilityAutoFrames) {
frame->GetContent()
->AsElement()
->SetTemporarilyVisibleForScrolledIntoViewDescendant(false);
}
}
void PresShell::UpdateContentRelevancyImmediately(
ContentRelevancyReason aReason) {
if (MOZ_UNLIKELY(mIsDestroying)) {

View file

@ -1748,25 +1748,11 @@ class PresShell final : public nsStubDocumentObserver,
void RegisterContentVisibilityAutoFrame(nsIFrame* aFrame) {
mContentVisibilityAutoFrames.Insert(aFrame);
}
bool HasContentVisibilityAutoFrames() const {
return !mContentVisibilityAutoFrames.IsEmpty();
}
void UpdateRelevancyOfContentVisibilityAutoFrames();
void ScheduleContentRelevancyUpdate(ContentRelevancyReason aReason);
void UpdateContentRelevancyImmediately(ContentRelevancyReason aReason);
// Determination of proximity to the viewport.
// Refer to "update the rendering: step 14", see
// https://html.spec.whatwg.org/#update-the-rendering
struct ProximityToViewportResult {
bool mHadInitialDetermination = false;
bool mAnyScrollIntoViewFlag = false;
};
ProximityToViewportResult DetermineProximityToViewport();
void ClearTemporarilyVisibleForScrolledIntoViewDescendantFlags() const;
private:
~PresShell();

View file

@ -2242,8 +2242,11 @@ void nsRefreshDriver::UpdateRelevancyOfContentVisibilityAutoFrames() {
mNeedToUpdateContentRelevancy = false;
}
void nsRefreshDriver::DetermineProximityToViewportAndNotifyResizeObservers() {
AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Update the rendering: step 14", LAYOUT);
void nsRefreshDriver::NotifyResizeObservers() {
AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Notify ResizeObserver", LAYOUT);
if (!mNeedToUpdateResizeObservers) {
return;
}
// NotifyResizeObservers might re-schedule us for next tick.
mNeedToUpdateResizeObservers = false;
@ -2252,19 +2255,17 @@ void nsRefreshDriver::DetermineProximityToViewportAndNotifyResizeObservers() {
}
AutoTArray<RefPtr<Document>, 32> documents;
if (mPresContext->Document()->HasResizeObservers() ||
mPresContext->Document()->HasContentVisibilityAutoElements()) {
if (mPresContext->Document()->HasResizeObservers()) {
documents.AppendElement(mPresContext->Document());
}
mPresContext->Document()->CollectDescendantDocuments(
documents, [](const Document* document) -> bool {
return document->HasResizeObservers() ||
document->HasContentVisibilityAutoElements();
return document->HasResizeObservers();
});
for (const RefPtr<Document>& doc : documents) {
MOZ_KnownLive(doc)->DetermineProximityToViewportAndNotifyResizeObservers();
MOZ_KnownLive(doc)->NotifyResizeObservers();
}
}
@ -2747,6 +2748,15 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime,
pm->UpdatePopupPositions(this);
}
// Notify resize observers if any, see
// https://html.spec.whatwg.org/#update-the-rendering step 14.
NotifyResizeObservers();
if (MOZ_UNLIKELY(!mPresContext || !mPresContext->GetPresShell())) {
// A resize observer callback apparently destroyed our PresContext.
StopTimer();
return;
}
// Update the relevancy of the content of any `content-visibility: auto`
// elements. The specification says: "Specifically, such changes will
// take effect between steps 13 and 14 of Update the Rendering step of
@ -2755,16 +2765,6 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime,
// https://drafts.csswg.org/css-contain/#cv-notes
UpdateRelevancyOfContentVisibilityAutoFrames();
// Step 14 (https://html.spec.whatwg.org/#update-the-rendering).
// 1) Initial proximity to the viewport determination for
// content-visibility:auto elements and 2) Resize observers notifications.
DetermineProximityToViewportAndNotifyResizeObservers();
if (MOZ_UNLIKELY(!mPresContext || !mPresContext->GetPresShell())) {
// A resize observer callback apparently destroyed our PresContext.
StopTimer();
return;
}
UpdateIntersectionObservations(aNowTime);
UpdateAnimatedImages(previousRefresh, aNowTime);

View file

@ -499,8 +499,7 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
void RunFrameRequestCallbacks(mozilla::TimeStamp aNowTime);
void UpdateIntersectionObservations(mozilla::TimeStamp aNowTime);
void UpdateRelevancyOfContentVisibilityAutoFrames();
MOZ_CAN_RUN_SCRIPT void
DetermineProximityToViewportAndNotifyResizeObservers();
MOZ_CAN_RUN_SCRIPT void NotifyResizeObservers();
void MaybeIncreaseMeasuredTicksSinceLoading();
void EvaluateMediaQueriesAndReportChanges();

View file

@ -766,6 +766,9 @@ void nsIFrame::InitPrimaryFrame() {
if (StyleDisplay()->ContentVisibility(*this) ==
StyleContentVisibility::Auto) {
PresShell()->RegisterContentVisibilityAutoFrame(this);
auto* element = Element::FromNodeOrNull(GetContent());
MOZ_ASSERT(element);
PresContext()->Document()->ObserveForContentVisibility(*element);
} else if (auto* element = Element::FromNodeOrNull(GetContent())) {
element->ClearContentRelevancy();
}
@ -837,6 +840,13 @@ void nsIFrame::Destroy(DestroyContext& aContext) {
}
}
if (StyleDisplay()->ContentVisibility(*this) ==
StyleContentVisibility::Auto) {
if (auto* element = Element::FromNodeOrNull(GetContent())) {
PresContext()->Document()->UnobserveForContentVisibility(*element);
}
}
// Disable visibility tracking. Note that we have to do this before we clear
// frame properties and lose track of whether we were previously visible.
// XXX(seth): It'd be ideal to assert that we're already marked nonvisible

View file

@ -0,0 +1,3 @@
[content-visibility-086.html]
[Content Visibility: innerText]
expected: [FAIL, PASS]

View file

@ -0,0 +1,3 @@
[content-visibility-auto-first-observation-immediate.html]
[Target is sized and laid out before resize observer]
expected: FAIL

View file

@ -1,139 +0,0 @@
<!doctype html>
<meta charset="utf-8">
<title>Content Visibility: stop ticking after relevancy updates</title>
<!--
Copied from testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-auto-relevancy-updates.html
-->
<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
<link rel="help" href="https://drafts.csswg.org/css-contain/#relevant-to-the-user">
<link rel="help" href="https://drafts.csswg.org/css-contain/#cv-notes">
<meta name="assert" content="Verify relevancy is properly updated for content-visibility: auto elements and refresh driver stops ticking after such update.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#spacer {
height: 300vh;
}
#contentVisibilityAuto {
content-visibility: auto;
border: solid;
}
</style>
<div>
<div id="log"></div>
<div tabindex="1" id="spacer"></div>
<div tabindex="2" id="contentVisibilityAuto">
<span>Hello, World!</span>
</div>
</div>
<script>
function hasPendingTick() {
return SpecialPowers.wrap(window).windowUtils.refreshDriverHasPendingTick;
}
// See comment in layout/base/tests/test_bug1756118.html about why the timeouts
// etc.
async function expectTicksToStop() {
for (let i = 0; i < 100; i++) {
await new Promise(r => setTimeout(r, 8));
if(!hasPendingTick()) {
break;
}
}
assert_false(hasPendingTick(), "refresh driver should have eventually stopped ticking");
}
function tick() {
return new Promise(r => {
requestAnimationFrame(() => requestAnimationFrame(r));
});
}
function contentVisibilityAutoElementIsRelevant() {
// A content-visibility: auto element that is not relevant skips its contents,
// which do not contribute to the result of innerText.
return contentVisibilityAuto.innerText.length > 0;
}
function clearRelevancyReasons() {
window.scrollTo(0, 0);
spacer.focus({preventScroll: true});
window.getSelection().empty();
}
promise_test(async function(t) {
// Wait for page load.
await new Promise(resolve => { window.addEventListener("load", resolve); });
// Register cleanup method to reset relevancy.
t.add_cleanup(clearRelevancyReasons);
// Element should initially not be relevant and ticking should have stopped.
await SpecialPowers.pushPrefEnv({'set':
[['layout.keep_ticking_after_load_ms', 0]]});
await tick();
await expectTicksToStop();
assert_false(contentVisibilityAutoElementIsRelevant(), "initial relevancy");
// Make element close to the viewport.
contentVisibilityAuto.firstElementChild.scrollIntoView();
await tick();
await expectTicksToStop();
assert_true(contentVisibilityAutoElementIsRelevant(), "close to viewport");
// Scroll away from the element again.
window.scrollTo(0, 0);
await tick();
await expectTicksToStop();
assert_false(contentVisibilityAutoElementIsRelevant(), "far from viewport");
}, "Relevancy updated after changing proximity to the viewport.");
promise_test(async function(t) {
// Register cleanup method to reset relevancy.
t.add_cleanup(clearRelevancyReasons);
// Element should initially not be relevant and no ticking be in progress.
await tick();
await expectTicksToStop();
assert_false(contentVisibilityAutoElementIsRelevant(), "initial relevancy");
// Focus the element.
contentVisibilityAuto.focus({preventScroll: true});
await tick();
await expectTicksToStop();
assert_true(contentVisibilityAutoElementIsRelevant(), "focused");
// Unfocus the element again.
spacer.focus({preventScroll: true});
await tick();
await expectTicksToStop();
assert_false(contentVisibilityAutoElementIsRelevant(), "unfocused");
}, "Relevancy updated after being focused/unfocused.");
promise_test(async function(t) {
// Register cleanup method to reset relevancy.
t.add_cleanup(clearRelevancyReasons);
// Element should initially not be relevant and no ticking be in progress.
await tick();
await expectTicksToStop();
assert_false(contentVisibilityAutoElementIsRelevant(), "initial relevancy");
// Select the contents of the element.
window.getSelection().selectAllChildren(contentVisibilityAuto);
await tick();
await expectTicksToStop();
assert_true(contentVisibilityAutoElementIsRelevant(), "selected");
// Unselect the contents of the element.
window.getSelection().empty();
await tick();
await expectTicksToStop();
assert_false(contentVisibilityAutoElementIsRelevant(), "unselected");
}, "Relevancy updated after being selected/unselected.");
</script>