diff --git a/index.bs b/index.bs index 4e3b1ee..290fa38 100644 --- a/index.bs +++ b/index.bs @@ -108,31 +108,8 @@ Usage Example {#example} observer.observe({type: "longtask", buffered: true}); // Long script execution after this will result in queueing // and receiving "longtask" entries in the observer. - - // Register observer for previous and future long animation frame notifications. - // After this, long periods where the main thread is busy will result in queueing - // and receiving "long-animation-frame" entries in the observer. - observer.observe({type: "long-animation-frame", buffered: true}); -Long Animation Frames vs. Long Tasks {#loaf-vs-longtasks} ---------------------------------------------------------- - -While both long tasks and long animation frames measure congestion and jank, long animation frames -provide information that has a better correlation with how user preceive this type of congestion. -That's because long animation frames measure a sequence that begins when the main thread is idle, -and end when the frame either renders or the user agents decides there is nothing to render. - -The [=task=] term is somewhat of an implementation detail, and the long animation frame addition -attempts to remedy that by introducing a more user-centric metric of the same phenomenon of main -thread congestion/jank. - -Because long animation frames are guaranteed to have a maximum of one rendering phase, we can also -use them to expose additional information about the rendering phase itself, such as -{{PerformanceLongAnimationFrameTiming/renderStart}} and {{PerformanceLongAnimationFrameTiming/styleAndLayoutStart}}. - -For a detailed explanation about long animation frames, see the explainer. - Terminology {#sec-terminology} ============================== @@ -152,12 +129,6 @@ Note: This term is outdated, and the new terms should be reused when revamping t Attribution refers to identifying the type of work (such as script, layout etc.) that contributed significantly to the long task, as well as identifying which culprit browsing context container is responsible for that work. -Long animation frame refers to any of the following occurrences whose duration exceeds 50ms: - -* A [=task=], after which updating the rendering is not necessary. - -* A [=task=] after which updating the rendering is necessary, up until rendering is updated. - Long Task Timing {#sec-longtask-timing} ======================================= @@ -309,197 +280,10 @@ These fields are not independent. The following gives an overview of how they ar -Long Animation Frame Timing {#sec-loaf-timing} -======================================= - -Long Animation Frame timing involves the following new interfaces: - -{{PerformanceLongAnimationFrameTiming}} interface {#sec-PerformanceLongAnimationFrameTiming} ------------------------------------------------------------------------- - -
-    [Exposed=Window]
-    interface PerformanceLongAnimationFrameTiming : PerformanceEntry {
-        /* Overloading PerformanceEntry */
-        readonly attribute DOMHighResTimeStamp startTime;
-        readonly attribute DOMHighResTimeStamp duration;
-        readonly attribute DOMString name;
-        readonly attribute DOMString entryType;
-
-        readonly attribute DOMHighResTimeStamp renderStart;
-        readonly attribute DOMHighResTimeStamp styleAndLayoutStart;
-        readonly attribute DOMHighResTimeStamp blockingDuration;
-        readonly attribute DOMHighResTimeStamp firstUIEventTimestamp;
-        [SameObject] readonly attribute FrozenArray<PerformanceScriptTiming> scripts;
-        [Default] object toJSON();
-    };
-
- -A {{PerformanceLongAnimationFrameTiming}} has a [=frame timing info=] timing info. - -The {{PerformanceLongAnimationFrameTiming/entryType}} attribute's getter step is to return "long-animation-frame". - -The {{PerformanceLongAnimationFrameTiming/name}} attribute's getter step is to return "long-animation-frame". - -The {{PerformanceLongAnimationFrameTiming/startTime}} attribute's getter step is to return the [=relative high resolution time=] given [=this=]'s [=PerformanceLongAnimationFrameTiming/timing info=]'s [=frame timing info/start time=] and [=this=]'s [=relevant global object=]. - -The {{PerformanceLongAnimationFrameTiming/duration}} attribute's getter step is to return the [=duration=] between [=this=]'s {{PerformanceEntry/startTime}} and the [=relative high resolution time=] given [=this=]'s [=PerformanceLongAnimationFrameTiming/timing info=]'s [=frame timing info/end time=] and [=this=]'s [=relevant global object=]. - -The {{PerformanceLongAnimationFrameTiming/renderStart}} attribute's getter step is to return the [=relative high resolution time=] given [=this=]'s [=PerformanceLongAnimationFrameTiming/timing info=]'s [=frame timing info/update the rendering start time=] and [=this=]'s [=relevant global object=]. - -The {{PerformanceLongAnimationFrameTiming/styleAndLayoutStart}} attribute's getter step is to return the [=relative high resolution time=] given [=this=]'s [=PerformanceLongAnimationFrameTiming/timing info=]'s [=frame timing info/style and layout start time=] and [=this=]'s [=relevant global object=]. - -The {{PerformanceLongAnimationFrameTiming/firstUIEventTimestamp}} attribute's getter step is to return the [=relative high resolution time=] given [=this=]'s [=PerformanceLongAnimationFrameTiming/timing info=]'s [=frame timing info/first ui event timestamp=] and [=this=]'s [=relevant global object=]. - -The {{PerformanceLongAnimationFrameTiming/blockingDuration}} attribute's getter steps are: - 1. Let |sortedTaskDurations| be [=PerformanceLongAnimationFrameTiming/timing info=]'s [=frame timing info/task durations=], [=list/sort in descending order|sorted in descending order=]. - 1. If [=this=]'s [=PerformanceLongAnimationFrameTiming/timing info=]'s [=frame timing info/update the rendering start time=] is not zero, then: - 1. Let |renderDuration| be the [=duration=] between [=this=]'s {{PerformanceLongAnimationFrameTiming/renderStart}} and - the [=relative high resolution time=] given [=this=]'s [=PerformanceLongAnimationFrameTiming/timing info=]'s [=frame timing info/end time=]. - 1. Increment |sortedTaskDurations|[0] by |renderDuration|. - - Note: This makes it so that the longest task duration + render duration would be considered blocking if their total - duration is >50ms. - - 1. Let |totalBlockingDuration| be 0. - 1. [=list/iterate|For each=] |duration| in |sortedTaskDurations|, if |duration| is greater than 50 then increment |totalBlockingDuration| by |duration| - 50. - 1. Return |totalBlockingDuration|. - -The {{PerformanceLongAnimationFrameTiming/scripts}} attribute's getter steps are: - 1. Let |scripts| be a [=/list=] « ». - 1. Let |entryWindow| be |this|'s [=relevant global object=]. - 1. [=list/For each=] |scriptInfo| in [=this=]'s [=frame timing info=]'s [=frame timing info/scripts=]: - 1. Let |scriptWindow| be |scriptInfo|'s [=script timing info/window=]. - 1. Let |scriptEntry| be a new {{PerformanceScriptTiming}} in [=this=]'s [=relevant realm=], - whose [=PerformanceScriptTiming/timing info=] is |scriptInfo| and whose [=PerformanceScriptTiming/window attribution=] is the value corresponding to the first matching statement: - - : |scriptWindow| is undefined - :: {{ScriptWindowAttribution/other}} - - : |scriptWindow| is |entryWindow| - :: {{ScriptWindowAttribution/self}} - - : |entryWindow|'s associated {{Document}}'s [=node navigable=]'s [=ancestor navigables=] [=list/contains=] |scriptWindow|'s associated {{Document}}'s [=node navigable=] - :: {{ScriptWindowAttribution/ancestor}} - - : |scriptWindow|'s associated {{Document}}'s [=node navigable=]'s [=ancestor navigables=] [=list/contains=] |entryWindow|'s associated {{Document}}'s [=node navigable=] - :: {{ScriptWindowAttribution/descendant}} - - : |entryWindow|'s associated {{Document}}'s [=node navigable=]'s [=navigable/top-level traversable=] is |scriptWindow|'s associated {{Document}}'s [=node navigable=]'s [=navigable/top-level traversable=] - :: {{ScriptWindowAttribution/same-page}} - - : Otherwise - :: {{ScriptWindowAttribution/other}}. - - 1. [=list/Append=] |scriptEntry| to |scripts|. - 1. Return |scripts|. - -{{PerformanceScriptTiming}} interface {#sec-PerformanceScriptTiming} ------------------------------------------------------------------------- - -
-    enum ScriptInvokerType {
-        "classic-script",
-        "module-script",
-        "event-listener",
-        "user-callback",
-        "resolve-promise",
-        "reject-promise"
-    };
-
-    enum ScriptWindowAttribution {
-        "self", "descendant", "ancestor", "same-page", "other"
-    };
-
-    [Exposed=Window]
-    interface PerformanceScriptTiming : PerformanceEntry {
-        /* Overloading PerformanceEntry */
-        readonly attribute DOMHighResTimeStamp startTime;
-        readonly attribute DOMHighResTimeStamp duration;
-        readonly attribute DOMString name;
-        readonly attribute DOMString entryType;
-
-        readonly attribute ScriptInvokerType invokerType;
-        readonly attribute DOMString invoker;
-        readonly attribute DOMHighResTimeStamp executionStart;
-        readonly attribute DOMString sourceURL;
-        readonly attribute DOMString sourceFunctionName;
-        readonly attribute long long sourceCharPosition;
-        readonly attribute DOMHighResTimeStamp pauseDuration;
-        readonly attribute DOMHighResTimeStamp forcedStyleAndLayoutDuration;
-        readonly attribute Window? window;
-        readonly attribute ScriptWindowAttribution windowAttribution;
-        [Default] object toJSON();
-    };
-
- -A {{PerformanceScriptTiming}} has an associated [=script timing info=] timing info. - -A {{PerformanceScriptTiming}} has an associated {{ScriptWindowAttribution}} window attribution. - -The {{PerformanceScriptTiming/entryType}} attribute's getter step is to return "script". - -The {{PerformanceScriptTiming/name}} attribute's getter step is to return "script". - -The {{PerformanceScriptTiming/invokerType}} attribute's getter step is to return [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/invoker type=]. - -The {{PerformanceScriptTiming/invoker}} attribute's getter steps are: - 1. Switch on |this|'s {{PerformanceScriptTiming/invokerType}}: - - : "`classic-script`" - : "`module-script`" - :: Return |this|'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/source url=]. - - : "`event-listener`" - :: - 1. Let |targetName| be |this|'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/invoker name=]. - 1. If |this|'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/event target element id=] is not the empty string, then: - Set |targetName| to the [=concatenate|concatenation=] of « |targetName|, "#", |this|'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/event target element id=] ». - 1. Otherwise, If |this|'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/event target element src attribute=] is not the empty string, then: - Set |targetName| to the [=concatenate|concatenation=] of « |targetName|, '[src=', |this|'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/event target element src attribute=], ']' ». - 1. Return the [=concatenate|concatenation=] of « |targetName|, ".on", [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/event type=] ». - - Issue: this feels a bit custom, need to discuss name generation. - - : "`user-callback`" - :: Return |this|'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/invoker name=]. - - : "`resolve-promise`" - : "`reject-promise`" - :: - 1. If |this|'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/invoker name=] is the empty string, - then: - 1. If |this|'s {{PerformanceScriptTiming/invokerType}} is "`resolve-promise`", then return "`Promise.resolve`". - 1. Otherwise, return "`Promise.reject`". - 1. Let |thenOrCatch| be "`then`" if {{PerformanceScriptTiming/invokerType}} is "`resolve-promise`"; otherwise "`reject-promise`". - 1. Return the [=concatenate|concatenation=] of « [=script timing info/invoker name=], ".", |thenOrCatch| ». - -The {{PerformanceScriptTiming/startTime}} attribute's getter step is to return the [=relative high resolution time=] given [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/start time=] and [=this=]'s [=relevant global object=]. - -The {{PerformanceScriptTiming/duration}} attribute's getter step is to return the [=duration=] between [=this=]'s {{PerformanceScriptTiming/startTime}} and the [=relative high resolution time=] given [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/end time=] and [=this=]'s [=relevant global object=]. - -The {{PerformanceScriptTiming/executionStart}} attribute's getter step is to return 0 if [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/execution start time=] is 0; Otherwise the [=relative high resolution time=] given [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/execution start time=] and [=this=]'s [=relevant global object=]. - -The {{PerformanceScriptTiming/forcedStyleAndLayoutDuration}} attribute's getter step is to return an [=implementation-defined=] value that represents time spent performing style and layout synchronously, e.g. by calling {{Window/getComputedStyle()}} or {{Element/getBoundingClientRect()}}. - - Issue: Find a way to make this interoperable/normative. Perhaps mark those functions in WebIDL as requiring synchronous style/layout? Also move to [=PerformanceScriptTiming/timing info=] once that's resolved. - -The {{PerformanceScriptTiming/pauseDuration}} attribute's getter step is to return [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/pause duration=]. - -The {{PerformanceScriptTiming/sourceURL}} attribute's getter step is to return [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/source url=]. -The {{PerformanceScriptTiming/sourceFunctionName}} attribute's getter step is to return [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/source function name=]. -The {{PerformanceScriptTiming/sourceCharPosition}} attribute's getter step is to return [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/source character position=]. - -The {{PerformanceScriptTiming/window}} attribute's getter steps are: - 1. Let |window| be the result of calling [=weakrefderef|deref=] on [=this=]'s [=PerformanceScriptTiming/timing info=]'s [=script timing info/window=]. - 1. If |window| is undefined, then return null; Otherwise return |window|. - -The {{PerformanceScriptTiming/windowAttribution}} attribute's getter step is to return [=this=]'s [=PerformanceScriptTiming/window attribution=]. - Processing model {#sec-processing-model} ======================================== -Note: A user agent implementing the Long Tasks or Long Animation Frame API would need to include "longtask" or "long-animation-frame" +Note: A user agent implementing the Long Tasks API would need to include "longtask" in {{PerformanceObserver/supportedEntryTypes}} for {{Window}} contexts, respectively. This allows developers to detect support for long tasks. @@ -611,404 +395,6 @@ Report long tasks {#report-long-tasks} -Frame Timing Info {#sec-frame-timing-info} ------------------------------------------- -frame timing info is a [=struct=] used as a bookkeeping detail by the long animation frame algorithms. -It has the following [=struct/items=]: - -
- : start time - : current task start time - : update the rendering start time - : style and layout start time - : first ui event timestamp - : end time - :: A {{DOMHighResTimeStamp}}, initially 0. - Note: all the above are [=monotonic clock/unsafe current time=|unsafe=], - and should be [=coarsen time|coarsened=] when exposed via an API. - - : task durations - :: A [=/list=] of {{DOMHighResTimeStamp}}, initially empty. - - : scripts - :: A [=/list=] of [=script timing info=], initially empty. - - : pending script - :: Null or a [=script timing info=], initially null. -
- -script timing info is a [=struct=]. It has the following [=struct/items=]: - -
- : invoker type - :: A {{ScriptInvokerType}}. - - : start time - : end time - : execution start time - :: An unsafe {{DOMHighResTimeStamp}}, initially 0. - - : pause duration - :: A {{DOMHighResTimeStamp}} representing a number of milliseconds, initially 0. - - : invoker name - : source url - : source function name - : event type - : event target element id - : event target element src attribute - :: A string, initially the empty string. - - : source character position - :: A number, initially -1. - - : window - :: A {{WeakRef}} to a {{Window}}. -
- -A {{Document}} has a null or [=frame timing info=] current frame timing info, initially null. - - -Report Long Animation Frames {#loaf-processing-model} ------------------------------------------- - -### Long Animation Frame Monitoring {#loaf-monitoring} - -
- To get the nearest same-origin root for a {{Document}} |document|: - 1. Let |ancestors| be the [=ancestor navigables=] of |document|. - - 1. [=list/For each=] |ancestorNavigable| in |ancestors|: - If |ancestorNavigable|'s [=navigable/active document=]'s [=Document/origin=] is [=same origin=] with |document|'s [=Document/origin=], - and |ancestorNavigable|'s [=navigable/active document=]'s [=relevant agent=] is |document|'s [=relevant agent=], - then return |ancestorNavigable|'s [=navigable/active document=]. - - 1. Return |document|. - - The relevant frame timing info for a {{Document}} |document| is its [=nearest same-origin root=]'s [=current frame timing info=]. -
- -
- To report task start time given a {{DOMHighResTimeStamp}} |unsafeTaskStartTime|, and a {{Document}} |document|: - - 1. Let |root| be |document|'s [=nearest same-origin root=]. - - 1. If |root|'s [=current frame timing info=] is null, - then set |root|'s [=current frame timing info=] to a new [=frame timing info=] whose [=frame timing info/start time=] is |unsafeTaskStartTime|. - - 1. Set |root|'s [=current frame timing info=]'s [=frame timing info/current task start time=] to |unsafeTaskStartTime|. - - 1. If |root|'s [=current frame timing info=]'s 's [=frame timing info/start time=] is 0, then set |root|'s [=current frame timing info=]'s [=frame timing info/start time=] to |unsafeTaskStartTime|. -
- -
- To report task end time given an {{DOMHighResTimeStamp}} |unsafeTaskEndTime|, and a {{Document}} |document|: - - 1. Let |timingInfo| be |document|'s [=relevant frame timing info=]. - - 1. If |timingInfo| is null, then return. - - Note: This can occur if the browser becomes hidden during the sequence. - - 1. Let |safeTaskEndTime| be the [=relative high resolution time=] given |unsafeTaskEndTime| and |document|'s [=relevant global object=]. - - 1. Let |safeTaskStartTime| be the [=relative high resolution time=] given |timingInfo|'s [=frame timing info/current task start time=] and |document|'s [=relevant global object=]. - - 1. [=list/Append=] the [=duration=] between |safeTaskStartTime| and |safeTaskEndTime| to |timingInfo|'s [=task durations=]. - - 1. If the user agent believes that updating the rendering of |document|'s [=node navigable=] would have no visible effect, then [=flush frame timing=] given |document| and return. - - Note: even though there was no actual visual update, we mark a [=long animation frame=] here because it would be blocking in a scenario where it coincided with an unrelated visual update. -
- -
- To report rendering time given a {{Document}} |document|, and a {{DOMHighResTimeStamp}} |unsafeStyleAndLayoutStart|: - - 1. Let |timingInfo| be |document|'s [=relevant frame timing info=]. - - 1. If |timingInfo| is null, then return. - - Note: This can occur if the browser becomes hidden during the sequence. - - 1. Set |timingInfo|'s [=frame timing info/update the rendering start time=] to |timingInfo|'s [=frame timing info/current task start time=]. - - 1. Set |timingInfo|'s [=frame timing info/style and layout start time=] to |unsafeStyleAndLayoutStart|. - - 1. [=Flush frame timing=] given |document| and the [=unsafe shared current time=]. -
- -
- To flush frame timing given a {{Document}} |document| and a {{DOMHighResTimeStamp}} |unsafeEndTime|: - - 1. Let |timingInfo| be |document|'s [=relevant frame timing info=]. - - 1. Assert: |timingInfo| is not null. - - 1. Let |global| be |document|'s [=relevant global object=]. - - 1. Let |frameDuration| be the [=duration=] between the [=relative high resolution time=] given |timingInfo|'s [=frame timing info/start time=] and |global|, - and the [=relative high resolution time=] given |unsafeEndTime| and |global|. - - 1. If |frameDuration| is greater than 50 milliseconds, then - [=queue a PerformanceEntry|Queue=] a new {{PerformanceLongAnimationFrameTiming}} in |document|'s [=relevant realm=], - whose [=PerformanceLongAnimationFrameTiming/timing info=] is |timingInfo|. - - 1. set |document|'s [=nearest same-origin root=]'s [=current frame timing info=] to null. -
- -### Long Script Monitoring ### {#long-script-monitoring} - -
- To report user callback given a [=callback function=] |callback| and an [=environment settings object=] |settings|: - [=Create script entry point=] given |settings|, "`user-callback`", and the following steps given a [=script timing info=] |scriptTimingInfo|: - - 1. Set |scriptTimingInfo|'s [=script timing info/invoker name=] to |callback|'s [=identifier=]. - 1. [=Apply source location=] for |scriptTimingInfo| given |callback|. -
- -
- To report timer handler given a string or {{Function}} |handler|, an [=environment settings object=] |settings|, and a boolean |repeat|: - [=Create script entry point=] given |settings|, "`user-callback`", - and the following steps given a [=script timing info=] |scriptTimingInfo|: - - 1. Let |setTimeoutOrInterval| be "setInterval" if |repeat| is true, "setTimeout" otherwise. - 1. Set |scriptTimingInfo|'s [=script timing info/invoker name=] to [=concatenate|concatenation=] of - « TimerHandler:", |setTimeoutOrInterval| ». - 1. If |handler| is a {{Function}}, then [=apply source location=] for |scriptTimingInfo| given |handler|. -
- -
- To report event handler given an {{Event}} |event| and an {{EventListener}} |listener|: - [=Create script entry point=] given |listener|'s [=relevant settings object=], "`event-listener`", - and the following steps given a [=script timing info=] |scriptTimingInfo| and a [=frame timing info=] |frameTimingInfo|: - - 1. Set |scriptTimingInfo|'s [=script timing info/event type=] to |event|'s {{Event/type}}. - 1. Let |target| be |event|'s {{Event/currentTarget}}. - 1. If |target| is a {{Node}}, then: - 1. Set |scriptTimingInfo|'s [=script timing info/invoker name=] to |target|'s {{Node/nodeName}}. - 1. If |target| is an {{Element}}, then: - 1. Set |scriptTimingInfo|'s [=script timing info/event target element id=] to |target|'s [=Element/id=]. - 1. Set |scriptTimingInfo|'s [=script timing info/event target element src attribute=] to the result of [=get an attribute by name|getting an attribute value by name=] "`src`" and |target|. - 1. Else, set |scriptTimingInfo|'s [=script timing info/invoker name=] to |target|'s interface name. - 1. [=Apply source location=] for |scriptTimingInfo| given |listener|'s [=event listener/callback=]. - 1. If |event| is a {{UIEvent}}, and |frameTimingInfo|'s [=frame timing info/first ui event timestamp=] is 0, - then set |frameTimingInfo|'s [=frame timing info/first ui event timestamp=] to |event|'s {{Event/timeStamp}}. -
- -
- To report promise resolver given a {{Promise}} |promise| and a "`resolve-promise`" or "`reject-promise`" |type|: - 1. [=Create script entry point=] given |promise|'s [=relevant realm=]'s [=realm/settings object=], |type|, - and the following steps given a [=script timing info=] |scriptTimingInfo|: - - 1. Set |scriptTimingInfo|'s [=script timing info/invoker name=] to |promise|'s [=Promise/invoker name when created=]. - 1. Set |scriptTimingInfo|'s [=script timing info/source url=] to |promise|'s [=Promise/script url when created=]. -
- -
- To set source url for script block given a [=script timing info=] |scriptTimingInfo|, a [=/script=] |script|, and a [=/URL=] |url|: - 1. If |url|'s [=url/scheme=] is "`http`" or "`https`", then set |scriptTimingInfo|'s [=script timing info/source url=] to |script|'s [=script/base URL=]. - 1. Otherwise, if |url|'s [=url/scheme=] is "`blob`" or "`data`" then set |scriptTimingInfo|'s [=script timing info/source url=] to the [=concatenate|concatenation=] of « |url|'s [=url/scheme=], ":"" ». -
- -
- To report classic script creation given a [=/script=] |script| and a [=/URL=] |originalSourceURL|: - 1. [=Create script entry point=] with |script|'s [=script/settings object=], "`classic-script`", - and the following step given a [=script timing info=] |scriptTimingInfo|: - [=Set source url for script block=] given |scriptTimingInfo|, |script|, and |originalSourceURL|. -
- -
- To report classic script execution start given a [=classic script=] |script|: - 1. Let |settings| be |script|'s [=script/settings object=]. - 1. If |script|'s [=classic script/muted errors=] is true, then return. - 1. If |settings| is not a {{Window}}, then return. - 1. Let |document| be |settings|'s {{Window/document}}. - 1. Let |frameTimingInfo| be |document|'s [=relevant frame timing info=]. - 1. If |frameTimingInfo| is null or if |frameTimingInfo|'s [=frame timing info/pending script=] is not null, then return. - 1. Assert: |frameTimingInfo|'s [=frame timing info/pending script=]'s [=script timing info/invoker type=] is "`classic-script`". - 1. Set |frameTimingInfo|'s [=frame timing info/pending script=]'s [=script timing info/execution start time=] to the [=unsafe shared current time=]. -
- -
- To report module script execution start given a [=module script=] |script|: - [=Create script entry point=] with |script|'s [=script/settings object=], "`module-script`", - and the following step given a [=script timing info=] |scriptTimingInfo|: - 1. Set |scriptTimingInfo|'s [=script timing info/execution start time=] to |script|'s |scriptTimingInfo|'s [=script timing info/start time=]. - 1. [=Set source url for script block=] given |scriptTimingInfo|, |script|, and |script|'s [=script/base URL=]. -
- -
- To create script entry point given an [=environment settings object=] |settings|, - a {{ScriptInvokerType}} |invokerType|, and |steps|, - which is an algorithm that takes a [=script timing info=] and an optional [=frame timing info=]: - - 1. If |settings| is not a {{Window}}, then return. - 1. Let |document| be |settings|'s {{Window/document}}. - 1. If |document| is not [=fully active=] or {{Document/hidden}}, then return. - 1. Let |frameTimingInfo| be |document|'s [=relevant frame timing info=]. - 1. If |frameTimingInfo| is null, then return. - 1. If |frameTimingInfo|'s [=frame timing info/pending script=] is not null, then return. - 1. Let |scriptTimingInfo| be a new [=script timing info=] - whose [=script timing info/start time=] is the [=unsafe shared current time=], - and whose [=script timing info/invoker type=] is |invokerType|. - 1. Run |steps| given |scriptTimingInfo| and |frameTimingInfo|. - 1. Set |scriptTimingInfo|'s [=script timing info/window=] to |settings|. - 1. Set |frameTimingInfo|'s [=frame timing info/pending script=] to |scriptTimingInfo|. -
- -
- To flush script entry point: - - 1. Let |script| be the [=running script=]. - 1. Let |settings| be |script|'s [=script/settings object=]. - 1. Let |document| be |settings|'s {{Window/document}}. - 1. If |document| is not [=fully active=] or {{Document/hidden}}, then return. - 1. Let |frameTimingInfo| be |document|'s [=relevant frame timing info=]. - 1. Let |scriptTimingInfo| be |frameTimingInfo|'s [=frame timing info/pending script=]. - 1. Set |frameTimingInfo|'s [=frame timing info/pending script=] to null. - 1. If |scriptTimingInfo| is null, then return. - 1. Set |scriptTimingInfo|'s [=script timing info/end time=] to the [=unsafe shared current time=]. - 1. If |script| is a [=classic script=] whose [=classic script/muted errors=] is true, then: - 1. set |scriptTimingInfo|'s [=script timing info/source url=] to the empty string. - 1. set |scriptTimingInfo|'s [=script timing info/source character position=] to -1. - 1. set |scriptTimingInfo|'s [=script timing info/source function name=] to the empty string. - 1. If the [=duration=] between |scriptTimingInfo|'s [=script timing info/start time=] and |scriptTimingInfo|'s [=script timing info/end time=] is greater than 5 milliseconds, then - [=list/append=] |scriptTimingInfo| to |frameTimingInfo|'s [=frame timing info/scripts=]. -
- -
- To apply source location to a [=script timing info=] |scriptTimingInfo| given a [=callback function=] or {{Function}} |callback|: - 1. The user agent may set |scriptTimingInfo|'s [=script timing info/source url=] to the source URL of the script where |callback| was defined. - 1. The user agent may set |scriptTimingInfo|'s [=script timing info/source function name=] to the function name of |callback|. - 1. The user agent may set |scriptTimingInfo|'s [=script timing info/source character position=] to the character position where |callback| was defined. -
- -
- To report pause duration given a [=duration=] |duration|: - 1. Let |script| be the [=running script=]. - 1. Let |settings| be |script|'s [=script/settings object=]. - 1. If |settings| is not a {{Window}}, then return. - 1. Let |document| be |settings|'s {{Window/document}}. - 1. If |document| is not [=fully active=] or {{Document/hidden}}, then return. - 1. Let |frameTimingInfo| be |document|'s [=relevant frame timing info=]. - 1. If |frameTimingInfo| is null, then return. - 1. If |frameTimingInfo|'s [=frame timing info/pending script=] is null, then return. - 1. Increment |frameTimingInfo|'s [=frame timing info/pending script=]'s [=script timing info/pause duration=] by the milliseconds value of |duration|. -
- -Additions to existing standards {#other-standards} -================================================== - -Issue: these should be upstreamed upon formal positive signals from -Gecko -/WebKit. - -Monkey-patches to the WebIDL standard {#webidl-monkey-patches} ----------------------------------------------------------- -
-The {{Promise}} interface has an associated string invoker name when created, initially "`Promise`". -The {{Promise}} interface has an associated string script url when created, initially the empty string. - -Append the following steps to creating a new promise, before returning the {{Promise}}: - 1. Let |interfaceName| be a string representing the [=interface=] responsible for creating this promise. - 1. Let |attributeName| be a string representing the [=attribute=] in the interface responsible for creating this promise. - 1. Set the created {{Promise}}'s [=Promise/script url when created=] to the [=running script=]'s [=script/base URL=]. - 1. The user-agent may set the created {{Promise}}'s [=Promise/invoker name when created=] to the last known [=concatenate|concatenation=] of - « |interfaceName|, ".", |attributeName| » - - Issue: this is quite handwavy, because this is difficult to do in a normative way. Need to see if - that can be improved, or if the source location for promise handlers would remain a bit implementation-defined. - -Prepend the following step to resolve a promise given {{Promise}} |p|: - [=Report promise resolver=] given |p| and "`resolve-promise`". - -Prepend the following step to reject a promise given {{Promise}} |p|: - [=Report promise resolver=] given |p| and "`reject-promise`". -
- -
-Insert the following steps to invoke a callback function, - once we have an [=environment settings object=] |relevant settings| and a [=callback function=] |F|: - [=Report user callback=] given |F| and |relevant settings|. -
- - -Monkey-patches to the DOM standard {#dom-monkey-patches} ----------------------------------------------------------- -
- Insert the following step to the inner invoke steps, - after determining that |global| is a {{Window}} (after step 8.2), assuming an [=event listener=] |listener|: - [=Report event handler=] given |global|'s {{Window/event}} and |listener|. -
- - -Monkey-patches to the HTML standard {#html-monkey-patches} ----------------------------------------------------------- -
- Insert step after step 2.3 of the event loop processing model, - after setting |taskStartTime| and |oldestTask|: - - 1. [=Report task start time=] given |taskStartTime| and |oldestTask|'s [=task/document=]. -
- -
- Insert a step before [update the rendering](https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering) step 6.14, - right before the loop that calculates style and layout for each {{Document}}: - - 1. Let |unsafeStyleAndLayoutStartTime| be the [=unsafe shared current time=]. - - Insert the following steps after [update the rendering](https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering) step 6.18, - right after calling [=mark paint timing=], using the existing |docs| variable: - - 1. Let |unsafeRenderingEndTime| be the [=unsafe shared current time=]. - 1. [=Report rendering time=] for each [=fully active=] {{Document}} object in |docs| given |unsafeRenderingEndTime| |unsafeStyleAndLayoutStartTime|. -
- -
- Insert a step to the timer initialisation steps, - after asserting that the timer ID exists in the map of active timers (After step 8.1), - assuming a {{Function}} or string |handler|, a {{WindowOrWorkerGlobalScope}} |global|, and a boolean |repeat|: - - 1. [=Report timer handler=] given |handler|, |global|'s [=relevant settings object=], and |repeat|. - - 1. Let |unsafeStyleAndLayoutStartTime| be the [=unsafe shared current time=]. - - Insert the following steps after [update the rendering](https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering) step 6.18, - right after calling [=mark paint timing=], using the existing |docs| variable: - - 1. Let |unsafeRenderingEndTime| be the [=unsafe shared current time=]. - 1. [=Report rendering time=] for each [=fully active=] {{Document}} object in |docs| given |unsafeRenderingEndTime| |unsafeStyleAndLayoutStartTime|. -
- -
- The [=classic script=] [=struct=] has an additional item: - - Insert a step to the create a classic script steps, - before parsing the script, assuming the |script| variable is populated, assuming a |url| variable: - [=Report classic script creation=] given |script| and |url|. - - Insert a step to the run a classic script steps, - before preparing to run a script (between steps 2 and 3): - [=Report classic script execution start=] given |script|. - - Insert a step to the run a module script steps, - before preparing to run a script (between steps 2 and 3): - [=Report module script execution start=] given |script|. -
- -
- Append the following step to perform a microtask checkpoint: - [=Flush script entry point=]. -
- -
- Add the following steps to pause: - - Prepend the following step: Let |timeBeforePause| be the [=monotonic clock/unsafe current time=]. - - Append the following step: [=Report pause duration=] given the [=duration=] between |timeBeforePause| and the [=monotonic clock/unsafe current time=]. -
- Security & privacy considerations {#priv-sec} =============================================== @@ -1070,23 +456,4 @@ The following are the timing attacks considered: the permalink page can be used to determine whether the user is in the target demographic. These scenarios are addressed by the 50ms threshold AND respecting cross-origin boundary i.e. not -showing task type or additional attribution to untrusted cross origin observers. - -Additional information exposed by the Long Animation Frames API {#loaf-sec-priv} --------------------------------------------------------------------------------- -Since several cross-origin documents can share the same event loop, they can also render as part of -the same frame sequence and influence each other's rendering time. This makes it so that these timings -are already somewhat observable cross-origin, e.g. by requesting an animation frame and observing if it is delayed, -though long animation frames exposes them at a higher fidelity. - -To mitigate this, long animation frames are only reported to "participating local roots": only documents -that are associated with a work task that contributed to the sequence, or that were rendered as part of the frame, -are eligible to observe the long animation frame, and that long animation frame would be available only in -their nearest ancestor that is either topmost or has a cross-origin parent. - -{{PerformanceScriptTiming}} and opaque scripts {#loaf-opaque-scripts-sec} ------------------------------------------------ -Since {{PerformanceScriptTiming}} exposes information about script execution, we need to make sure it -doesn't expose too much information about [=CORS cross-origin=] scripts that cannot be easily deduced otherwise. -To do that, we use the existing [=classic script/muted errors=] boolean, and report an empty {{PerformanceScriptTiming/sourceLocation}} -in such cases. +showing task type or additional attribution to untrusted cross origin observers. \ No newline at end of file