RESOLVED FIXED212482
[macOS] Drag/drop an image of a unsupported format to an file input element should convert it to a supported format
https://bugs.webkit.org/show_bug.cgi?id=212482
Summary [macOS] Drag/drop an image of a unsupported format to an file input element s...
Said Abou-Hallawa
Reported 2020-05-28 11:51:44 PDT
If a page has an <input> file element which accepts an image like one of these: <input type="file" accept="image/*"> <input type="file" accept="image/png, image/jpeg"> And the user drags/drops an image of unsupported format, HEIF for example, the image should be converted to one of the formats in the "accept" attribute if possible. This will be similar to what happens when dragging and dropping a photo from the "Photos" app which is converting the HEIF image to JPEG image.
Attachments
Patch (51.46 KB, patch)
2020-06-21 15:47 PDT, Said Abou-Hallawa
no flags
Patch (34.05 KB, patch)
2020-08-05 14:40 PDT, Said Abou-Hallawa
no flags
Patch (34.14 KB, patch)
2020-08-05 14:51 PDT, Said Abou-Hallawa
no flags
Patch (34.12 KB, patch)
2020-08-05 15:05 PDT, Said Abou-Hallawa
no flags
Patch (34.13 KB, patch)
2020-08-05 15:32 PDT, Said Abou-Hallawa
no flags
Patch (45.14 KB, patch)
2020-08-06 18:03 PDT, Said Abou-Hallawa
no flags
Patch (50.30 KB, patch)
2020-08-07 17:30 PDT, Said Abou-Hallawa
no flags
Patch (50.39 KB, patch)
2020-08-09 15:06 PDT, Said Abou-Hallawa
no flags
Radar WebKit Bug Importer
Comment 1 2020-05-28 13:56:10 PDT
Said Abou-Hallawa
Comment 2 2020-06-21 15:47:52 PDT
Said Abou-Hallawa
Comment 3 2020-08-05 14:40:50 PDT
Created attachment 406041 [details] Patch WIP patch
Said Abou-Hallawa
Comment 4 2020-08-05 14:42:31 PDT
This patch is mostly working. It still needs some clean-up and maybe threading.
Said Abou-Hallawa
Comment 5 2020-08-05 14:51:36 PDT
Said Abou-Hallawa
Comment 6 2020-08-05 15:05:00 PDT
Said Abou-Hallawa
Comment 7 2020-08-05 15:32:19 PDT
Said Abou-Hallawa
Comment 8 2020-08-06 18:03:37 PDT
Said Abou-Hallawa
Comment 9 2020-08-06 18:07:02 PDT
Layout test were added.
Said Abou-Hallawa
Comment 10 2020-08-07 17:30:12 PDT
Darin Adler
Comment 11 2020-08-08 11:25:27 PDT
Comment on attachment 406235 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=406235&action=review > Source/WebCore/html/FileInputType.cpp:504 > + sharedImageTranscodingQueue()->dispatch([this, protectedThis = makeRef(*this), paths = paths.isolatedCopy(), transcodingPaths = transcodingPaths.isolatedCopy(), transcodingUTI = transcodingUTI.isolatedCopy(), transcodingExtension = transcodingExtension.isolatedCopy()]() mutable { Not 100% sure about the efficiency/thread-safety here. With protectedThis seems like we are carefully passing this in a way that does not require a thread-safe reference count. Perhaps we could use the same approach with "paths" that we use with protectedThis, and not make an isolated copy, since it’s only going to be used back on the main thread. I think that means that here we would write "paths" and below we would write paths = WTFMove(paths) and it would be safe for the same reason that protectedThis is safe. Alternatively we could change InputType to use ThreadSafeRefCounted, to make this more obviously thread safe. Maybe another way to write this that’s more obviously safe would be to create another inner lambda, one that takes a replacementPaths argument, as a local variable and capture *that* in the the outer lambda. Then we would not need to capture "this", "protectedThis", or "paths" in the outer lambda: auto callFilesChosen = [protectedThis = makeRef(this), paths] (const Vector<String>& replacementPaths) { protectedThis->filesChosen(paths, replacementPaths); }; sharedImageTranscodingQueue()->dispatch([callFilesChosen = WTFMove(callFilesChosen), transcodingPaths = transcodingPaths.isolatedCopy(), transcodingUTI = transcodingUTI.isolatedCopy(), transcodingExtension = transcodingExtension.isolatedCopy()]() mutable { ASSERT(!RunLoop::isMain()); auto replacementPaths = transcodeImages(transcodingPaths, transcodingUTI, transcodingExtension); ASSERT(transcodingPaths.size() == replacementPaths.size()); RunLoop::main().dispatch([callFilesChosen = WTFMove(callFilesChosen), replacementPaths = replacementPaths.isolatedCopy()]() { callFilesChosen(replacementPaths); }); }); I think the thread safety is easier to understand in that version. > Source/WebCore/platform/graphics/ImageUtilities.h:30 > +WEBCORE_EXPORT Ref<WorkQueue> sharedImageTranscodingQueue(); I suggest this return WorkQueue& instead of Ref<WorkQueue> since the queue in question is global and immortal. No reason to return a newly protected pointer each time.
Said Abou-Hallawa
Comment 12 2020-08-09 15:06:08 PDT
Said Abou-Hallawa
Comment 13 2020-08-09 21:44:45 PDT
Comment on attachment 406235 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=406235&action=review >> Source/WebCore/html/FileInputType.cpp:504 >> + sharedImageTranscodingQueue()->dispatch([this, protectedThis = makeRef(*this), paths = paths.isolatedCopy(), transcodingPaths = transcodingPaths.isolatedCopy(), transcodingUTI = transcodingUTI.isolatedCopy(), transcodingExtension = transcodingExtension.isolatedCopy()]() mutable { > > Not 100% sure about the efficiency/thread-safety here. > > With protectedThis seems like we are carefully passing this in a way that does not require a thread-safe reference count. Perhaps we could use the same approach with "paths" that we use with protectedThis, and not make an isolated copy, since it’s only going to be used back on the main thread. I think that means that here we would write "paths" and below we would write paths = WTFMove(paths) and it would be safe for the same reason that protectedThis is safe. > > Alternatively we could change InputType to use ThreadSafeRefCounted, to make this more obviously thread safe. > > Maybe another way to write this that’s more obviously safe would be to create another inner lambda, one that takes a replacementPaths argument, as a local variable and capture *that* in the the outer lambda. Then we would not need to capture "this", "protectedThis", or "paths" in the outer lambda: > > auto callFilesChosen = [protectedThis = makeRef(this), paths] (const Vector<String>& replacementPaths) { > protectedThis->filesChosen(paths, replacementPaths); > }; > sharedImageTranscodingQueue()->dispatch([callFilesChosen = WTFMove(callFilesChosen), transcodingPaths = transcodingPaths.isolatedCopy(), transcodingUTI = transcodingUTI.isolatedCopy(), transcodingExtension = transcodingExtension.isolatedCopy()]() mutable { > ASSERT(!RunLoop::isMain()); > auto replacementPaths = transcodeImages(transcodingPaths, transcodingUTI, transcodingExtension); > ASSERT(transcodingPaths.size() == replacementPaths.size()); > RunLoop::main().dispatch([callFilesChosen = WTFMove(callFilesChosen), replacementPaths = replacementPaths.isolatedCopy()]() { > callFilesChosen(replacementPaths); > }); > }); > > I think the thread safety is easier to understand in that version. This is neat. I have just realized that lambda captures its parameters when it's defined not when it is called. Using this solution, we do not have to capture *this" twice: (1) from the main thread to the transcoding thread and (2) form the transcoding thread back to the main thread.
EWS
Comment 14 2020-08-09 22:12:40 PDT
Committed r265422: <https://trac.webkit.org/changeset/265422> All reviewed patches have been landed. Closing bug and clearing flags on attachment 406273 [details].
Note You need to log in before you can comment on or make changes to this bug.