Bug 1807251 - content-visibility should not block IntersectionObserver which control content relevancy r=emilio

IntersectionObserver is used to decide whether content is relevant for
the purposes of `content-visibility: auto`. Content hidden by this
property normally blocks IntersectionObserver, but it should not block
the observer which controls content relevancy.

Differential Revision: https://phabricator.services.mozilla.com/D167193
This commit is contained in:
Martin Robinson 2023-01-19 17:14:46 +00:00
Родитель b2525b4d3c
Коммит 897c6495ad
5 изменённых файлов: 67 добавлений и 4 удалений

Просмотреть файл

@ -634,7 +634,8 @@ IntersectionInput DOMIntersectionObserver::ComputeInput(
// https://w3c.github.io/IntersectionObserver/#update-intersection-observations-algo
// (steps 2.1 - 2.5)
IntersectionOutput DOMIntersectionObserver::Intersect(
const IntersectionInput& aInput, Element& aTarget) {
const IntersectionInput& aInput, Element& aTarget,
IgnoreContentVisibility aIgnoreContentVisibility) {
const bool isSimilarOrigin = SimilarOrigin(aTarget, aInput.mRootNode) ==
BrowsingContextOrigin::Similar;
nsIFrame* targetFrame = aTarget.GetPrimaryFrame();
@ -647,7 +648,12 @@ IntersectionOutput DOMIntersectionObserver::Intersect(
// true even if both the root and the target elements are in the skipped
// contents."
// https://drafts.csswg.org/css-contain/#cv-notes
if (targetFrame->IsHiddenByContentVisibilityOnAnyAncestor()) {
//
// Skip the intersection if the element is hidden, unless this is the
// DOMIntersectionObserver used specifically to track the visibility of
// `content-visibility: auto` elements.
if (aIgnoreContentVisibility == IgnoreContentVisibility::No &&
targetFrame->IsHiddenByContentVisibilityOnAnyAncestor()) {
return {isSimilarOrigin};
}
@ -707,11 +713,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`.
IgnoreContentVisibility ignoreContentVisibility =
aDocument->GetContentVisibilityObserver() == this
? IgnoreContentVisibility::Yes
: IgnoreContentVisibility::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, ignoreContentVisibility);
// 2.5. Let targetArea be targetRects area.
int64_t targetArea = (int64_t)output.mTargetRect.Width() *

Просмотреть файл

@ -95,6 +95,9 @@ struct IntersectionInput {
nsMargin mRootMargin;
// If this is in an OOP iframe, the visible rect of the OOP frame.
Maybe<nsRect> mRemoteDocumentVisibleRect;
// Whether this intersection is for the purposes of computing content
// relevancy for `content-visiblilty: auto`.
bool mIsForContentVisibility = false;
};
struct IntersectionOutput {
@ -151,7 +154,11 @@ class DOMIntersectionObserver final : public nsISupports,
static IntersectionInput ComputeInput(
const Document& aDocument, const nsINode* aRoot,
const StyleRect<LengthPercentage>* aRootMargin);
static IntersectionOutput Intersect(const IntersectionInput&, Element&);
enum class IgnoreContentVisibility : bool { No, Yes };
static IntersectionOutput Intersect(
const IntersectionInput&, Element&,
IgnoreContentVisibility = IgnoreContentVisibility::No);
// Intersects with a given rect, already relative to the root frame.
static IntersectionOutput Intersect(const IntersectionInput&, const nsRect&);

Просмотреть файл

@ -3789,6 +3789,9 @@ class Document : public nsINode,
}
DOMIntersectionObserver& EnsureLazyLoadImageObserver();
DOMIntersectionObserver* GetContentVisibilityObserver() const {
return mContentVisibilityObserver;
}
DOMIntersectionObserver& EnsureContentVisibilityObserver();
void ObserveForContentVisibility(Element&);
void UnobserveForContentVisibility(Element&);

Просмотреть файл

@ -0,0 +1,10 @@
<!doctype HTML>
<html>
<meta charset="utf8">
<title>Content Visibility: content in nested `content-visibility: auto` elements is considered relevant</title>
<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
<div style="border:solid">
<div>content with content-visibility: auto</div>
</div>

Просмотреть файл

@ -0,0 +1,28 @@
<!doctype HTML>
<html class="reftest-wait">
<meta charset="utf8">
<title>Content Visibility: content in nested `content-visibility: auto` elements is considered relevant</title>
<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
<link rel="match" href="content-visibility-auto-nested-ref.html">
<meta name="assert" content="content in nested `content-visibility: auto` elements is considered relevant">
<script src="/common/reftest-wait.js"></script>
<script src="../resources/utils.js"></script>
<style>
div {
content-visibility: auto;
}
</style>
<script>
function runTest() {
requestAnimationFrame(takeScreenshot);
}
window.onload = () => { requestAnimationFrame(runTest); };
</script>
<div style="border:solid">
<div>content with content-visibility: auto</div>
</div>