[fontations] Fix anchor unreduction

This commit is contained in:
Behdad Esfahbod 2025-03-05 10:48:48 -07:00 committed by Khaled Hosny
parent b5ad6de8d6
commit 3a699c3764

View file

@ -407,50 +407,32 @@ extern "C" fn _hb_fontations_get_extend(
color_line_data.extend as hb_paint_extend_t // They are the same
}
/// Returns (x0, y0, x1, y1, x2, y2) such that the original `_hb_cairo_reduce_anchors`
/// would produce (xx0, yy0, xx1, yy1) as outputs.
pub fn _hb_fontations_unreduce_anchors(
xx0: f32,
yy0: f32,
xx1: f32,
yy1: f32,
x0: f32,
y0: f32,
x1: f32,
y1: f32,
) -> (f32, f32, f32, f32, f32, f32) {
// 1) Force the first anchor to match directly:
let x0 = xx0;
let y0 = yy0;
/* Returns (x0, y0, x1, y1, x2, y2) such that the original
* `_hb_cairo_reduce_anchors` would produce (xx0, yy0, xx1, yy1)
* as outputs.
* The OT spec has the following wording; we just need to
* invert that operation here:
*
* Note: An implementation can derive a single vector, from p to a point p, by computing the
* orthogonal projection of the vector from p to p onto a line perpendicular to line pp and
* passing through p to obtain point p. The linear gradient defined using p, p and p as
* described above is functionally equivalent to a linear gradient defined by aligning stop
* offset 0 to p and aligning stop offset 1.0 to p, with each color projecting on either side
* of that line in a perpendicular direction. This specification uses three points, p, p and
* p, as that provides greater flexibility in controlling the placement and rotation of the
* gradient, as well as variations thereof.
*/
// 2) Force the second anchor to match directly:
let x1 = xx1;
let y1 = yy1;
let dx = x1 - x0;
let dy = y1 - y0;
// Vector from (xx0, yy0) to (xx1, yy1)
let dx = xx1 - xx0;
let dy = yy1 - yy0;
let dist2 = dx * dx + dy * dy;
// 3) Pick (x2, y2)
let (x2, y2) = if dist2 < 1e-12 {
// Degenerate: both anchors are almost the same point
// => choose any non-zero offset from (x0, y0)
(xx0 + 100.0, yy0)
} else {
// Non-degenerate: pick a perpendicular vector to (dx, dy)
let len = dist2.sqrt();
let mut q2x = dy;
let mut q2y = -dx;
// Optionally scale it to the same length as (dx, dy)
let q2len = (q2x * q2x + q2y * q2y).sqrt();
if q2len > 1e-12 {
let scale = len / q2len;
q2x *= scale;
q2y *= scale;
}
(xx0 + q2x, yy0 + q2y)
};
(x0, y0, x1, y1, x2, y2)
(x0, y0, x1, y1, x0 + dy, y0 - dx)
}
impl ColorPainter for HbColorPainter {
@ -540,20 +522,19 @@ impl ColorPainter for HbColorPainter {
};
let mut color_line = self.make_color_line(&color_stops);
// Untested
let points = _hb_fontations_unreduce_anchors(p0.x, p0.y, p1.x, p1.y);
let (x0, y0, x1, y1, x2, y2) = _hb_fontations_unreduce_anchors(p0.x, p0.y, p1.x, p1.y);
unsafe {
hb_paint_linear_gradient(
self.paint_funcs,
self.paint_data,
&mut color_line,
points.0,
points.1,
points.2,
points.3,
points.4,
points.5,
x0,
y0,
x1,
y1,
x2,
y2,
);
}
}