Bug 267808 - OffscreenCanvas rendered with ImageData on a Web Worker does not resize properly.
Summary: OffscreenCanvas rendered with ImageData on a Web Worker does not resize prope...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Canvas (show other bugs)
Version: Safari 16
Hardware: Mac (Apple Silicon) macOS 13
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2024-01-20 00:05 PST by Arhan Chaudhary
Modified: 2024-04-13 16:17 PDT (History)
5 users (show)

See Also:


Attachments
The code snippet running on my machine. (10.29 MB, video/mp4)
2024-01-20 00:05 PST, Arhan Chaudhary
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Arhan Chaudhary 2024-01-20 00:05:46 PST
Created attachment 469478 [details]
The code snippet running on my machine.

I've ran into a particular canvas rendering issue that only happens on Safari. Following is the code snippet that produces the behavior demonstrated in the attached video.

index.html

<canvas style="border: 15px solid red; width: 50vw;" width="512" height="256"></canvas>
<script>
    const canvas = document.querySelector('canvas');
    const ctx = canvas.transferControlToOffscreen();
    const worker = new Worker('worker.js');
    worker.postMessage(ctx, [ctx]);
    self.onresize = () => {
        worker.postMessage(undefined);
    }
</script>


worker.js

self.onmessage = (e) => {
  let ctx = e.data.getContext("2d");
  self.onmessage = () => {
    const imageData = ctx.createImageData(512, 256);
    const data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
      data[i] = 0;
      data[i + 1] = 0;
      data[i + 2] = 0;
      data[i + 3] = 255;
    }
    for (let i = 50; i < 120; i++) {
      for (let j = 50; j < 120; j++) {
        const index = (i + j * imageData.width) * 4;
        data[index] = 255;
        data[index + 1] = 0;
        data[index + 2] = 0;
        data[index + 3] = 255;
      }
    }
    ctx.putImageData(imageData, 0, 0);
  };
};

Some of my preliminary questions include: Why does the canvas image sometimes escape its content box and "move" to the border box? Why does the canvas image not scale with the rest of the content box? Does some sort of inner buffer data race condition cause the flashing? Could the culprit be the explicit width and height in ctx.createImageData(512, 256)?

From my testing thus far, no similar derivative of this code causes the bug to occur. It only seems to happen under the following set of circumstances:
1. you are using safari
2. you are using a web worker to render an offscreen canvas
3. you are constantly updating the screen
4. you are rendering the canvas with ImageData
5. you are actively resizing the screen
Comment 1 Radar WebKit Bug Importer 2024-01-27 00:06:16 PST
<rdar://problem/121721620>
Comment 2 Arhan Chaudhary 2024-04-13 16:17:34 PDT
This seems to have been fixed in Safari v17.4.1