diff --git a/index.bs b/index.bs index 8ab73a9..67c6865 100644 --- a/index.bs +++ b/index.bs @@ -64,12 +64,21 @@ urlPrefix: https://drafts.csswg.org/css-display/ url: #containing-block-chain; type: dfn; text: containing block chain urlPrefix: http://www.w3.org/TR/css-masking-1/ url: #propdef-clip-path; type:dfn; text: clip-path +urlPrefix: https://drafts.csswg.org/css-overflow-3/ + url: #ink-overflow-rectangle; type:dfn; text: ink overflow rectangle + url: #ink-overflow-region; type:dfn; text: ink overflow region + url: #overflow-properties; type:dfn; text: overflow properties +urlPrefix: https://drafts.csswg.org/css-transforms-1/ + url: #transformation-matrix; type:dfn; text: transformation matrix + url: #serialization-of-the-computed-value; type:dfn; text: serialization + url: #identity-transform-function; type:dfn; text: identity transform function + url: #post-multiplied; type:dfn; text: post-multiplied urlPrefix: https://drafts.csswg.org/cssom-view-1/ url: #pinch-zoom; type:dfn; text: pinch zoom urlPrefix: https://drafts.csswg.org/css2/visuren.html url: #viewport; type:dfn; text: viewport -urlPrefix: https://drafts.csswg.org/css-overflow-3/ - url: #overflow-properties; type:dfn; text: overflow properties +urlPrefix: https://drafts.fxtf.org/filter-effects/ + url: #funcdef-filter-blur; type:dfn; text: blur -This callback will be invoked when there are changes to target's +This callback will be invoked when there are changes to a target's intersection with the intersection root, as per the processing model. @@ -192,7 +201,7 @@ and it can observe any target {{Element}} that {{IntersectionObserver/root}} in the containing block chain. An {{IntersectionObserver}} with a null {{IntersectionObserver/root}} is referred to as an implicit root observer. -Valid targets for an implicit root observer include +Valid targets for an implicit root observer include any {{Element}} in the top-level browsing context, as well as any {{Element}} in any nested browsing context which is in the list of the descendant browsing contexts of the top-level browsing context. @@ -225,6 +234,8 @@ interface IntersectionObserver { readonly attribute DOMString rootMargin; readonly attribute DOMString scrollMargin; readonly attribute FrozenArray<double> thresholds; + readonly attribute long delay; + readonly attribute boolean trackVisibility; undefined observe(Element target); undefined unobserve(Element target); undefined disconnect(); @@ -247,7 +258,7 @@ interface IntersectionObserver { Note: {{MutationObserver}} does not implement {{unobserve()}}. For {{IntersectionObserver}}, {{unobserve()}} addresses the - lazy-loading use case. After |target| becomes visible, + lazy-loading use case. After loading is initiated for |target|, it does not need to be tracked. It would be more work to either {{disconnect()}} all |target|s and {{observe()}} the remaining ones, @@ -306,6 +317,14 @@ interface IntersectionObserver { If no |options|.{{IntersectionObserverInit/threshold}} was provided to the {{IntersectionObserver}} constructor, or the sequence is empty, the value of this attribute will be [0]. + : delay + :: + A number indicating the minimum delay in milliseconds + between notifications from this observer for a given target. + : trackVisibility + :: + A boolean indicating whether this {{IntersectionObserver}} will track + changes in a target's visibility. An {{Element}} is defined as having a content clip if its computed style has overflow properties that cause its content to be clipped to the element's padding edge. @@ -401,6 +420,7 @@ interface IntersectionObserverEntry { readonly attribute DOMRectReadOnly boundingClientRect; readonly attribute DOMRectReadOnly intersectionRect; readonly attribute boolean isIntersecting; + readonly attribute boolean isVisible; readonly attribute double intersectionRatio; readonly attribute Element target; }; @@ -411,6 +431,7 @@ dictionary IntersectionObserverEntryInit { required DOMRectInit boundingClientRect; required DOMRectInit intersectionRect; required boolean isIntersecting; + required boolean isVisible; required double intersectionRatio; required Element target; }; @@ -428,8 +449,8 @@ dictionary IntersectionObserverEntryInit { rects (up to but not including {{IntersectionObserver/root}}), intersected with the root intersection rectangle. This value represents the portion of - {{IntersectionObserverEntry/target}} actually visible - within the root intersection rectangle. + {{IntersectionObserverEntry/target}} that intersects with + the root intersection rectangle. : isIntersecting :: True if the {{IntersectionObserverEntry/target}} intersects with the @@ -440,6 +461,10 @@ dictionary IntersectionObserverEntryInit { to intersecting with a zero-area intersection rect (as will happen with edge-adjacent intersections, or when the {{IntersectionObserverEntry/boundingClientRect}} has zero area). + : isVisible + :: + Contains the result of running the visibility algorithm + on {{IntersectionObserverEntry/target}}. : intersectionRatio :: If the {{IntersectionObserverEntry/boundingClientRect}} has non-zero area, @@ -474,6 +499,8 @@ dictionary IntersectionObserverInit { DOMString rootMargin = "0px"; DOMString scrollMargin = "0px"; (double or sequence<double>) threshold = 0; + long delay = 0; + boolean trackVisibility = false; }; @@ -513,6 +540,16 @@ dictionary IntersectionObserverInit { by getting the bounding box for target. Note: 0.0 is effectively "any non-zero number of pixels". + : delay + :: + A number specifying the minimum delay in milliseconds + between notifications from the observer for a given target. + : trackVisibility + :: + A boolean indicating whether the observer should track visibility. + Note that tracking visibility is likely to be a more expensive operation + than tracking intersections. It is recommended that this option be used + only when necessary.

