Certain webfonts freeze firefox when Stroke enabled

RESOLVED FIXED in mozilla23

Status

()

Core
Graphics: Text
RESOLVED FIXED
5 years ago
5 years ago

People

(Reporter: Teemu Ikonen, Assigned: jfkthame)

Tracking

20 Branch
mozilla23
x86
Mac OS X
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(3 attachments, 1 obsolete attachment)

(Reporter)

Description

5 years ago
Created attachment 743112 [details]
bug.html demonstrates the bug

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:20.0) Gecko/20100101 Firefox/20.0
Build ID: 20130326150557

Steps to reproduce:

Open attached file in Firefox. This file strokes and fills text to both offscreen and onscreen canvas for testing purposes. Finally it writes elapsed time in milliseconds onscreen.



Actual results:

Firefox freezes for about ~20 seconds until showing up the page.
Note: I've tested this only on OS/X 10.8.3.


Expected results:

Firefox should have rendered the page quickly (<100ms). Chrome takes ~20ms to render this file. 
If I change the font to 'Germania One' (bug.html line 36) it's pretty fast so this might have something to do with the Skranji Webfont.
It does not seem to make difference if Skranji is loaded via link or is already installed locally from ttf file.
(Reporter)

Updated

5 years ago
Summary: Certain webfonts freeze firefox with Stroke enabled → Certain webfonts freeze firefox when Stroke enabled

Comment 1

5 years ago
Are you able to test in the latest nightly build from http://nightly.mozilla.org to see how much the fix for bug 699331 affects this?
Possible duplicate of bug 864445
Component: Untriaged → Graphics: Text
Product: Firefox → Core
(Reporter)

Comment 2

5 years ago
Created attachment 743126 [details]
bug.html with stroke commented out
(Reporter)

Comment 3

5 years ago
Running bug.html in nightly build has no improvement. This appears to be related to using font stroke when drawing to canvas. Added bug-nostroke.html that has stroke styles commented out, it renders very quickly.
(Assignee)

Updated

5 years ago
Attachment #743112 - Attachment mime type: text/plain → text/html
(Assignee)

Updated

5 years ago
Attachment #743126 - Attachment mime type: text/plain → text/html
(Assignee)

Comment 4

