Skip to content

[read-fonts] Make FloatItemDelta float accessors public#1954

Merged
cmyr merged 1 commit into
mainfrom
float-item-delta-pub-accessors
Jul 3, 2026
Merged

[read-fonts] Make FloatItemDelta float accessors public#1954
cmyr merged 1 commit into
mainfrom
float-item-delta-pub-accessors

Conversation

@behdad

@behdad behdad commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Expose FloatItemDelta::to_f32 (new) and to_f64 (was pub(crate)) so downstream crates can read the unrounded item-variation delta.

Previously the only reachable accessor was the integer-rounded ItemVariationStore::compute_delta. Callers that need HarfBuzz-compatible positioning must keep the delta fractional and round only once, after scaling to output units; that requires the raw float value from compute_float_delta.

Assisted by Claude Opus 4.8 (1M context)

@behdad

behdad commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Downstream user: harfbuzz/harfrust#403

Comment thread read-fonts/src/tables/variations.rs Outdated
Comment on lines +1557 to +1560
/// Returns the (unrounded) delta value as a 32-bit float.
pub fn to_f32(self) -> f32 {
self.0 as f32
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this genuinely useful, versus just exposing to_f64 and letting the caller convert if they want?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that works.

Expose FloatItemDelta::to_f32 (new) and to_f64 (was pub(crate)) so
downstream crates can read the unrounded item-variation delta.

Previously the only reachable accessor was the integer-rounded
ItemVariationStore::compute_delta.  Callers that need
HarfBuzz-compatible positioning must keep the delta fractional and
round only once, after scaling to output units; that requires the
raw float value from compute_float_delta.

Assisted by Claude Opus 4.8 (1M context)
@behdad
behdad force-pushed the float-item-delta-pub-accessors branch from 1d40545 to c23e7d6 Compare July 3, 2026 18:20
@cmyr
cmyr merged commit 940249f into main Jul 3, 2026
19 checks passed
@cmyr
cmyr deleted the float-item-delta-pub-accessors branch July 3, 2026 18:25
behdad added a commit to harfbuzz/harfrust that referenced this pull request Jul 3, 2026
GPOS Device/VariationIndex deltas -- both value-record adjustments
and anchor coordinates -- were computed with
ItemVariationStore::compute_delta, which rounds the delta to whole
font units, and then scaled to output units.  That double rounding
discards up to half a font unit of the advance, placement, or
attachment adjustment.

HarfBuzz instead keeps the delta fractional and rounds only once,
after scaling: Device::get_x_delta is em_scalef_x(get_delta()),
i.e. roundf(delta * scale / upem), used for both value records and
Anchor::get_anchor.  For variable fonts this made the "harfrust"
shaper disagree with "ot" by sub-font-unit amounts on non-default
instances (#402, e.g. SFNSItalic at weights other
than the default).

Compute the deltas with compute_float_delta and scale them with new
Scale::scale_x_f/scale_y_f helpers that mirror HarfBuzz's em_multf
(roundf(v * scale / upem)), keeping f32 arithmetic to match it.
resolve_anchor now returns fractional font units, and its cursive
and mark callers round once when scaling.  The static value-record
path stays on the integer scale, matching HarfBuzz (static ->
em_scale, device -> em_scalef).

Bump the read-fonts dependency to 0.41.0, which makes the
FloatItemDelta::to_f64 accessor public (googlefonts/fontations#1954);
compute_float_delta's result is read through it.

Advances now match the "ot" shaper exactly (0.000000px) for
SFNSItalic across weights 100-900; the harfrust and HarfBuzz shape
suites pass with no regressions.

Fixes: #402
Assisted-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
behdad added a commit to harfbuzz/harfrust that referenced this pull request Jul 3, 2026
GPOS Device/VariationIndex deltas -- both value-record adjustments
and anchor coordinates -- were computed with
ItemVariationStore::compute_delta, which rounds the delta to whole
font units, and then scaled to output units.  That double rounding
discards up to half a font unit of the advance, placement, or
attachment adjustment.

HarfBuzz instead keeps the delta fractional and rounds only once,
after scaling: Device::get_x_delta is em_scalef_x(get_delta()),
i.e. roundf(delta * scale / upem), used for both value records and
Anchor::get_anchor.  For variable fonts this made the "harfrust"
shaper disagree with "ot" by sub-font-unit amounts on non-default
instances (#402, e.g. SFNSItalic at weights other
than the default).

Compute the deltas with compute_float_delta and scale them with new
Scale::scale_x_f/scale_y_f helpers that mirror HarfBuzz's em_multf
(roundf(v * scale / upem)), keeping f32 arithmetic to match it.
resolve_anchor now returns fractional font units, and its cursive
and mark callers round once when scaling.  The static value-record
path stays on the integer scale, matching HarfBuzz (static ->
em_scale, device -> em_scalef).

Bump the read-fonts dependency to 0.41.0, which makes the
FloatItemDelta::to_f64 accessor public (googlefonts/fontations#1954);
compute_float_delta's result is read through it.

Advances now match the "ot" shaper exactly (0.000000px) for
SFNSItalic across weights 100-900; the harfrust and HarfBuzz shape
suites pass with no regressions.

Fixes: #402
Assisted-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
behdad added a commit to harfbuzz/harfrust that referenced this pull request Jul 3, 2026
GPOS Device/VariationIndex deltas -- both value-record adjustments
and anchor coordinates -- were computed with
ItemVariationStore::compute_delta, which rounds the delta to whole
font units, and then scaled to output units.  That double rounding
discards up to half a font unit of the advance, placement, or
attachment adjustment.

HarfBuzz instead keeps the delta fractional and rounds only once,
after scaling: Device::get_x_delta is em_scalef_x(get_delta()),
i.e. roundf(delta * scale / upem), used for both value records and
Anchor::get_anchor.  For variable fonts this made the "harfrust"
shaper disagree with "ot" by sub-font-unit amounts on non-default
instances (#402, e.g. SFNSItalic at weights other
than the default).

Compute the deltas with compute_float_delta and scale them with new
Scale::scale_x_f/scale_y_f helpers that mirror HarfBuzz's em_multf
(roundf(v * scale / upem)), keeping f32 arithmetic to match it.
resolve_anchor now returns fractional font units, and its cursive
and mark callers round once when scaling.  The static value-record
path stays on the integer scale, matching HarfBuzz (static ->
em_scale, device -> em_scalef).

Bump the read-fonts dependency to 0.41.0, which makes the
FloatItemDelta::to_f64 accessor public (googlefonts/fontations#1954);
compute_float_delta's result is read through it.

Advances now match the "ot" shaper exactly (0.000000px) for
SFNSItalic across weights 100-900; the harfrust and HarfBuzz shape
suites pass with no regressions.

Fixes: #402
Assisted-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
behdad added a commit to harfbuzz/harfrust that referenced this pull request Jul 3, 2026
GPOS Device/VariationIndex deltas -- both value-record adjustments
and anchor coordinates -- were computed with
ItemVariationStore::compute_delta, which rounds the delta to whole
font units, and then scaled to output units.  That double rounding
discards up to half a font unit of the advance, placement, or
attachment adjustment.

HarfBuzz instead keeps the delta fractional and rounds only once,
after scaling: Device::get_x_delta is em_scalef_x(get_delta()),
i.e. roundf(delta * scale / upem), used for both value records and
Anchor::get_anchor.  For variable fonts this made the "harfrust"
shaper disagree with "ot" by sub-font-unit amounts on non-default
instances (#402, e.g. SFNSItalic at weights other
than the default).

Compute the deltas with compute_float_delta and scale them with new
Scale::scale_x_f/scale_y_f helpers that mirror HarfBuzz's em_multf
(roundf(v * scale / upem)), keeping f32 arithmetic to match it.
resolve_anchor now returns fractional font units, and its cursive
and mark callers round once when scaling.  The static value-record
path stays on the integer scale, matching HarfBuzz (static ->
em_scale, device -> em_scalef).

Bump the read-fonts dependency to 0.41.0, which makes the
FloatItemDelta::to_f64 accessor public (googlefonts/fontations#1954);
compute_float_delta's result is read through it.

Advances now match the "ot" shaper exactly (0.000000px) for
SFNSItalic across weights 100-900; the harfrust and HarfBuzz shape
suites pass with no regressions.

Fixes: #402
Assisted-by: Claude <noreply@anthropic.com>

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants