Conversation
02f55d3 to
62c028b
Compare
|
Yeah I think we first have to figure out how to deal with fontdb before doing anything with resvg. I don’t think RazrFalcon would want to switch it, and I’m not sure that fontique supports everything we need? |
|
It's an interesting experiment, but I don't see a point in it. Is there a reason in switching to PS: even if |
|
Oh wait, it depends on proc-macros/syn?! Burn it with fire! No proc-macros in |
harfrust is rustybuzz, just with ttf-parser switched out by read-fonts. It passes all the same tests, so it should be no less robust than then rustybuzz.
The reason is that going forward, (most likely) no one will be continually developing ttf-parser/rustybuzz, while harfrust will be actively maintained. |
|
I would suggest to come back to it in a year. No rush. And once again, proc-macros are no go. We have to figure out that one as well. |
Not sure about 'beta' type labels, but the first release (0.1.0) of HarfRust happened on June 10, marking a significant milestone.
For an immediate effect, it seems to be far more compliant when tested against the HarfBuzz test suite. To quote Chad:
And the HarfRust introduction post by Behdad contains the following claim:
Moving forward, HarfRust will receive active development and continuous sync with HarfBuzz, while RustyBuzz is likely to only see critical fixes. |
Apples and oranges, but sure. Either way, proc-macros is the current major roadblock. |
|
@RazrFalcon Seems like the proc-macros are coming from font-types which uses bytemuck and serde derive macros. Do we want to talk to them about converting to manual implementations? |
|
@mattfbacon if it's an easy fix - sure. |
|
No it wouldn't be at all, since the bytemuck derive macros generate unsafe code so they would need to allow unsafe code back into the codebase. But what is your plan here? Earlier you said wait, but for what? |
I would call it easy. It's not like the code deeply depends on proc-macros.
Adoption, etc. I don't see a point/reason in switching to 0.1. Especially if we would keep |
|
There are derive helpers based on It is likely possible to implement an alternative |
e29cfbe to
0973b97
Compare
harfrustharfrust and fontations
3c5c998 to
c05e2fd
Compare
As some months have passed another benefit has appeared - performance. In the last month the HarfRust vs HarfBuzz OpenType shaping performance difference has gone from ~4x to ~1.2x, which is a massive boost. Not quite on par with HarfBuzz yet, but getting a lot closer. More importantly for this PR here though, HarfRust is now a lot faster than RustyBuzz. |
|
The geometric mean of the last result is ~1.16, meaning Harfrust is now only 16% slower than Harfbuzz. |
It's even better than that. See the comment: In short, there's some hb-harfrust overhead included in the spreadsheet number. |
da2754d to
7e549e1
Compare
Skrifa's Matrix multiplication chains right-to-left (C = A * B applies B then A), so nested paint transforms must be pre-concatenated onto the current transform, matching the previous ttf-parser Transform::combine(self.transform, transform) behaviour and skrifa's own CollectFillGlyphPainter.
The single-glyph vs multi-glyph document heuristic was checking the first record in the SVG table instead of the record that actually contains the requested glyph, picking the wrong branch for fonts whose records differ (e.g. Noto Color Emoji).
Replace unwraps and direct slice indexing with graceful fallbacks: - palette lookups fall back to the foreground color instead of panicking on a missing/malformed CPAL table or an out-of-range palette index - clip glyph outlining returns early on a draw error, matching the old ttf-parser behaviour
CPAL color records for all palettes live in a single shared array; palette entry indices must be offset by the start index of the palette from color_record_indices rather than indexing the array directly. This is usually 0 for the first palette, but not guaranteed to be.
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Make font metrics variation-aware Resolve the requested font-variation-settings to a normalized location in load_font so that skrifa applies MVAR deltas to ascent, descent, x-height, underline and strikeout metrics, and so the manual subscript/superscript (SBYO/SPYO) delta handling actually runs. Metrics are cached per Font spec (which includes variations), so caching remains correct. Also drop the leftover commented-out ttf-parser code in outline(): with skrifa, the default (empty) location already resolves to the default value of every axis. Cache variable font outlines per variation set Previously any span with explicit variations (or auto optical sizing on a font with an opsz axis) bypassed the glyph outline cache entirely, re-extracting the outline for every glyph occurrence. Instead, compute the effective variation list (explicit settings plus auto opsz) once per glyph via a shared helper, include it in the cache key, and merge outline_with_variations into a single cached outline function. An empty variation list resolves to the default location, so non-variable fonts behave as before. Apply font variations to COLR color glyphs COLR glyphs were always painted at the default variation location, ignoring font-variation-settings. Resolve the effective variations to a normalized location and pass it to skrifa paint(), which resolves all COLR ItemVariationStore deltas (paint transforms, gradient stops, clip boxes). The GlyphPainter now also draws clip glyph outlines at the same location so the base outlines vary too. Color glyph trees are cached per variation set, like outlines.
Skrifa pairs push_clip_glyph with pop_clip (including via the default fill_glyph decomposition), but push_clip_glyph never opened an XML element while pop_clip unconditionally closed one. Each painted layer therefore closed an ancestor element, truncating the generated SVG and making Tree::from_data fail for color glyphs with more than a few layers. This went unnoticed because the Noto COLR test font also contains an SVG table, so rendering silently fell back to the SVG glyph path. push_clip_glyph now always opens a clip group with the glyph outline (an empty path when outlining fails), keeping pop_clip balanced. The colrv0/colrv1 snapshots change because COLR rendering now takes priority over the SVG table again; the output matches main.
ColorPalettes handles per-palette record offsets internally, so the manual color_record_indices base-offset handling is no longer needed.
Replaces the manual fvar table iteration in has_opsz_axis and the shaping auto-opsz check, and drops the harfrust FontRef usage from flatten.rs (skrifa and harfrust share the same underlying types).
The instance only exists to apply variation settings, so avoid the setup cost for non-variable text (the common case).
ttf-parser enforced 16..=16384 when parsing the head table; skrifa does not, so add the check to load_font to avoid nonsensical metrics from malformed fonts.
skrifa reports metrics as f32; round when converting to the integer font units used by ResolvedFont rather than truncating toward zero, matching the integer values ttf-parser used to return. Also ignore non-positive x-height values, like ttf-parser did.
The painter previously reused the last outlined glyph (path_buf) as the fill geometry, which only works when exactly one clip glyph is active. The COLR imaging model instead has a proper clip stack: a fill paints the intersection of all currently pushed clips. - fill() now paints a rectangle covering the intersection of the tracked clip bounds (in root space), shaped by the enclosing SVG clip groups, instead of whatever happened to be in path_buf. - push_clip_glyph/push_clip_box track their bounds on a clip stack. - fill_glyph() is implemented directly (fill the glyph outline with the brush), avoiding the default clip-then-fill decomposition. This also restores the exact rendering of the old ttf-parser painter for COLRv0, so colrv0.png reverts to the version on main. The colrv1 snapshot changes slightly at glyph edges: leaf fills no longer pass through a clip of the same shape, so edge anti-aliasing is no longer applied twice.
Co-authored-by: Laurenz Stampfl <47084093+LaurenzV@users.noreply.github.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
|
I've published |
Signed-off-by: Nico Burns <nico@nicoburns.com>
|
This has now been published as part of the v0.48 release |
##### [v0.48.0](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0480-2026-07-31) This release has an MSRV of 1.89.0 for `usvg` and `resvg` and the C API. The big change in this release is that text support is now backed by [`skrifa`](https://github.com/googlefonts/fontations) and [`harfrust`](https://github.com/harfbuzz/harfrust) rather than [`ttf-parser`](https://github.com/harfbuzz/ttf-parser) and [`rustybuzz`](https://github.com/harfbuzz/rustybuzz): - Moves resvg onto an actively maintained font stack. - Should have faster and more correct text rendering. - Will enable further improvements to things like variable font rendering in future. - May impact binary size (expected +\~500kb for people not otherwise including fontations dependencies in their tree). - May result in small rendering changes compared to older versions of resvg. ##### Added - New `svgz` and `writer` feature gates to reduce the number of required dependencies. ([#1088](linebender/resvg#1088) by [@reed-smout](https://github.com/reed-smout)) - Warnings when parsing malformed paths. ([#1011](linebender/resvg#1011)) - A `Display` implementation for `Units`. ([#986](linebender/resvg#986)) ##### Changed - MSRV bumped from 1.87 to 1.89. The requirement comes from `font-types`. - Text shaping now uses `harfrust` instead of `rustybuzz`, and font parsing uses `skrifa` (fontations) instead of `ttf-parser`. ([#922](linebender/resvg#922) by [@nicoburns](https://github.com/nicoburns)) - Filter input dimension checks are now debug-only assertions. ([#991](linebender/resvg#991)) ##### Fixed - Glyph advances are now calculated correctly. ([#1043](linebender/resvg#1043) by [@fundon](https://github.com/fundon)) - Text nodes now inherit their absolute transform. ([#1040](linebender/resvg#1040) by [@fundon](https://github.com/fundon)) - Fixes related to non-finite values. ([#1049](linebender/resvg#1049) by [@SAY-5](https://github.com/SAY-5)) - Transforms are no longer applied twice in `abs_transform`. ([#1056](linebender/resvg#1056) by [@fundon](https://github.com/fundon)) - `fr` is now resolved for radial gradients referenced via `href`. ([#1098](linebender/resvg#1098) by [@T1mVo](https://github.com/T1mVo)) - Panic in `feComposite` with the `arithmetic` operator when the filter region is larger than the clamped layer. ([#1021](linebender/resvg#1021), [#1007](linebender/resvg#1007)) - Application of `transform` (and other group properties like `opacity`) on a nested `svg` element. - The missing dimension of an `svg` with only `width` or `height` specified is now computed from its `viewBox` aspect ratio. ([#1045](linebender/resvg#1045)) - The `wght` variation coordinate is now set even when `font-weight` has its default value. ([#1099](linebender/resvg#1099)) - The unprefixed `href` attribute now takes precedence over the deprecated `xlink:href` when both are present, as required by SVG 2. ([#1015](linebender/resvg#1015)) - Incorrect y-axis offsets when transforming `feSpotLight` sources. ([#1052](linebender/resvg#1052)) - Panics caused by bounding boxes that exceed the supported integer range. ([#989](linebender/resvg#989)) ##### [v0.47.0](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0470-2026-02-05) This release has an MSRV of 1.87.0 for `usvg` and `resvg` and the C API. ##### Added - Focal radius (`fr`) supported for Radial Gradients. ([#1014](linebender/resvg#1014) by [@wmedrano](https://github.com/wmedrano)) - Support for variable fonts based on font-variation-settings CSS property. ([#997](linebender/resvg#997) by [@oetiker](https://github.com/oetiker)) ##### Changed - `tiny-skia` has a major version bump from 0.11 to 0.12.
##### [v0.48.0](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0480-2026-07-31) This release has an MSRV of 1.89.0 for `usvg` and `resvg` and the C API. The big change in this release is that text support is now backed by [`skrifa`](https://github.com/googlefonts/fontations) and [`harfrust`](https://github.com/harfbuzz/harfrust) rather than [`ttf-parser`](https://github.com/harfbuzz/ttf-parser) and [`rustybuzz`](https://github.com/harfbuzz/rustybuzz): - Moves resvg onto an actively maintained font stack. - Should have faster and more correct text rendering. - Will enable further improvements to things like variable font rendering in future. - May impact binary size (expected +\~500kb for people not otherwise including fontations dependencies in their tree). - May result in small rendering changes compared to older versions of resvg. ##### Added - New `svgz` and `writer` feature gates to reduce the number of required dependencies. ([#1088](linebender/resvg#1088) by [@reed-smout](https://github.com/reed-smout)) - Warnings when parsing malformed paths. ([#1011](linebender/resvg#1011)) - A `Display` implementation for `Units`. ([#986](linebender/resvg#986)) ##### Changed - MSRV bumped from 1.87 to 1.89. The requirement comes from `font-types`. - Text shaping now uses `harfrust` instead of `rustybuzz`, and font parsing uses `skrifa` (fontations) instead of `ttf-parser`. ([#922](linebender/resvg#922) by [@nicoburns](https://github.com/nicoburns)) - Filter input dimension checks are now debug-only assertions. ([#991](linebender/resvg#991)) ##### Fixed - Glyph advances are now calculated correctly. ([#1043](linebender/resvg#1043) by [@fundon](https://github.com/fundon)) - Text nodes now inherit their absolute transform. ([#1040](linebender/resvg#1040) by [@fundon](https://github.com/fundon)) - Fixes related to non-finite values. ([#1049](linebender/resvg#1049) by [@SAY-5](https://github.com/SAY-5)) - Transforms are no longer applied twice in `abs_transform`. ([#1056](linebender/resvg#1056) by [@fundon](https://github.com/fundon)) - `fr` is now resolved for radial gradients referenced via `href`. ([#1098](linebender/resvg#1098) by [@T1mVo](https://github.com/T1mVo)) - Panic in `feComposite` with the `arithmetic` operator when the filter region is larger than the clamped layer. ([#1021](linebender/resvg#1021), [#1007](linebender/resvg#1007)) - Application of `transform` (and other group properties like `opacity`) on a nested `svg` element. - The missing dimension of an `svg` with only `width` or `height` specified is now computed from its `viewBox` aspect ratio. ([#1045](linebender/resvg#1045)) - The `wght` variation coordinate is now set even when `font-weight` has its default value. ([#1099](linebender/resvg#1099)) - The unprefixed `href` attribute now takes precedence over the deprecated `xlink:href` when both are present, as required by SVG 2. ([#1015](linebender/resvg#1015)) - Incorrect y-axis offsets when transforming `feSpotLight` sources. ([#1052](linebender/resvg#1052)) - Panics caused by bounding boxes that exceed the supported integer range. ([#989](linebender/resvg#989)) ##### [v0.47.0](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0470-2026-02-05) This release has an MSRV of 1.87.0 for `usvg` and `resvg` and the C API. ##### Added - Focal radius (`fr`) supported for Radial Gradients. ([#1014](linebender/resvg#1014) by [@wmedrano](https://github.com/wmedrano)) - Support for variable fonts based on font-variation-settings CSS property. ([#997](linebender/resvg#997) by [@oetiker](https://github.com/oetiker)) ##### Changed - `tiny-skia` has a major version bump from 0.11 to 0.12.
##### [v0.48.1](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0481-2026-08-02) This release has an MSRV of 1.85.0 for `usvg` and `resvg` and the C API. ##### Changed - MSRV lowered from 1.89 to 1.85. ([#1109](linebender/resvg#1109)) - Downgraded strict-num dependency to 0.1.1. This prevents duplicate versions from being included ([#1110](linebender/resvg#1110)) ##### Fixed - Fixed an `as_mut_slice` future-compatibility warning. ([#1108](linebender/resvg#1108)) ##### [v0.48.0](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0480-2026-07-31) This release has an MSRV of 1.89.0 for `usvg` and `resvg` and the C API. The big change in this release is that text support is now backed by [`skrifa`](https://github.com/googlefonts/fontations) and [`harfrust`](https://github.com/harfbuzz/harfrust) rather than [`ttf-parser`](https://github.com/harfbuzz/ttf-parser) and [`rustybuzz`](https://github.com/harfbuzz/rustybuzz): - Moves resvg onto an actively maintained font stack. - Should have faster and more correct text rendering. - Will enable further improvements to things like variable font rendering in future. - May impact binary size (expected +\~500kb for people not otherwise including fontations dependencies in their tree). - May result in small rendering changes compared to older versions of resvg. ##### Added - New `svgz` and `writer` feature gates to reduce the number of required dependencies. ([#1088](linebender/resvg#1088) by [@reed-smout](https://github.com/reed-smout)) - Warnings when parsing malformed paths. ([#1011](linebender/resvg#1011)) - A `Display` implementation for `Units`. ([#986](linebender/resvg#986)) ##### Changed - MSRV bumped from 1.87 to 1.89. The requirement comes from `font-types`. - Text shaping now uses `harfrust` instead of `rustybuzz`, and font parsing uses `skrifa` (fontations) instead of `ttf-parser`. ([#922](linebender/resvg#922) by [@nicoburns](https://github.com/nicoburns)) - Filter input dimension checks are now debug-only assertions. ([#991](linebender/resvg#991)) ##### Fixed - Glyph advances are now calculated correctly. ([#1043](linebender/resvg#1043) by [@fundon](https://github.com/fundon)) - Text nodes now inherit their absolute transform. ([#1040](linebender/resvg#1040) by [@fundon](https://github.com/fundon)) - Fixes related to non-finite values. ([#1049](linebender/resvg#1049) by [@SAY-5](https://github.com/SAY-5)) - Transforms are no longer applied twice in `abs_transform`. ([#1056](linebender/resvg#1056) by [@fundon](https://github.com/fundon)) - `fr` is now resolved for radial gradients referenced via `href`. ([#1098](linebender/resvg#1098) by [@T1mVo](https://github.com/T1mVo)) - Panic in `feComposite` with the `arithmetic` operator when the filter region is larger than the clamped layer. ([#1021](linebender/resvg#1021), [#1007](linebender/resvg#1007)) - Application of `transform` (and other group properties like `opacity`) on a nested `svg` element. - The missing dimension of an `svg` with only `width` or `height` specified is now computed from its `viewBox` aspect ratio. ([#1045](linebender/resvg#1045)) - The `wght` variation coordinate is now set even when `font-weight` has its default value. ([#1099](linebender/resvg#1099)) - The unprefixed `href` attribute now takes precedence over the deprecated `xlink:href` when both are present, as required by SVG 2. ([#1015](linebender/resvg#1015)) - Incorrect y-axis offsets when transforming `feSpotLight` sources. ([#1052](linebender/resvg#1052)) - Panics caused by bounding boxes that exceed the supported integer range. ([#989](linebender/resvg#989)) ##### [v0.47.0](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0470-2026-02-05) This release has an MSRV of 1.87.0 for `usvg` and `resvg` and the C API. ##### Added - Focal radius (`fr`) supported for Radial Gradients. ([#1014](linebender/resvg#1014) by [@wmedrano](https://github.com/wmedrano)) - Support for variable fonts based on font-variation-settings CSS property. ([#997](linebender/resvg#997) by [@oetiker](https://github.com/oetiker)) ##### Changed - `tiny-skia` has a major version bump from 0.11 to 0.12.
##### [v0.48.1](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0481-2026-08-02) This release has an MSRV of 1.85.0 for `usvg` and `resvg` and the C API. ##### Changed - MSRV lowered from 1.89 to 1.85. ([#1109](linebender/resvg#1109)) - Downgraded strict-num dependency to 0.1.1. This prevents duplicate versions from being included ([#1110](linebender/resvg#1110)) ##### Fixed - Fixed an `as_mut_slice` future-compatibility warning. ([#1108](linebender/resvg#1108)) ##### [v0.48.0](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0480-2026-07-31) This release has an MSRV of 1.89.0 for `usvg` and `resvg` and the C API. The big change in this release is that text support is now backed by [`skrifa`](https://github.com/googlefonts/fontations) and [`harfrust`](https://github.com/harfbuzz/harfrust) rather than [`ttf-parser`](https://github.com/harfbuzz/ttf-parser) and [`rustybuzz`](https://github.com/harfbuzz/rustybuzz): - Moves resvg onto an actively maintained font stack. - Should have faster and more correct text rendering. - Will enable further improvements to things like variable font rendering in future. - May impact binary size (expected +\~500kb for people not otherwise including fontations dependencies in their tree). - May result in small rendering changes compared to older versions of resvg. ##### Added - New `svgz` and `writer` feature gates to reduce the number of required dependencies. ([#1088](linebender/resvg#1088) by [@reed-smout](https://github.com/reed-smout)) - Warnings when parsing malformed paths. ([#1011](linebender/resvg#1011)) - A `Display` implementation for `Units`. ([#986](linebender/resvg#986)) ##### Changed - MSRV bumped from 1.87 to 1.89. The requirement comes from `font-types`. - Text shaping now uses `harfrust` instead of `rustybuzz`, and font parsing uses `skrifa` (fontations) instead of `ttf-parser`. ([#922](linebender/resvg#922) by [@nicoburns](https://github.com/nicoburns)) - Filter input dimension checks are now debug-only assertions. ([#991](linebender/resvg#991)) ##### Fixed - Glyph advances are now calculated correctly. ([#1043](linebender/resvg#1043) by [@fundon](https://github.com/fundon)) - Text nodes now inherit their absolute transform. ([#1040](linebender/resvg#1040) by [@fundon](https://github.com/fundon)) - Fixes related to non-finite values. ([#1049](linebender/resvg#1049) by [@SAY-5](https://github.com/SAY-5)) - Transforms are no longer applied twice in `abs_transform`. ([#1056](linebender/resvg#1056) by [@fundon](https://github.com/fundon)) - `fr` is now resolved for radial gradients referenced via `href`. ([#1098](linebender/resvg#1098) by [@T1mVo](https://github.com/T1mVo)) - Panic in `feComposite` with the `arithmetic` operator when the filter region is larger than the clamped layer. ([#1021](linebender/resvg#1021), [#1007](linebender/resvg#1007)) - Application of `transform` (and other group properties like `opacity`) on a nested `svg` element. - The missing dimension of an `svg` with only `width` or `height` specified is now computed from its `viewBox` aspect ratio. ([#1045](linebender/resvg#1045)) - The `wght` variation coordinate is now set even when `font-weight` has its default value. ([#1099](linebender/resvg#1099)) - The unprefixed `href` attribute now takes precedence over the deprecated `xlink:href` when both are present, as required by SVG 2. ([#1015](linebender/resvg#1015)) - Incorrect y-axis offsets when transforming `feSpotLight` sources. ([#1052](linebender/resvg#1052)) - Panics caused by bounding boxes that exceed the supported integer range. ([#989](linebender/resvg#989)) ##### [v0.47.0](https://github.com/linebender/resvg/blob/HEAD/CHANGELOG.md#0470-2026-02-05) This release has an MSRV of 1.87.0 for `usvg` and `resvg` and the C API. ##### Added - Focal radius (`fr`) supported for Radial Gradients. ([#1014](linebender/resvg#1014) by [@wmedrano](https://github.com/wmedrano)) - Support for variable fonts based on font-variation-settings CSS property. ([#997](linebender/resvg#997) by [@oetiker](https://github.com/oetiker)) ##### Changed - `tiny-skia` has a major version bump from 0.11 to 0.12.
Changes made
rustybuzzwithharfrustttf_parserwithskrifaNotes
1.65to1.85resvg.Production profile
The analysis below uses the following "production" profile:
Binary size analysis:
According to
cargo-bloat(not the most accurate):harfrustandrustybuzzare both ~250kbttf_parserandread-fontsare both ~100kbttf_parserincludes the metrics outlining functionality ofskrifa. And skrifa is another ~250kb.Compiling the CLI (which is a much more useful test) with the production profile above (
cargo build --profile production --bin resvg) I get:2.4mbformain3.0mbfor this PRSo this PR causes a binary size increase of around
600kbCompile time analysis
Compile times on an M1 Pro (8+2 cores) are shown below (
cargo build):maindebugreleaseproductionSo this PR roughly doubles compile times at regular opt settings
(with the effect being less pronounced with LTO and other production optimisation settings enabled)