@@ -538,23 +575,38 @@ Element

\[[RegisteredIntersectionObservers]] slot, which is initialized to an empty list. This list holds IntersectionObserverRegistration records, -which have an observer property -holding an {{IntersectionObserver}}, a previousThresholdIndex property -holding a number between -1 and the length of the observer's {{IntersectionObserver/thresholds}} property (inclusive), and -a previousIsIntersecting property holding a boolean. +which have: + * an observer property + holding an {{IntersectionObserver}}. + * a previousThresholdIndex property + holding a number between -1 and the length of the observer's {{IntersectionObserver/thresholds}} property (inclusive). + * a previousIsIntersecting property + holding a boolean. + * a lastUpdateTime property + holding a {{DOMHighResTimeStamp}} value. + * a previousIsVisible property + holding a boolean.

IntersectionObserver

-{{IntersectionObserver}} objects have internal -\[[QueuedEntries]] and -\[[ObservationTargets]] slots, -which are initialized to empty lists and an internal -\[[callback]] slot -which is initialized by {{IntersectionObserver(callback, options)}}. -They also have internal \[[rootMargin]] -and \[[scrollMargin]] slots -which are lists of four pixel lengths or percentages. +{{IntersectionObserver}} objects have the following internal slots: + * A \[[QueuedEntries]] slot + initialized to an empty list. + * A \[[ObservationTargets]] slot + initialized to an empty list. + * A \[[callback]] slot + which is initialized by {{IntersectionObserver(callback, options)}}. + * A \[[rootMargin]] slot + which is a list of four pixel lengths or percentages. + * A \[[scrollMargin]] slot + which is a list of four pixel lengths or percentages. + * A \[[thresholds]] slot + which is initialized by {{IntersectionObserver(callback, options)}}. + * A \[[delay]] slot + which is initialized by {{IntersectionObserver(callback, options)}}. + * A \[[trackVisibility]] slot + which is initialized by {{IntersectionObserver(callback, options)}}.

Algorithms

@@ -584,7 +636,12 @@ and an {{IntersectionObserverInit}} dictionary |options|, run these steps: 8. If |thresholds| is empty, append 0 to |thresholds|. 9. The {{IntersectionObserver/thresholds}} attribute getter will return this sorted |thresholds| list. -10. Return |this|. +10. Let |delay| be the value of |options|.{{IntersectionObserverInit/delay}}. +11. If |options|.{{IntersectionObserverInit/trackVisibility}} is true + and |delay| is less than 100, set |delay| to 100. +11. Set |this|'s internal {{[[delay]]}} slot to |options|.{{IntersectionObserverInit/delay}} to |delay|. +12. Set |this|'s internal {{[[trackVisibility]]}} slot to |options|.{{IntersectionObserverInit/trackVisibility}}. +13. Return |this|.

