Repository navigation
[font] cache the un-compressed SVG document and its viewBox - #294
Conversation
benoitkugler
left a comment
There was a problem hiding this comment.
Nice change !
I have a minor suggestion, but this looks good overall (pending merge conflicts resolution).
| ) | ||
|
|
||
| type svg []svgDocument | ||
| type svg []*svgDocument |
There was a problem hiding this comment.
Can we avoid pointer indirection here ? Since svg is a slice, its elements are adressable anyway right ?
There was a problem hiding this comment.
The reason it was using a pointer was due to sync.Once; which usually expects to be attached to a pointer struct. Otherwise when the slice is appended and items copied, it could break. Here it's safe to use, because the slice is built only once.
The alternative would be to have the resolved data as atomic.Pointer and then just have rarely two goroutines race to write it.
Anyways, changed it to []svgDocument for now.
Every GlyphDataSVG call gunzipped the shared document again and ran an xml.Decoder over it to find the viewBox. Each svgDocument now resolves both once, under a sync.Once because the table lives on the Font, which many goroutines share. resolve only gunzips a document that starts with the gzip magic bytes, and rejects one whose stream is truncated or fails its checksum. For a rejected document glyphData returns false instead of the raw bytes. GlyphSVG.Source is documented as read-only, since every glyph of a document now shares it. TestSVGResolveConcurrent covers plain, gzipped and corrupt documents resolved from several goroutines at once. BenchmarkGlyphDataSVG (Apple M4 Max, count=6): old: 1885ns ± 7% 2488B/op 26 allocs/op new: 108ns ± 3% 416B/op 4 allocs/op -94.3% time
b2a3c02 to
cda92ee
Compare
benoitkugler
left a comment
There was a problem hiding this comment.
Nice optimization, thank you !
Every GlyphDataSVG call gunzipped the shared document again and ran an
xml.Decoder over it to find the viewBox. Each svgDocument now resolves
both once, under a sync.Once because the table lives on the Font, which
many goroutines share.
resolve only gunzips a document that starts with the gzip magic bytes,
and rejects one whose stream is truncated or fails its checksum. For a
rejected document glyphData returns false instead of the raw bytes.
GlyphSVG.Source is documented as read-only, since every glyph of a
document now shares it. TestSVGResolveConcurrent covers plain, gzipped
and corrupt documents resolved from several goroutines at once.
BenchmarkGlyphDataSVG (Apple M4 Max, count=6):
old: 1885ns ± 7% 2488B/op 26 allocs/op
new: 108ns ± 3% 416B/op 4 allocs/op -94.3% time