LoAF: Use document character position for inline scripts

This applies to classic/module script blocks and event content
attributes.

Bug: 328209286
Change-Id: Id11e0a9324c529925b11b950d73ed4491410f96d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5425010
Reviewed-by: Michal Mocny <mmocny@chromium.org>
Reviewed-by: Kouhei Ueno <kouhei@chromium.org>
Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1291353}
diff --git a/long-animation-frame/tentative/loaf-source-location-inline-classic-script.html b/long-animation-frame/tentative/loaf-source-location-inline-classic-script.html
new file mode 100644
index 0000000..30033c9
--- /dev/null
+++ b/long-animation-frame/tentative/loaf-source-location-inline-classic-script.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>Long Animation Frame Timing: source location for inline classic scripts</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+
+<body>
+  <script>
+    busy_wait();
+  </script>
+  <script>
+    promise_test(async () => {
+      const script = await loaf_with_inline_script("classic-script");
+      assert_equals(script.sourceURL, location.href);
+      assert_greater_than(script.sourceCharPosition, 0);
+    }, "Source location should be available for inline classic scripts");
+  </script>
+</body>
diff --git a/long-animation-frame/tentative/loaf-source-location-inline-event-listener.html b/long-animation-frame/tentative/loaf-source-location-inline-event-listener.html
new file mode 100644
index 0000000..bd7e8bb
--- /dev/null
+++ b/long-animation-frame/tentative/loaf-source-location-inline-event-listener.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>Long Animation Frame Timing: source location for inline scripts</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+
+<body>
+<img id=image onload="busy_wait()">
+<script>
+  promise_test(async () => {
+    document.querySelector("#image").src = "/images/green.png";
+    const script = await loaf_with_inline_script("event-listener");
+    assert_equals(script.sourceURL, location.href);
+    assert_equals(script.sourceFunctionName, "onload");
+    assert_greater_than(script.sourceCharPosition, 0);
+  }, "Source location should be available for event handlers");
+</script>
+</body>
diff --git a/long-animation-frame/tentative/loaf-source-location-inline-module-script.html b/long-animation-frame/tentative/loaf-source-location-inline-module-script.html
new file mode 100644
index 0000000..f40b3e4
--- /dev/null
+++ b/long-animation-frame/tentative/loaf-source-location-inline-module-script.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>Long Animation Frame Timing: source location for inline module scripts</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+
+<body>
+<script type=module>
+  busy_wait();
+</script>
+<script>
+    promise_test(async () => {
+      const script = await loaf_with_inline_script("module-script");
+      assert_equals(script.sourceURL, location.href);
+      assert_greater_than(script.sourceCharPosition, 0);
+  }, "Source location should be available for inline classic scripts");
+  </script>
+</body>
diff --git a/long-animation-frame/tentative/resources/utils.js b/long-animation-frame/tentative/resources/utils.js
index aa537d3..a3f3da0 100644
--- a/long-animation-frame/tentative/resources/utils.js
+++ b/long-animation-frame/tentative/resources/utils.js
@@ -7,7 +7,7 @@
 const no_long_frame_timeout = very_long_frame_duration * 2;
 const waiting_for_long_frame_timeout = very_long_frame_duration * 10;
 
-function loaf_promise(t) {
+function loaf_promise(t, options = {}) {
   return new Promise(resolve => {
       const observer = new PerformanceObserver(entries => {
           const entry = entries.getEntries()[0];
@@ -20,7 +20,7 @@
 
       t.add_cleanup(() => observer.disconnect());
 
-      observer.observe({entryTypes: ['long-animation-frame']});
+      observer.observe({type: 'long-animation-frame', ...options});
   });
 }
 
@@ -29,7 +29,7 @@
   while (performance.now() < deadline) {}
 }
 
-async function expect_long_frame(cb, t) {
+async function expect_long_frame(cb, t, opt = {}) {
   await windowLoaded;
   await new Promise(resolve => t.step_timeout(resolve, 0));
   const timeout = new Promise((resolve, reject) =>
@@ -43,9 +43,9 @@
   return entry;
 }
 
-async function expect_long_frame_with_script(cb, predicate, t) {
+async function expect_long_frame_with_script(cb, predicate, t, opt = {}) {
   for (let i = 0; i < 10; ++i) {
-      const entry = await expect_long_frame(cb, t);
+      const entry = await expect_long_frame(cb, t, opt);
       if (entry === "timeout" || !entry.scripts.length)
         continue;
       for (const script of entry.scripts) {
@@ -129,3 +129,15 @@
 function test_self_script_block(cb, invoker, type) {
   test_loaf_script(cb, invoker, type);
 }
+
+function loaf_with_inline_script(type) {
+  return new Promise(resolve => new PerformanceObserver(entries => {
+    for (const e of entries.getEntries()) {
+      if (e.duration < very_long_frame_duration - 5)
+        return;
+      const script = e.scripts.find(s => s.invokerType === type && s.sourceURL === location.href);
+      if (script)
+        resolve(script);
+    }
+  }).observe({ type: "long-animation-frame", buffered: true }));
+}