Observe a target Element

@@ -597,7 +654,8 @@ and an {{Element}} |target|, follow these steps: an {{IntersectionObserverRegistration}} record with an {{IntersectionObserverRegistration/observer}} property set to |observer|, a {{IntersectionObserverRegistration/previousThresholdIndex}} property set to -1, - and a {{IntersectionObserverRegistration/previousIsIntersecting}} property set to false. + a {{IntersectionObserverRegistration/previousIsIntersecting}} property set to false, + and a {{IntersectionObserverRegistration/previousIsVisible}} property set to false. 3. Append |intersectionObserverRegistration| to |target|'s internal {{[[RegisteredIntersectionObservers]]}} slot. 4. Add |target| to |observer|'s internal {{[[ObservationTargets]]}} slot. @@ -691,6 +749,32 @@ run these steps: 6. Map |intersectionRect| to the coordinate space of the viewport of the {{document}} containing |target|. 7. Return |intersectionRect|. +

+Compute whether a Target is unoccluded, untransformed, unfiltered, and opaque.

+ +To compute the visibility of a target, run these steps: +1. If the |observer|'s {{IntersectionObserver/trackVisibility}} attribute is false, return false. +2. If the target has an effective transformation matrix other than a 2D translation or proportional 2D upscaling, return false. +3. If the target, or any element in its containing block chain, has an effective opacity other than 100%, return false. +4. If the target, or any element in its containing block chain, has any filters applied, return false. +5. If the implementation cannot guarantee that the target is completely unoccluded by other page content, return false. + +Note: Implementations should use the ink overflow rectangle of page content when determining whether a target is occluded. For blur effects, which have theoretically infinite extent, the ink overflow rectangle is defined by the finite-area approximation described for the blur filter function. + +6. Return true. + +

Calculate a target's Effective Transformation Matrix

+To compute the effective transformation matrix of a target, run these steps: + 1. Let |matrix| be the serialization of the identity transform function. + 2. Let |container| be the target. + 3. While |container| is not the intersection root: + 1. Set |t| to |container|'s transformation matrix. + 2. Set |matrix| to |t| post-multiplied by |matrix|. + 3. If |container| is the root element of a nested browsing context, + update |container| to be the browsing context container of |container|. Otherwise, update |container| to be the containing block of |container|. + 4. Return |matrix|. + +

Run the Update Intersection Observations Steps

