Bug 225853

Summary: HTMLCanvasElement toDataURL and toBlob do unnecessary data copies through a CFDataRef
Product: WebKit Reporter: Sam Weinig <sam>
Component: New BugsAssignee: Sam Weinig <sam>
Status: RESOLVED FIXED    
Severity: Normal CC: beidson, benjamin, cdumez, cmarcelo, darin, ews-watchlist, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Patch
none
Patch
ews-feeder: commit-queue-
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Sam Weinig
Reported 2021-05-16 08:59:57 PDT
HTMLCanvasElement toDataURL and toBlob do unnecessary data copies through a CFDataRef
Attachments
Patch (20.90 KB, patch)
2021-05-16 09:13 PDT, Sam Weinig
no flags
Patch (21.05 KB, patch)
2021-05-16 11:02 PDT, Sam Weinig
no flags
Patch (37.12 KB, patch)
2021-05-16 15:27 PDT, Sam Weinig
ews-feeder: commit-queue-
Patch (37.12 KB, patch)
2021-05-16 16:32 PDT, Sam Weinig
no flags
Patch (37.31 KB, patch)
2021-05-16 19:26 PDT, Sam Weinig
no flags
Patch (37.24 KB, patch)
2021-05-17 09:10 PDT, Sam Weinig
no flags
Patch (37.48 KB, patch)
2021-05-18 07:05 PDT, Sam Weinig
no flags
Patch (22.82 KB, patch)
2021-05-19 12:00 PDT, Sam Weinig
no flags
Sam Weinig
Comment 1 2021-05-16 09:13:11 PDT Comment hidden (obsolete)
Sam Weinig
Comment 2 2021-05-16 11:02:55 PDT Comment hidden (obsolete)
Sam Weinig
Comment 3 2021-05-16 15:27:37 PDT Comment hidden (obsolete)
Sam Weinig
Comment 4 2021-05-16 16:32:31 PDT Comment hidden (obsolete)
Sam Weinig
Comment 5 2021-05-16 19:26:52 PDT Comment hidden (obsolete)
Sam Weinig
Comment 6 2021-05-17 09:10:07 PDT
Sam Weinig
Comment 7 2021-05-17 09:59:03 PDT
Ok, ready for review now.
Darin Adler
Comment 8 2021-05-17 18:22:14 PDT
Comment on attachment 428835 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=428835&action=review > Source/WTF/wtf/text/Base64.cpp:94 > +template<typename CharacterType> static inline void base64EncodeInternal(const unsigned char* inputDataBuffer, unsigned inputLength, CharacterType* destinationDataBuffer, unsigned destinationLength, Base64EncodePolicy policy) Maybe we should be using uint8_t instead of unsigned char? > Source/WTF/wtf/text/Base64.cpp:143 > +static inline void base64EncodeInternal(const unsigned char* inputDataBuffer, unsigned inputLength, Vector<char>& destinationVector, Base64EncodePolicy policy) Can this use a return value instead of an out vector? > Source/WTF/wtf/text/Base64.h:52 > +static constexpr unsigned maximumBase64EncoderInputBufferSize = UINT_MAX / 77 * 76 / 4 * 3 - 2; std::numeric_limits instead of UINT_MAX? Comment should explain the nature of the conservative estimate. > Source/WTF/wtf/text/Base64.h:153 > +WTF_EXPORT_PRIVATE void base64Encode(const void*, unsigned, Vector<char>&, Base64EncodePolicy = Base64DoNotInsertLFs); Can we change this to product a return value instead of taking an out argument? > Source/WTF/wtf/text/Base64.h:159 > +void base64Encode(ConstSignedOrUnsignedCharVectorAdapter, Vector<char>&, Base64EncodePolicy = Base64DoNotInsertLFs); > +void base64Encode(const CString&, Vector<char>&, Base64EncodePolicy = Base64DoNotInsertLFs); Can we change this to product a return value instead of taking an out argument? > Source/WTF/wtf/text/Base64.h:252 > + if (result > 76) > + return result + ((result - 1) / 76); Can we name the 76 constant? Why the if statement? Seems like values in the 1-76 range would still yield the correct result. I would drop one set of parentheses here. > Source/WebCore/ChangeLog:49 > + Replace encodeImage(), which use a filled in a CFMutableDataRef with overloads > + of data and dataURL that now use a callback based CGDataConsumer and some callback > + functors to allow the encoded data to be consumed as it is being created. Some grammar problems in this sentence. "which use a", and not enough commas. > Source/WebCore/platform/graphics/cg/ImageBufferCGBackend.cpp:203 > + auto image = nativeImage->platformImage(); > + return createCroppedImageIfNecessary(image.get(), backendSize()); Better without the local? > Source/WebCore/platform/graphics/cg/ImageBufferCGBackend.h:58 > - virtual RetainPtr<CFDataRef> toCFData(const String& mimeType, Optional<double> quality, PreserveResolution) const; > + > + virtual PlatformImagePtr copyPlatformImageForEncoding(CFStringRef destinationUTI, PreserveResolution) const; Is this really an improvement? I’m not sure we need to use the typedef name when this is not platform-independent code.
Sam Weinig
Comment 9 2021-05-17 19:58:42 PDT
(In reply to Darin Adler from comment #8) > Comment on attachment 428835 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=428835&action=review > > > Source/WTF/wtf/text/Base64.cpp:94 > > +template<typename CharacterType> static inline void base64EncodeInternal(const unsigned char* inputDataBuffer, unsigned inputLength, CharacterType* destinationDataBuffer, unsigned destinationLength, Base64EncodePolicy policy) > > Maybe we should be using uint8_t instead of unsigned char? Sounds good. > > > Source/WTF/wtf/text/Base64.cpp:143 > > +static inline void base64EncodeInternal(const unsigned char* inputDataBuffer, unsigned inputLength, Vector<char>& destinationVector, Base64EncodePolicy policy) > > Can this use a return value instead of an out vector? There are still some places that are passing one in, but I plan to resolve those soon. > > > Source/WTF/wtf/text/Base64.h:52 > > +static constexpr unsigned maximumBase64EncoderInputBufferSize = UINT_MAX / 77 * 76 / 4 * 3 - 2; > > std::numeric_limits instead of UINT_MAX? Comment should explain the nature > of the conservative estimate. Will change to std::numeric_limits. I will do some digging, but the reason may be lost to time. I was just moving the comment along. > > > Source/WTF/wtf/text/Base64.h:153 > > +WTF_EXPORT_PRIVATE void base64Encode(const void*, unsigned, Vector<char>&, Base64EncodePolicy = Base64DoNotInsertLFs); > > Can we change this to product a return value instead of taking an out > argument? Yep, planning on it, just not in this round. > > > Source/WTF/wtf/text/Base64.h:252 > > + if (result > 76) > > + return result + ((result - 1) / 76); > > Can we name the 76 constant? Will do. > > Why the if statement? Seems like values in the 1-76 range would still yield > the correct result. I think you are right. I was moving it from the encode function and didn't think it through. > > I would drop one set of parentheses here. But which one? :). > > > Source/WebCore/ChangeLog:49 > > + Replace encodeImage(), which use a filled in a CFMutableDataRef with overloads > > + of data and dataURL that now use a callback based CGDataConsumer and some callback > > + functors to allow the encoded data to be consumed as it is being created. > > Some grammar problems in this sentence. "which use a", and not enough commas. Fixed. > > > Source/WebCore/platform/graphics/cg/ImageBufferCGBackend.cpp:203 > > + auto image = nativeImage->platformImage(); > > + return createCroppedImageIfNecessary(image.get(), backendSize()); > > Better without the local? Yeah. Fixed. > > > Source/WebCore/platform/graphics/cg/ImageBufferCGBackend.h:58 > > - virtual RetainPtr<CFDataRef> toCFData(const String& mimeType, Optional<double> quality, PreserveResolution) const; > > + > > + virtual PlatformImagePtr copyPlatformImageForEncoding(CFStringRef destinationUTI, PreserveResolution) const; > > Is this really an improvement? I’m not sure we need to use the typedef name > when this is not platform-independent code. Which part of it are you concerned isn't an improvement? I agree making the function return a RetainPtr<CGImageRef> and calling it something like createCGImageForEncoding() would be even better and will do that.
Darin Adler
Comment 10 2021-05-17 23:20:57 PDT
Comment on attachment 428835 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=428835&action=review >>> Source/WTF/wtf/text/Base64.cpp:143 >>> +static inline void base64EncodeInternal(const unsigned char* inputDataBuffer, unsigned inputLength, Vector<char>& destinationVector, Base64EncodePolicy policy) >> >> Can this use a return value instead of an out vector? > > There are still some places that are passing one in, but I plan to resolve those soon. The places that are passing one in can just assign it to the result, so I see no reason to wait.
Darin Adler
Comment 11 2021-05-17 23:22:42 PDT
Comment on attachment 428835 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=428835&action=review >>> Source/WebCore/platform/graphics/cg/ImageBufferCGBackend.h:58 >>> + virtual PlatformImagePtr copyPlatformImageForEncoding(CFStringRef destinationUTI, PreserveResolution) const; >> >> Is this really an improvement? I’m not sure we need to use the typedef name when this is not platform-independent code. > > Which part of it are you concerned isn't an improvement? I agree making the function return a RetainPtr<CGImageRef> and calling it something like createCGImageForEncoding() would be even better and will do that. If PlatformImagePtr exists so we can write platform-independent code that manipulates an image pointer, I still suggest calling it RetainPtr<CGImageRef> in CoreGraphics-platform-only code. I don’t think the typedef is an abstraction. But your idea is even better because this virtual function is platform-specific!
Sam Weinig
Comment 12 2021-05-18 07:05:59 PDT
Sam Weinig
Comment 13 2021-05-18 08:17:37 PDT
(In reply to Darin Adler from comment #10) > Comment on attachment 428835 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=428835&action=review > > >>> Source/WTF/wtf/text/Base64.cpp:143 > >>> +static inline void base64EncodeInternal(const unsigned char* inputDataBuffer, unsigned inputLength, Vector<char>& destinationVector, Base64EncodePolicy policy) > >> > >> Can this use a return value instead of an out vector? > > > > There are still some places that are passing one in, but I plan to resolve those soon. > > The places that are passing one in can just assign it to the result, so I > see no reason to wait. Fair enough. To do this, I am going to somehow differentiate the base64Encode() that returns a String and the one that returns a Vector<char>. Do you have a naming preference here? I was thinking of just using base64EncodeToString() and base64EncodeToVector(). I could also do base64Encode<String>() and base64Encode<Vector<char>>()?
Sam Weinig
Comment 14 2021-05-18 08:23:20 PDT
(In reply to Sam Weinig from comment #13) > (In reply to Darin Adler from comment #10) > > Comment on attachment 428835 [details] > > Patch > > > > View in context: > > https://bugs.webkit.org/attachment.cgi?id=428835&action=review > > > > >>> Source/WTF/wtf/text/Base64.cpp:143 > > >>> +static inline void base64EncodeInternal(const unsigned char* inputDataBuffer, unsigned inputLength, Vector<char>& destinationVector, Base64EncodePolicy policy) > > >> > > >> Can this use a return value instead of an out vector? > > > > > > There are still some places that are passing one in, but I plan to resolve those soon. > > > > The places that are passing one in can just assign it to the result, so I > > see no reason to wait. > > Fair enough. > > To do this, I am going to somehow differentiate the base64Encode() that > returns a String and the one that returns a Vector<char>. Do you have a > naming preference here? > I was thinking of just using base64EncodeToString() and > base64EncodeToVector(). I could also do base64Encode<String>() and > base64Encode<Vector<char>>()? Or, I could make base64Encode() always return a Vector<char> and use makeString(base64Encoded()) for the string cases. That might be nicer
Sam Weinig
Comment 15 2021-05-18 09:03:13 PDT
I decided that I should do the base64 changes first, and then land this part as they are quite disconnected. Doing the base64 bit in https://bugs.webkit.org/show_bug.cgi?id=225920.
Sam Weinig
Comment 16 2021-05-19 12:00:13 PDT
EWS
Comment 17 2021-05-19 14:19:04 PDT
Committed r277751 (237921@main): <https://commits.webkit.org/237921@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 429082 [details].
Radar WebKit Bug Importer
Comment 18 2021-05-19 14:20:19 PDT
Note You need to log in before you can comment on or make changes to this bug.