5 years ago
(In reply to Mardeg from comment #1)
> Are you able to test in the latest nightly build from
> http://nightly.mozilla.org to see how much the fix for bug 699331 affects
> this?
> Possible duplicate of bug 864445

Those bugs aren't relevant here; this is specifically about poor performance when stroking fonts to canvas.
(Assignee)

Comment 5

5 years ago
On OS X 10.7, I'm getting timings of around 225ms for the first testcase, and about 55ms for the second, with the stroke commented out. So the stroke operation is certainly slowish here, but nowhere near as bad as the ~20s reported in comment #0.
(Assignee)

Comment 6

5 years ago
Ah, ignore those timings - I wasn't getting the expected webfont, due to mixed-content blocking when loading from bugzilla. After disabling that, so that the font actually loads, I see timings in the same ballpark as Teemu's. That seems pretty bad.
Status: UNCONFIRMED → NEW
Ever confirmed: true
(Assignee)

Comment 7

5 years ago
The reason for the slowness is no doubt the fact that the Skranji font is a "grungy" face with highly irregular outlines that involve large numbers of points. E.g. the "O" glyph has close to 600 points making up its outline - compared to a couple of dozen in a more "normal" design.

So perhaps this indicates poor performance (do we have an O(n^2) algorithm somewhere?) when stroking a path with a large number of segments.
(Assignee)

Comment 8

5 years ago
According to Instruments, the time is virtually all spent in CGContextDrawPath. So is that a particularly poor API, or is there something wrong about how we're using it?
(Assignee)

Comment 9

5 years ago
Created attachment 743232 [details] [diff] [review]
experimental patch - stroke glyphs individually instead of entire run as a single path
(Assignee)

Updated

5 years ago
Assignee: nobody → jfkthame
(Assignee)

Comment 10

5 years ago
It seems that CGContextDrawPath (or CGContextStrokePath, which is what we're actually calling, but presumably that's just a wrapper) performs really badly when the path contains a very large number of elements.

The code in CanvasRenderingContext2D currently gathers the outlines of all the glyphs in a text run into a single path, and then strokes that. This results in pathologically poor performance on OS X if there are many glyphs in the run, and/or the glyphs have particularly complex outlines, as in this example.

Modifying CanvasRenderingContext2D to stroke the glyph outlines individually instead of accumulating them into a single large path reduces the time taken by this testcase from over 18 seconds to about 3.2s on my machine. That's still not very good, but it's a lot better than it was!

I don't know whether such a change would be a positive or negative thing for other platforms, but at least for the CG backend on OS X, it seems worth considering.
(Assignee)

Comment 11

5 years ago
Comment on attachment 743232 [details] [diff] [review]
experimental patch - stroke glyphs individually instead of entire run as a single path

Bas, is it at all reasonable to do this, or is it liable to cause problems in more complex examples, or to perform worse on other platforms?
Attachment #743232 - Flags: feedback?(bas)
(Assignee)

Comment 12

5 years ago
Created attachment 743587 [details] [diff] [review]
stroke glyphs individually instead of entire run as a single path

Slightly modified, as the original patch caused crashes on Windows and Linux. This version seems to work fine, according to tryserver (https://tbpl.mozilla.org/?tree=Try&rev=3b1d713082d2). It improves perf of the testcase here on all of OS X (before: 18s; after: 3.2s), Win7/D2D (before: 3.2s; after: 2.7s), Win7/GDI (before: 1.7s; after: 1.0s) and Linux/cairo (before: 30s; after: 18s) in my local testing, suggesting that stroking extremely long/complex paths is not very performant on any of these backends, though OS X (CoreGraphics) shows the most extreme problem.
Attachment #743587 - Flags: review?(bas)
(Assignee)

Updated

5 years ago
Attachment #743232 - Attachment is obsolete: true
Attachment #743232 - Flags: feedback?(bas)
(Assignee)

Updated

5 years ago
Attachment #743587 - Attachment description: experimental patch - stroke glyphs individually instead of entire run as a single path → stroke glyphs individually instead of entire run as a single path
(Assignee)

Comment 13

5 years ago
Incidentally, note that the glyph-stroking testcase here performs significantly worse in general (both with and without this patch) on Win7/D2D than it does on Win7/GDI (i.e. with hardware acceleration disabled in Options). Can we do something about that?
(In reply to Jonathan Kew (:jfkthame) from comment #13)
> Incidentally, note that the glyph-stroking testcase here performs
> significantly worse in general (both with and without this patch) on
> Win7/D2D than it does on Win7/GDI (i.e. with hardware acceleration disabled
> in Options). Can we do something about that?

Possibly, possibly not, it's hard to say. D2D doesn't seem to be too great at strking but there might be things we can do.
Comment on attachment 743587 [details] [diff] [review]
stroke glyphs individually instead of entire run as a single path

Review of attachment 743587 [details] [diff] [review]:
-----------------------------------------------------------------

This seems like it's probably not a bad idea in general.
Attachment #743587 - Flags: review?(bas) → review+
https://hg.mozilla.org/mozilla-central/rev/9bc277eb0698
Status: NEW → RESOLVED
Last Resolved: 5 years ago
Resolution: --- → FIXED

Comment 18

5 years ago
(In reply to Jonathan Kew (:jfkthame) from comment #10)
> Modifying CanvasRenderingContext2D to stroke the glyph outlines individually
> instead of accumulating them into a single large path reduces the time taken
> by this testcase from over 18 seconds to about 3.2s on my machine.

But what about Arabic and other connected scripts, are they affected by this change?
(Assignee)

Comment 19

5 years ago
(In reply to Khaled Hosny from comment #18)
> (In reply to Jonathan Kew (:jfkthame) from comment #10)
> > Modifying CanvasRenderingContext2D to stroke the glyph outlines individually
> > instead of accumulating them into a single large path reduces the time taken
> > by this testcase from over 18 seconds to about 3.2s on my machine.
> 
> But what about Arabic and other connected scripts, are they affected by this
> change?

I don't believe so. The text is still shaped in exactly the same way. The end result should be that the same path - i.e. the outlines of all the glyphs in the run - will be stroked; it's just done in separate calls to the rendering back-end, rather than all the glyph outlines being collected into a single huge path (with many disconnected subpaths, at least one per glyph).

Stroking Arabic is rarely a good idea, anyhow, because the "joins" between the glyphs will show up, as they're part of the glyph outline. This patch won't change that. If you do want to "outline" Arabic-script text, it's probably best to draw the text with a stroke first, and then overprint it with the same text filled with white (or the background color), so as to "erase" the stroke across the glyph joins.

Comment 20

5 years ago
(In reply to Jonathan Kew (:jfkthame) from comment #19)
> Stroking Arabic is rarely a good idea, anyhow, because the "joins" between
> the glyphs will show up, as they're part of the glyph outline.

I was worried about this, since trying the attached file with Arabic text showed no visible joints in Firefox 20, but I just finished building mozilla-centeral and the joints are not visible either, so all good.
You need to log in before you can comment on or make changes to this bug.