@@ -703,45 +787,54 @@ To run the update intersection observations steps for a 2. For each |observer| in |observer list|: 1. Let |rootBounds| be |observer|'s root intersection rectangle. 2. For each |target| in |observer|'s internal {{[[ObservationTargets]]}} slot, processed in the same order that {{observe()}} was called on each |target|: - 1. Let: + 1. Let |registration| be the {{IntersectionObserverRegistration}} record + in |target|'s internal {{[[RegisteredIntersectionObservers]]}} slot + whose {{IntersectionObserverRegistration/observer}} property is equal to |observer|. + 2. If (|time| - |registration|.{{IntersectionObserverRegistration/lastUpdateTime}} < |observer|.{{IntersectionObserver/delay}}), skip further processing for |target|. + 3. Set |registration|.{{IntersectionObserverRegistration/lastUpdateTime}} to |time|. + 4. Let: - |thresholdIndex| be 0. - |isIntersecting| be false. - |targetRect| be a {{DOMRectReadOnly}} with |x|, |y|, |width|, and |height| set to 0. - |intersectionRect| be a {{DOMRectReadOnly}} with |x|, |y|, |width|, and |height| set to 0. - 2. If the intersection root is not the implicit root, + 5. If the intersection root is not the implicit root, and |target| is not in the same {{document}} as the intersection root, skip to step 11. - 3. If the intersection root is an {{Element}}, + 6. If the intersection root is an {{Element}}, and |target| is not a descendant of the intersection root in the containing block chain, skip to step 11. - 4. Set |targetRect| to the {{DOMRectReadOnly}} obtained by getting the bounding box for + 7. Set |targetRect| to the {{DOMRectReadOnly}} obtained by getting the bounding box for |target|. - 4. Let |intersectionRect| be the result of running the compute the intersection + 8. Let |intersectionRect| be the result of running the compute the intersection algorithm on |target| and |observer|'s intersection root. - 5. Let |targetArea| be |targetRect|'s area. - 6. Let |intersectionArea| be |intersectionRect|'s area. - 7. Let |isIntersecting| be true if |targetRect| and |rootBounds| intersect or are edge-adjacent, + 9. Let |targetArea| be |targetRect|'s area. + 10. Let |intersectionArea| be |intersectionRect|'s area. + 11. Let |isIntersecting| be true if |targetRect| and |rootBounds| intersect or are edge-adjacent, even if the intersection has zero area (because |rootBounds| or |targetRect| have zero area). - 9. If |targetArea| is non-zero, let |intersectionRatio| be |intersectionArea| divided by |targetArea|.
+ 12. If |targetArea| is non-zero, let |intersectionRatio| be |intersectionArea| divided by |targetArea|.
Otherwise, let |intersectionRatio| be 1 if |isIntersecting| is true, or 0 if |isIntersecting| is false. - 10. Set |thresholdIndex| to the index of the first entry in |observer|.{{thresholds}} whose value is greater than |intersectionRatio|, or the length of |observer|.{{thresholds}} if |intersectionRatio| is greater than or equal to the last entry in |observer|.{{thresholds}}. - 11. Let |intersectionObserverRegistration| be the {{IntersectionObserverRegistration}} record - in |target|'s internal {{[[RegisteredIntersectionObservers]]}} slot - whose {{IntersectionObserverRegistration/observer}} property is equal to |observer|. - 12. Let |previousThresholdIndex| be the |intersectionObserverRegistration|'s + 13. Set |thresholdIndex| to the index of the first entry in |observer|.{{thresholds}} whose value is greater than |intersectionRatio|, or the length of |observer|.{{thresholds}} if |intersectionRatio| is greater than or equal to the last entry in |observer|.{{thresholds}}. + 14. Let |isVisible| be the result of running the visibility algorithm on |target|. + 15. Let |previousThresholdIndex| be the |registration|'s {{IntersectionObserverRegistration/previousThresholdIndex}} property. - 13. Let |previousIsIntersecting| be the |intersectionObserverRegistration|'s + 16. Let |previousIsIntersecting| be the |registration|'s {{IntersectionObserverRegistration/previousIsIntersecting}} property. - 14. If |thresholdIndex| does not equal |previousThresholdIndex| or if - |isIntersecting| does not equal |previousIsIntersecting|, + 17. Let |previousIsVisible| be the |registration|'s + {{IntersectionObserverRegistration/previousIsVisible}} property. + 18. If |thresholdIndex| does not equal |previousThresholdIndex|, + or if |isIntersecting| does not equal |previousIsIntersecting|, + or if |isVisible| does not equal |previousIsVisible|, queue an IntersectionObserverEntry, passing in |observer|, |time|, |rootBounds|, - |targetRect|, |intersectionRect|, |isIntersecting|, and |target|. - 15. Assign |thresholdIndex| to |intersectionObserverRegistration|'s + |targetRect|, |intersectionRect|, |isIntersecting|, + |isVisible|, and |target|. + 19. Assign |thresholdIndex| to |registration|'s {{IntersectionObserverRegistration/previousThresholdIndex}} property. - 16. Assign |isIntersecting| to |intersectionObserverRegistration|'s + 20. Assign |isIntersecting| to |registration|'s {{IntersectionObserverRegistration/previousIsIntersecting}} property. + 21. Assign |isVisible| to |registration|'s + {{IntersectionObserverRegistration/previousIsVisible}} property.

IntersectionObserver Lifetime