Support copying non-pngs and wait for focus to avoid race conditions#180322
Support copying non-pngs and wait for focus to avoid race conditions#180322mjbvz merged 4 commits intomicrosoft:mainfrom
Conversation
mjbvz
left a comment
There was a problem hiding this comment.
Thanks for looking into this! Left some small feedback
| canvas.getContext('2d').drawImage(image, 0, 0); | ||
| canvas.toBlob(async (blob) => { | ||
| try { | ||
| await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]); |
There was a problem hiding this comment.
Should we move the canvas drawing and toBlob call to be a promise inside ClipboardItem value?
There was a problem hiding this comment.
Added that, will test now to verify it works as expected.
| // copyImage is called at the same time as webview.reveal, which means this function is running whilst the webview is gaining focus. | ||
| // Since navigator.clipboard.write requires the document to be focused, we need to wait for focus. | ||
| // We cannot use a listener, as there is a high chance the focus is gained during the setup of the listener resulting in us missing it. | ||
| setTimeout(copyImage, 10); |
There was a problem hiding this comment.
Let's limit the number of retries on this. If the document doesn't get focused for some reason, I don't want this to be looping forever
There was a problem hiding this comment.
I've added a basic mechanism to limit it to 3 retries
There was a problem hiding this comment.
Increased to 5 retries 20ms apart. From testing 3 at 10 was regularly not enough, but 3 at 20 seems fine. Increasing to 5 retries at 20ms to be safe.
This is a follow up to #180269 which fixes #171616
I patched the first PR to test it out and notices a couple of problems.
Firstly, when right clicking, it would often fail with the error message:
This was because it was called by doing:
Since
.reveal()runs async, there was a race condition where the object was receiving focus and trying to copy at the same time, and for me, the copying was often winning.I tried to fix this by adding an event listener on document to wait for it to gain focus, but this would also usually fail as it would usually gain focus whilst the listener was being setup, causing it to miss the focus gain event. Instead, I have a slightly less optimal solution which just waits 10ms and then checks again for focus. In testing this was never called more than once so I think that it is acceptable. Another solution would be to have a message sent back from the webview when it has focus, and wait for that in the copy command on the extension side, but I think this would be a lot more expensive.
The other issue I came across was that the copy only works for png images, other types it complains about the mime type not matching. I tried setting the mimetype based on the content type returned in the fetch, but it turns out the clipboard only supports png.
What I have done here is created a temporary canvas, which we can write the image into, avoiding the fetch() entirely. This allows us to get a png from any image type - when testing with gifs, this only keeps a single frame of the gif, so there is room for improvement there.
I think there is room for improvement here, but this resolves some of the issues I was seeing when copying images.