Skip to content
Permalink
Browse files
canvas-createPattern-video-modify.html is an intermittent failure
https://bugs.webkit.org/show_bug.cgi?id=240780
rdar://93731906

Reviewed by Youenn Fablet.

The tests relied on the event "loadeddata" to be fired to check if the first video frame got painted.
However, at present there's no guarantee that a frame would have been painted at the time this event is fired.
This issue is separately tracked in bug 240779

So instead we use the new requestVideoCallbackFrame API which is designed specifically for this case.
We also simplify the existing page, using more modern JS features.

* LayoutTests/fast/canvas/canvas-createPattern-video-loading.html:
* LayoutTests/fast/canvas/canvas-createPattern-video-modify.html:
* LayoutTests/media/utilities.js:
(once):
(fetchWithXHR):
(waitForVideoFrame):
(waitForVideoFrameUntil):

Canonical link: https://commits.webkit.org/250910@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@294742 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
jyavenard committed May 24, 2022
1 parent 73d6aa6 commit 98d5ed7111afb53d8df891c4651d0bb375e890dd
Showing 3 changed files with 56 additions and 38 deletions.
@@ -3,6 +3,7 @@
<head>
<script src="../../resources/js-test-pre.js"></script>
<script src="../../media/media-file.js"></script>
<script src="../../media/utilities.js"></script>
<script src="../../resources/platform-helper.js"></script>
</head>
<body>
@@ -32,13 +33,13 @@
document.body.appendChild(canvases);

var video = document.createElement("video");
video.addEventListener("loadeddata", loadeddata);
video.addEventListener("playing", playing);

shouldBeNull("document.createElement('canvas').getContext('2d').createPattern(video, 'repeat')");

waitForVideoFrame(video, firstframe);
video.src = findMediaFile("video", "../../media/content/test");


function checkPixels(context, x, y, r, g, b, tolerance)
{
buffer = context.getImageData(x, y, 1, 1).data;
@@ -63,16 +64,13 @@
});
}

function loadeddata()
async function firstframe()
{
drawImageToCanvasAndCheckPixels();

video.currentTime = 1;
video.play();
}

function playing()
{
await waitForVideoFrameUntil(video, 1);
video.pause();

drawImageToCanvasAndCheckPixels();
@@ -3,6 +3,7 @@
<head>
<script src="../../resources/js-test-pre.js"></script>
<script src="../../media/media-file.js"></script>
<script src="../../media/utilities.js"></script>
<script src="../../resources/platform-helper.js"></script>
</head>
<body>
@@ -11,7 +12,6 @@

var buffer;
var canvas, context;
var modified = false;
var expectedResults = [
// Each entry is formatted as [x, y, r, g, b].
[40, 165, 200, 200, 0], // Represents yellow north west tile.
@@ -21,31 +21,30 @@
];

var video = document.createElement("video");
video.addEventListener("loadeddata", loadeddata);

waitForVideoFrame(video, firstframe);
video.src = findMediaFile("video", "../../media/content/test");

function loadeddata()
async function firstframe()
{
if (!modified) {
canvas = document.createElement("canvas");
canvas.width = 2.5 * video.videoWidth;
canvas.height = 2.5 * video.videoHeight;
document.body.appendChild(canvas);

context = canvas.getContext("2d");
context.fillStyle = context.createPattern(video, "repeat");

video.src = findMediaFile("video", "../../media/content/counting");
modified = !modified;
} else {
context.fillRect(0, 0, canvas.width, canvas.height);

expectedResults.forEach(function(element) {
checkPixels(context, element[0], element[1], element[2], element[3], element[4], videoCanvasPixelComparisonTolerance());
});

finishJSTest();
}
canvas = document.createElement("canvas");
canvas.width = 2.5 * video.videoWidth;
canvas.height = 2.5 * video.videoHeight;
document.body.appendChild(canvas);

context = canvas.getContext("2d");
context.fillStyle = context.createPattern(video, "repeat");

video.src = findMediaFile("video", "../../media/content/counting");

await waitForVideoFrame(video);

context.fillRect(0, 0, canvas.width, canvas.height);
expectedResults.forEach(function(element) {
checkPixels(context, element[0], element[1], element[2], element[3], element[4], videoCanvasPixelComparisonTolerance());
});

finishJSTest();
}

function checkPixels(context, x, y, r, g, b, tolerance)
@@ -4,9 +4,8 @@ function once(target, name, cb) {
resolve(event);
}, { once: true });
});
if (cb) {
if (cb)
p.then(cb);
}
return p;
}

@@ -21,9 +20,8 @@ function fetchWithXHR(uri, onLoadFunction) {
xhr.send();
});

if (onLoadFunction) {
if (onLoadFunction)
p.then(onLoadFunction);
}

return p;
};
@@ -42,18 +40,41 @@ function fetchAndLoad(sb, prefix, chunks, suffix) {
// Fetch the buffers in parallel.
let buffers = {};
let fetches = [];
for (var chunk of chunks) {
for (var chunk of chunks)
fetches.push(fetchWithXHR(prefix + chunk + suffix).then(((c, x) => buffers[c] = x).bind(null, chunk)));
}

// Load them in series, as required per spec.
return Promise.all(fetches).then(() => {
let rv = Promise.resolve();
for (let chunk of chunks) {
for (let chunk of chunks)
rv = rv.then(loadSegment.bind(null, sb, buffers[chunk]));
}
return rv;
});
}

const delay = ms => new Promise(res => setTimeout(res, ms));

function waitForVideoFrame(video, cb) {
const p = new Promise((resolve) => {
video.requestVideoFrameCallback((now, metadata) => resolve(now, metadata));
});
if (cb)
p.then(cb);
return p;
}

function waitForVideoFrameUntil(video, time, cb) {
const p = new Promise(resolve => {
const callback = ((now, metadata) => {
if (metadata.mediaTime >= time) {
resolve(now, metadata);
return;
}
video.requestVideoFrameCallback(callback);
});
video.requestVideoFrameCallback(callback);
});
if (cb)
p.then(cb);
return p;
}

0 comments on commit 98d5ed7

Please sign in to comment.