Skip to content

Rotated text: kerning offset added to dest.x regardless of rotation angle (regression in 0.4.15) #1045

@benface

Description

@benface

Summary

The kerning support added in #1035 (released in 0.4.15, partial DPI fix in #1039) adds the kerning offset to dest.x unconditionally, ignoring TextParams.rotation. For non-zero rotation the offset lands perpendicular to the text-flow axis instead of along it, so each kerned pair shifts the following glyph sideways from its line.

Reproduction

Any draw_text_ex call with TextParams.rotation != 0 and a font that has kerning entries between consecutive glyphs in the rendered string. Concrete repro with OstrichSans-Heavy at rotation = π / 2: the AT / TE / PA pairs that gap horizontally at rotation = 0 now produce vertical-in-screen-space misalignment instead — visible as a per-character perpendicular shift that varies with the surrounding kerning context (the same letter in two different words shifts by different amounts).

Cause

In src/text.rs::draw_text_ex (current master):

let rot_cos = rot.cos();
let rot_sin = rot.sin();
let dest_x = (offset_x + total_width) * rot_cos + (glyph_scaled_h + offset_y) * rot_sin;
let dest_y = (offset_x + total_width) * rot_sin + (-glyph_scaled_h - offset_y) * rot_cos;

let dest = Rect::new(
    dest_x / dpi_scaling + x + kerning_offset / dpi_scaling,  // ← always +X
    dest_y / dpi_scaling + y,                                  //   never +Y
    ...
);

(offset_x + total_width) is the cumulative advance along the unrotated text-flow direction (+X in glyph-local space). The rotation matrix correctly routes it into dest_x / dest_y per the rotation angle. But kerning_offset is an additional text-flow advance and gets bolted onto dest.x without the same rotation routing — so at rotation = π / 2 it lands on screen-Y (perpendicular to flow) instead of screen-X.

Affected platforms

Anywhere draw_text_ex is called with non-zero TextParams.rotation AND the font has kerning entries between consecutive glyphs. Platform-independent — fontdue's kerning data is loaded the same way on every platform that miniquad supports.

Fix

One-line — project kerning_offset onto the rotated text-flow axis before adding it:

let kerning_logical = kerning_offset / dpi_scaling;
let dest = Rect::new(
    dest_x / dpi_scaling + x + kerning_logical * rot_cos,
    dest_y / dpi_scaling + y + kerning_logical * rot_sin,
    ...
);

PR follows.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions