diff --git a/images/anim-tao.png b/images/anim-tao.png
new file mode 100644
index 00000000000000..925e2efc9a97ad
Binary files /dev/null and b/images/anim-tao.png differ
diff --git a/images/anim-tao.png.headers b/images/anim-tao.png.headers
new file mode 100644
index 00000000000000..0230e176e44567
--- /dev/null
+++ b/images/anim-tao.png.headers
@@ -0,0 +1,2 @@
+Timing-Allow-Origin: *
+
diff --git a/images/webp-animated.webp b/images/webp-animated.webp
new file mode 100644
index 00000000000000..35a8dfcf34d580
Binary files /dev/null and b/images/webp-animated.webp differ
diff --git a/largest-contentful-paint/animated/observe-animated-image-gif.tentative.html b/largest-contentful-paint/animated/observe-animated-image-gif.tentative.html
new file mode 100644
index 00000000000000..a2c0d7975abe34
--- /dev/null
+++ b/largest-contentful-paint/animated/observe-animated-image-gif.tentative.html
@@ -0,0 +1,27 @@
+
+
+
+
+ Largest Contentful Paint: observe image.
+
+
+
+
+
+
+
+
diff --git a/largest-contentful-paint/animated/observe-animated-image-webp.tentative.html b/largest-contentful-paint/animated/observe-animated-image-webp.tentative.html
new file mode 100644
index 00000000000000..de59d5c5f78c68
--- /dev/null
+++ b/largest-contentful-paint/animated/observe-animated-image-webp.tentative.html
@@ -0,0 +1,27 @@
+
+
+
+
+ Largest Contentful Paint: observe image.
+
+
+
+
+
+
+
+
diff --git a/largest-contentful-paint/animated/observe-animated-image.tentative.html b/largest-contentful-paint/animated/observe-animated-image.tentative.html
new file mode 100644
index 00000000000000..cf7d262b0f842a
--- /dev/null
+++ b/largest-contentful-paint/animated/observe-animated-image.tentative.html
@@ -0,0 +1,29 @@
+
+
+
+
+ Largest Contentful Paint: observe image.
+
+
+
+
+
+
+
+
diff --git a/largest-contentful-paint/animated/observe-cross-origin-animated-image.tentative.html b/largest-contentful-paint/animated/observe-cross-origin-animated-image.tentative.html
new file mode 100644
index 00000000000000..993883c607b8f7
--- /dev/null
+++ b/largest-contentful-paint/animated/observe-cross-origin-animated-image.tentative.html
@@ -0,0 +1,30 @@
+
+
+
+
+ Largest Contentful Paint: observe image.
+
+
+
+
+
+
+
+
+
diff --git a/largest-contentful-paint/animated/observe-cross-origin-tao-animated-image.tentative.html b/largest-contentful-paint/animated/observe-cross-origin-tao-animated-image.tentative.html
new file mode 100644
index 00000000000000..137dde66383f77
--- /dev/null
+++ b/largest-contentful-paint/animated/observe-cross-origin-tao-animated-image.tentative.html
@@ -0,0 +1,30 @@
+
+
+
+
+ Largest Contentful Paint: observe image.
+
+
+
+
+
+
+
+
+
diff --git a/largest-contentful-paint/animated/observe-non-animated-image.tentative.html b/largest-contentful-paint/animated/observe-non-animated-image.tentative.html
new file mode 100644
index 00000000000000..6bbc0958b1deb2
--- /dev/null
+++ b/largest-contentful-paint/animated/observe-non-animated-image.tentative.html
@@ -0,0 +1,27 @@
+
+
+
+
+ Largest Contentful Paint: observe image.
+
+
+
+
+
+
+
+
diff --git a/largest-contentful-paint/resources/largest-contentful-paint-helpers.js b/largest-contentful-paint/resources/largest-contentful-paint-helpers.js
index e12ece0a7561cb..5012faf3b1be33 100644
--- a/largest-contentful-paint/resources/largest-contentful-paint-helpers.js
+++ b/largest-contentful-paint/resources/largest-contentful-paint-helpers.js
@@ -1,3 +1,6 @@
+const image_delay = 1000;
+const delay_pipe_value = image_delay / 1000;
+
// Receives an image LargestContentfulPaint |entry| and checks |entry|'s attribute values.
// The |timeLowerBound| parameter is a lower bound on the loadTime value of the entry.
// The |options| parameter may contain some string values specifying the following:
@@ -33,4 +36,33 @@ function checkImage(entry, expectedUrl, expectedID, expectedSize, timeLowerBound
} else {
assert_equals(entry.size, expectedSize);
}
+ if (options.includes('animated')) {
+ assert_greater_than(entry.loadTime, entry.firstAnimatedFrameTime,
+ 'firstAnimatedFrameTime should be smaller than loadTime');
+ assert_greater_than(entry.renderTime, entry.firstAnimatedFrameTime,
+ 'firstAnimatedFrameTime should be smaller than renderTime');
+ assert_less_than(entry.firstAnimatedFrameTime, image_delay,
+ 'firstAnimatedFrameTime should be smaller than the delay applied to the second frame');
+ assert_greater_than(entry.firstAnimatedFrameTime, 0,
+ 'firstAnimatedFrameTime should be larger than 0');
+ }
+ if (options.includes('animated-zero')) {
+ assert_equals(entry.firstAnimatedFrameTime, 0, 'firstAnimatedFrameTime should be 0');
+ }
}
+
+const load_and_observe = url => {
+ return new Promise(resolve => {
+ (new PerformanceObserver(entryList => {
+ for (let entry of entryList.getEntries()) {
+ if (entry.url == url) {
+ resolve(entryList.getEntries()[0]);
+ }
+ }
+ })).observe({type: 'largest-contentful-paint', buffered: true});
+ const img = new Image();
+ img.id = 'image_id';
+ img.src = url;
+ document.body.appendChild(img);
+ });
+};