RESOLVED FIXED Bug 224277
Refactor font loading to make it possible for Worker to implement it
https://bugs.webkit.org/show_bug.cgi?id=224277
Summary Refactor font loading to make it possible for Worker to implement it
Chris Lord
Reported 2021-04-07 03:50:38 PDT
To support FontFace in OffscreenCanvas correctly, custom font loading needs to be possible on a Worker. Currently, custom font loading is tied to CachedFont, CachedResourceLoader and Document. It would be good to abstract this somewhat to make it easier to provide an alternative implementation of the loading portion that can be used by a Worker. I detailed a plan for this in bug 224178 and have a patch incoming so we can begin testing/discussion/review.
Attachments
Patch (44.26 KB, patch)
2021-04-07 04:31 PDT, Chris Lord
ews-feeder: commit-queue-
Patch (44.44 KB, patch)
2021-04-07 04:49 PDT, Chris Lord
ews-feeder: commit-queue-
Patch (47.78 KB, patch)
2021-04-07 04:57 PDT, Chris Lord
ews-feeder: commit-queue-
Patch (48.65 KB, patch)
2021-04-07 05:06 PDT, Chris Lord
ews-feeder: commit-queue-
Patch (49.81 KB, patch)
2021-04-07 06:09 PDT, Chris Lord
no flags
Patch (50.45 KB, patch)
2021-04-07 10:40 PDT, Chris Lord
no flags
Patch (50.46 KB, patch)
2021-04-08 02:21 PDT, Chris Lord
no flags
Patch (50.67 KB, patch)
2021-04-08 04:50 PDT, Chris Lord
no flags
Patch (50.77 KB, patch)
2021-04-08 04:52 PDT, Chris Lord
no flags
Patch (61.83 KB, patch)
2021-04-09 05:00 PDT, Chris Lord
ews-feeder: commit-queue-
Patch (61.83 KB, patch)
2021-04-09 05:10 PDT, Chris Lord
no flags
Patch (61.75 KB, patch)
2021-04-12 01:06 PDT, Chris Lord
no flags
Chris Lord
Comment 1 2021-04-07 04:31:34 PDT
Chris Lord
Comment 2 2021-04-07 04:49:46 PDT
Chris Lord
Comment 3 2021-04-07 04:57:58 PDT
Chris Lord
Comment 4 2021-04-07 05:06:22 PDT
Chris Lord
Comment 5 2021-04-07 06:09:28 PDT
Chris Lord
Comment 6 2021-04-07 09:18:05 PDT
Comment on attachment 425389 [details] Patch Needs a slight refactor, I've done some bad things with references here...
Chris Lord
Comment 7 2021-04-07 10:40:59 PDT
Darin Adler
Comment 8 2021-04-07 13:15:11 PDT
Should fix those crashes before we review.
Chris Lord
Comment 9 2021-04-08 02:21:43 PDT
Chris Lord
Comment 10 2021-04-08 04:19:44 PDT
Fixed. I'd missed checking a result - took the opportunity to remove some unnecessary pointer use in the API.
Chris Lord
Comment 11 2021-04-08 04:50:03 PDT
Chris Lord
Comment 12 2021-04-08 04:52:33 PDT
Darin Adler
Comment 13 2021-04-08 08:49:01 PDT
Comment on attachment 425499 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=425499&action=review > Source/WebCore/css/CSSFontFaceSource.h:53 > + CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, CSSFontSelector&, std::unique_ptr<FontLoadRequest>&&); Since the argument can’t be null, consider using UniqueRef&& instead of unique_ptr&&. > Source/WebCore/css/CSSFontFaceSrcValue.h:70 > + std::unique_ptr<FontLoadRequest> fontLoadRequest(ScriptExecutionContext*, bool isSVG, bool isInitiatingElementInUserAgentShadowTree); Since this never returns nullptr, consider returning UniqueRef instead of unique_ptr. > Source/WebCore/dom/Document.cpp:646 > + , m_fontLoadingTimer(*this, &Document::fontLoadingTimerFired) This is unfortunate, bloating the already huge Document class even more by adding back font function and data members that were factored out into a separate object. Can we keep this code from CSSFontSelector in a separate object even if Document is the only client? > Source/WebCore/dom/ScriptExecutionContext.h:170 > + virtual std::unique_ptr<FontLoadRequest> fontLoadRequest(String& url, bool isSVG, bool isInitiatingElementInUserAgentShadowTree, LoadedFromOpaqueSource); A function like this that returns a heap alloca\ted object would normally be named createXXX. > Source/WebCore/loader/FontLoadRequest.h:41 > +class FontLoadRequestClient { Can we use a function for the font loaded call\back instead of a client class? Use WTF::CompletionHandler perhaps? We used to use classes for this but we have found we don’t need that in modern C++.
Chris Lord
Comment 14 2021-04-09 02:33:56 PDT
(In reply to Darin Adler from comment #13) > Comment on attachment 425499 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=425499&action=review > > > Source/WebCore/css/CSSFontFaceSource.h:53 > > + CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, CSSFontSelector&, std::unique_ptr<FontLoadRequest>&&); > > Since the argument can’t be null, consider using UniqueRef&& instead of > unique_ptr&&. Sounds good. > > Source/WebCore/css/CSSFontFaceSrcValue.h:70 > > + std::unique_ptr<FontLoadRequest> fontLoadRequest(ScriptExecutionContext*, bool isSVG, bool isInitiatingElementInUserAgentShadowTree); > > Since this never returns nullptr, consider returning UniqueRef instead of > unique_ptr. This can be null as Document::fontLoadRequest can return nullptr. > > Source/WebCore/dom/Document.cpp:646 > > + , m_fontLoadingTimer(*this, &Document::fontLoadingTimerFired) > > This is unfortunate, bloating the already huge Document class even more by > adding back font function and data members that were factored out into a > separate object. Can we keep this code from CSSFontSelector in a separate > object even if Document is the only client? I'll try factoring this out into DocumentFontLoader or something like that. > > Source/WebCore/dom/ScriptExecutionContext.h:170 > > + virtual std::unique_ptr<FontLoadRequest> fontLoadRequest(String& url, bool isSVG, bool isInitiatingElementInUserAgentShadowTree, LoadedFromOpaqueSource); > > A function like this that returns a heap alloca\ted object would normally be > named createXXX. > > > Source/WebCore/loader/FontLoadRequest.h:41 > > +class FontLoadRequestClient { > > Can we use a function for the font loaded call\back instead of a client > class? Use WTF::CompletionHandler perhaps? We used to use classes for this > but we have found we don’t need that in modern C++. Sure.
Chris Lord
Comment 15 2021-04-09 02:59:53 PDT
(In reply to Chris Lord from comment #14) > (In reply to Darin Adler from comment #13) > > Comment on attachment 425499 [details] > > > Source/WebCore/loader/FontLoadRequest.h:41 > > > +class FontLoadRequestClient { > > > > Can we use a function for the font loaded call\back instead of a client > > class? Use WTF::CompletionHandler perhaps? We used to use classes for this > > but we have found we don’t need that in modern C++. > > Sure. So looking at implementing this, it's tricky without just having another setCompletionHandler function, which seems against how CompletionHandler is generally used elsewhere. The issue is that FontLoadRequest isn't expected to start loading on creation and the actual begin-loading trigger is handled externally to the request, so there's no call for which you could add a CompletionHandler argument. Ideally, ScriptExecutionContext::beginLoadingFontSoon would have this argument, but this would then mean that Document (or DocumentFontLoader) would have to save a map of FontLoadRequest->CompletionHandler, which seems overkill compared to the current Client setup. I'm open to suggestions, but it seems to me the client setup is actually quite convenient in this particular case.
Chris Lord
Comment 16 2021-04-09 05:00:13 PDT
Chris Lord
Comment 17 2021-04-09 05:10:14 PDT
Darin Adler
Comment 18 2021-04-10 12:11:14 PDT
Comment on attachment 425613 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=425613&action=review > Source/WebCore/css/CSSFontFaceSource.cpp:240 > - return m_hasSVGFontFaceElement || is<CachedSVGFont>(m_font.get()); > + if (!m_hasSVGFontFaceElement || !is<CachedFontLoadRequest>(m_fontRequest.get())) > + return false; > + > + auto* cachedFontRequest = downcast<CachedFontLoadRequest>(m_fontRequest.get()); > + return is<CachedSVGFont>(cachedFontRequest->cachedFont()); I’d write it like this: return m_hasSVGFontFaceElement && is<CachedFontLoadRequest>(m_fontRequest.get()) && is<CachedSVGFont>(downcast<CachedFontLoadRequest>(*m_fontRequest).cachedFont()); For me this seems easier to follow than the if statement and the local variable, and also it’s slightly nicer to use reference instead of pointers once we have null-checked something. But also, when writing it like this, it becomes clear that the old logic used || and this new logic uses &&. Is this correct?
Chris Lord
Comment 19 2021-04-12 01:06:56 PDT
Chris Lord
Comment 20 2021-04-12 01:08:20 PDT
(In reply to Darin Adler from comment #18) > Comment on attachment 425613 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=425613&action=review > > > Source/WebCore/css/CSSFontFaceSource.cpp:240 > > - return m_hasSVGFontFaceElement || is<CachedSVGFont>(m_font.get()); > > + if (!m_hasSVGFontFaceElement || !is<CachedFontLoadRequest>(m_fontRequest.get())) > > + return false; > > + > > + auto* cachedFontRequest = downcast<CachedFontLoadRequest>(m_fontRequest.get()); > > + return is<CachedSVGFont>(cachedFontRequest->cachedFont()); > > I’d write it like this: > > return m_hasSVGFontFaceElement > && is<CachedFontLoadRequest>(m_fontRequest.get()) > && > is<CachedSVGFont>(downcast<CachedFontLoadRequest>(*m_fontRequest). > cachedFont()); > > For me this seems easier to follow than the if statement and the local > variable, and also it’s slightly nicer to use reference instead of pointers > once we have null-checked something. > > But also, when writing it like this, it becomes clear that the old logic > used || and this new logic uses &&. Is this correct? Well spotted, it isn't correct - fixed.
EWS
Comment 21 2021-04-12 02:26:49 PDT
Committed r275817 (236387@main): <https://commits.webkit.org/236387@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 425722 [details].
Radar WebKit Bug Importer
Comment 22 2021-04-12 02:27:20 PDT
Note You need to log in before you can comment on or make changes to this bug.