RESOLVED FIXED Bug 35486
canvas fillText with @font-face crashes
https://bugs.webkit.org/show_bug.cgi?id=35486
Summary canvas fillText with @font-face crashes
Philip Taylor
Reported 2010-02-27 14:04:09 PST
The linked test case crashes randomly when loading (most of the time, but not always), in nightly WebKit on Windows and in Chromium on Linux. It loads a font with @font-face, and doesn't use the font in the page itself, but tries drawing with it in onload onto the canvas (which won't work because it hasn't got around to downloading the font yet); and then it draws in the canvas again, after a time delay, at which point it usually crashes.
Attachments
Proposed patch (1.94 KB, patch)
2010-06-25 04:40 PDT, Robin Cao
no flags
Updated patch (4.36 KB, patch)
2010-06-27 20:20 PDT, Robin Cao
no flags
Jakob Petsovits
Comment 1 2010-06-15 11:56:23 PDT
The issue is that the SimpleFontData object is deleted by CSSFontFaceSource::fontLoaded() - called from CachedFont::checkNotify(), CachedFont::data(), and that one from Loader::Host::didFinishLoading(). When CanvasRenderingContext2D::drawTextInternal() accesses the font the second time, after loading has finished, the Font's cached SimpleFontData is a corrupt pointer and (mostly) crashes when trying to draw. Still trying to understand why the font has to be deleted...
Jakob Petsovits
Comment 2 2010-06-24 13:40:02 PDT
Alright, so just to conclude my previous comment, or rephrase it in a better way... When the font is first accessed, it hasn't been loaded yet; it does not yet exist in the font cache or anywhere. Instead, CSSFontFaceSource::getFontData() kicks off loading and, as an interim solution, creates a copy of a system font (likely the last-resort fallback font, but there might be a more suitable one). When the font is fully loaded, these interim objects will be deleted so that on next access, the actually desired font will be generated from the downloaded data when it's accessed by CSSFontFaceSource::getFontData() the next time. By deleting the interim SimpleFontData objects though, CSSFontFaceSource::pruneTable() pulls the foundations from existing Font objects like the one in CanvasRenderingContext2D. Apparently the SimpleFontData objects are not expected to last that long in the RenderTree, which might well be the case, only the CanvasRenderingContext2D is not part of the RenderTree so I guess that doesn't apply here. Anyways, I can't see a straightforward fix right now.
Robin Cao
Comment 3 2010-06-24 20:09:45 PDT
This issue is a little tricky. Normally we get font objects from RenderStyle, and font objects get updated automatically after calling recalcStyle. But the font object in CanvasRenderingContext2D seems to be an exception, so it may become invalid at some point. We can override recalcStyle() in HTMLCanvasElement, and update the font object from there if needed. The patch will look like this: Index: WebCore/html/HTMLCanvasElement.h =================================================================== + virtual void recalcStyle(StyleChange); Index: WebCore/html/HTMLCanvasElement.cpp +void HTMLCanvasElement::recalcStyle(StyleChange change) +{ + HTMLElement::recalcStyle(change); + + // Update font if needed. + if (change == Force && m_context && m_context->is2d()) { + CanvasRenderingContext2D* ctx = static_cast<CanvasRenderingContext2D*>(m_context.get()); + ctx->setFont(ctx->font()); + } +} Jakob, do you think this is a viable solution?
Jakob Petsovits
Comment 4 2010-06-25 01:12:10 PDT
Awesome, I think that's the solution we're looking for, yes. I can't currently look it up (posting only from my phone), but do other contexts have font properties too? In that case, we should update those as well.
Robin Cao
Comment 5 2010-06-25 01:54:51 PDT
Only CanvasRenderingContext2D has font properties. I will upload a patch later.
Robin Cao
Comment 6 2010-06-25 04:40:07 PDT
Created attachment 59757 [details] Proposed patch
David Levin
Comment 7 2010-06-25 08:11:19 PDT
Layout test?
Jakob Petsovits
Comment 8 2010-06-25 08:35:50 PDT
The Philip canvas tests are already in WebKit, this bug concerns canvas/philip/tests/2d.text.draw.fontface.repeat.html.
mitz
Comment 9 2010-06-27 09:09:52 PDT
Comment on attachment 59757 [details] Proposed patch The patch looks correct to me, but rather than calling setFont(), could you just reset the m_realizedFont member of the state? Alternatively, could you just call a method that calls Font::update() rather than involving the CSS parser and style selector?
Robin Cao
Comment 10 2010-06-27 20:20:14 PDT
Created attachment 59870 [details] Updated patch Update the patch according to mitz's comment.
mitz
Comment 11 2010-06-27 20:27:00 PDT
(In reply to comment #8) > The Philip canvas tests are already in WebKit, this bug concerns canvas/philip/tests/2d.text.draw.fontface.repeat.html. I am not sure what this comment means. Does the test fail without this patch and pass with it? If so, new results need to be included in the patch. If not, the question from comment #7 stands: can you make a regression test for this bug? The code change itself looks good.
Jakob Petsovits
Comment 12 2010-06-27 22:00:31 PDT
Yes, the test crashes without the patch. Didn't test out the fix yet; if it does solve the problem as I believe it does, the crash is avoided afterwards.
Robin Cao
Comment 13 2010-06-27 22:35:08 PDT
(In reply to comment #12) > Yes, the test crashes without the patch. Didn't test out the fix yet; if it does solve the problem as I believe it does, the crash is avoided afterwards. The patch fixes the crash, i have verified that. The test result need not be updated, as the patch does not affect test output.
WebKit Commit Bot
Comment 14 2010-06-28 10:00:49 PDT
Comment on attachment 59870 [details] Updated patch Clearing flags on attachment: 59870 Committed r62016: <http://trac.webkit.org/changeset/62016>
WebKit Commit Bot
Comment 15 2010-06-28 10:00:54 PDT
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.