// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
/// Outline manipulation instruction implementations for the TT engine.
///
/// Ported from `fontations/skrifa/src/outline/glyf/hint/engine/outline.rs`
/// (Apache-2.0 OR MIT).
fn tt_abs_i(x : Int) -> Int {
if x < 0 {
-x
} else {
x
}
}
///|
fn tt_in_bounds(
gs : TtGraphicsState,
zone_ptr : TtZonePointer,
p : Int,
) -> Bool {
let zone = match zone_ptr {
Twilight => gs.twilight
Glyph => gs.glyph
}
p >= 0 && p < zone.points.length()
}
///|
fn TtEngine::op_flippt(self : TtEngine) -> Result[Unit, HintError] {
let count = self.graphics.loop_counter
self.graphics.loop_counter = 1
// In backward compatibility mode, don't flip points after IUP has run.
if self.graphics.backward_compatibility &&
self.graphics.did_iup_x &&
self.graphics.did_iup_y {
for _ in 0.. return Err(e)
Ok(_) => ()
}
}
return Ok(())
}
let zone = self.graphics.glyph
for _ in 0.. return Err(e)
Ok(v) => v
}
match zone.flip_on_curve(p) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
Ok(())
}
///|
fn TtEngine::set_on_curve_for_range(
self : TtEngine,
on : Bool,
) -> Result[Unit, HintError] {
let high0 = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let low = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
// high_point is inclusive; convert to exclusive.
let high = high0 + 1
if high <= high0 {
return Err(InvalidPointIndex(high0))
}
if self.graphics.backward_compatibility &&
self.graphics.did_iup_x &&
self.graphics.did_iup_y {
return Ok(())
}
self.graphics.glyph.set_on_curve(low, high, on)
}
///|
fn TtEngine::op_fliprgon(self : TtEngine) -> Result[Unit, HintError] {
self.set_on_curve_for_range(true)
}
///|
fn TtEngine::op_fliprgoff(self : TtEngine) -> Result[Unit, HintError] {
self.set_on_curve_for_range(false)
}
///|
fn TtEngine::op_shp(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let gs = self.graphics
let disp = match gs.point_displacement(opcode) {
Err(e) => return Err(e)
Ok(v) => v
}
let count = gs.loop_counter
self.graphics.loop_counter = 1
for _ in 0.. return Err(e)
Ok(v) => v
}
match self.graphics.move_zp2_point(p, disp.dx, disp.dy, true) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
Ok(())
}
///|
fn TtEngine::op_shc(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let contour_ix = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let gs = self.graphics
let z = gs.zp2_zone()
if !gs.is_pedantic && (contour_ix < 0 || contour_ix >= z.contours.length()) {
return Ok(())
}
let disp = match gs.point_displacement(opcode) {
Err(e) => return Err(e)
Ok(v) => v
}
let start = if contour_ix != 0 {
match z.contour_end(contour_ix - 1) {
Err(e) => return Err(e)
Ok(v) => v + 1
}
} else {
0
}
let end = if gs.zp2.is_twilight() {
z.points.length()
} else {
match z.contour_end(contour_ix) {
Err(e) => return Err(e)
Ok(v) => v + 1
}
}
for i in start.. return Err(e)
Ok(_) => ()
}
}
}
Ok(())
}
///|
fn TtEngine::op_shz(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let e = match self.value_stack.pop() {
Err(e) => return Err(e)
Ok(v) => v
}
// Validate zone pointer but we shift the current zp2 zone regardless.
match tt_zone_pointer_from_i32(e) {
Err(e) => return Err(e)
Ok(_) => ()
}
let gs = self.graphics
let disp = match gs.point_displacement(opcode) {
Err(e) => return Err(e)
Ok(v) => v
}
let z = gs.zp2_zone()
let end = if gs.zp2.is_twilight() {
z.points.length()
} else if !z.contours.is_empty() {
z.contours.at(z.contours.length() - 1) + 1
} else {
0
}
for i in 0.. return Err(e)
Ok(_) => ()
}
}
}
Ok(())
}
///|
fn TtEngine::op_shpix(self : TtEngine) -> Result[Unit, HintError] {
let gs = self.graphics
let in_twilight = gs.zp0.is_twilight() ||
gs.zp1.is_twilight() ||
gs.zp2.is_twilight()
let amount = match self.value_stack.pop() {
Err(e) => return Err(e)
Ok(v) => v
}
let dx = tt_hint_mul14(amount, gs.freedom_vector.x)
let dy = tt_hint_mul14(amount, gs.freedom_vector.y)
let count = gs.loop_counter
self.graphics.loop_counter = 1
let did_iup = gs.did_iup_x && gs.did_iup_y
for _ in 0.. return Err(e)
Ok(v) => v
}
if gs.backward_compatibility {
let touched_y = match gs.zp2_zone().is_touched(p, Y) {
Err(e) => return Err(e)
Ok(v) => v
}
if in_twilight ||
(
!did_iup &&
((gs.is_composite && gs.freedom_vector.y != 0) || touched_y)
) {
match self.graphics.move_zp2_point(p, dx, dy, true) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
} else {
match self.graphics.move_zp2_point(p, dx, dy, true) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
}
Ok(())
}
///|
fn TtEngine::op_msirp(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let gs = self.graphics
let distance = match self.value_stack.pop() {
Err(e) => return Err(e)
Ok(v) => v
}
let point_ix = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
if !gs.is_pedantic &&
(!tt_in_bounds(gs, gs.zp1, point_ix) || !tt_in_bounds(gs, gs.zp0, gs.rp0)) {
return Ok(())
}
if gs.zp1.is_twilight() {
let zp0z = gs.zp0_zone()
let orig = match zp0z.original_point(gs.rp0) {
Err(e) => return Err(e)
Ok(v) => v
}
let zp1z = gs.zp1_zone()
match zp1z.set_point(point_ix, orig) {
Err(e) => return Err(e)
Ok(_) => ()
}
match zp1z.set_original_point(point_ix, orig) {
Err(e) => return Err(e)
Ok(_) => ()
}
match self.graphics.move_point(gs.zp1, point_ix, distance) {
Err(e) => return Err(e)
Ok(_) => ()
}
let p1 = match zp1z.original_point(point_ix) {
Err(e) => return Err(e)
Ok(v) => v
}
match zp1z.set_point(point_ix, p1) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
let d = self.graphics.project(
match gs.zp1_zone().point(point_ix) {
Err(e) => return Err(e)
Ok(v) => v
},
match gs.zp0_zone().point(gs.rp0) {
Err(e) => return Err(e)
Ok(v) => v
},
)
match self.graphics.move_point(gs.zp1, point_ix, distance - d) {
Err(e) => return Err(e)
Ok(_) => ()
}
self.graphics.rp1 = gs.rp0
self.graphics.rp2 = point_ix
if (opcode & 1) != 0 {
self.graphics.rp0 = point_ix
}
Ok(())
}
///|
fn TtEngine::op_mdap(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let p = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let gs = self.graphics
if !gs.is_pedantic && !tt_in_bounds(gs, gs.zp0, p) {
self.graphics.rp0 = p
self.graphics.rp1 = p
return Ok(())
}
let distance = if (opcode & 1) != 0 {
let cur_dist = self.graphics.project(
match gs.zp0_zone().point(p) {
Err(e) => return Err(e)
Ok(v) => v
},
{ x: 0, y: 0 },
)
self.graphics.round(cur_dist) - cur_dist
} else {
0
}
match self.graphics.move_point(gs.zp0, p, distance) {
Err(e) => return Err(e)
Ok(_) => ()
}
self.graphics.rp0 = p
self.graphics.rp1 = p
Ok(())
}
///|
fn TtEngine::op_miap(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let cvt_entry = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let point_ix = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
if cvt_entry < 0 || cvt_entry >= self.cvt.length() {
return Err(InvalidCvtIndex(cvt_entry))
}
let mut distance = self.cvt.at(cvt_entry)
let gs = self.graphics
if gs.zp0.is_twilight() {
let fv = gs.freedom_vector
let z = gs.zp0_zone()
let original_point = TtPoint::{
x: tt_hint_mul14(distance, fv.x),
y: tt_hint_mul14(distance, fv.y),
}
match z.set_original_point(point_ix, original_point) {
Err(e) => return Err(e)
Ok(_) => ()
}
match z.set_point(point_ix, original_point) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
let original_distance = self.graphics.project(
match gs.zp0_zone().point(point_ix) {
Err(e) => return Err(e)
Ok(v) => v
},
{ x: 0, y: 0 },
)
if (opcode & 1) != 0 {
let delta = tt_abs_i(distance - original_distance)
if delta > gs.retained.control_value_cutin {
distance = original_distance
}
distance = self.graphics.round(distance)
}
match
self.graphics.move_point(gs.zp0, point_ix, distance - original_distance) {
Err(e) => return Err(e)
Ok(_) => ()
}
self.graphics.rp0 = point_ix
self.graphics.rp1 = point_ix
Ok(())
}
///|
fn TtEngine::op_mdrp(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let p = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let gs = self.graphics
if !gs.is_pedantic &&
(!tt_in_bounds(gs, gs.zp1, p) || !tt_in_bounds(gs, gs.zp0, gs.rp0)) {
self.graphics.rp1 = gs.rp0
self.graphics.rp2 = p
if (opcode & 16) != 0 {
self.graphics.rp0 = p
}
return Ok(())
}
let mut original_distance = if gs.zp0.is_twilight() || gs.zp1.is_twilight() {
self.graphics.dual_project(
match gs.zp1_zone().original_point(p) {
Err(e) => return Err(e)
Ok(v) => v
},
match gs.zp0_zone().original_point(gs.rp0) {
Err(e) => return Err(e)
Ok(v) => v
},
)
} else {
let v1 = gs.zp1_zone().unscaled_point(p)
let v2 = gs.zp0_zone().unscaled_point(gs.rp0)
let dist = self.graphics.dual_project_unscaled(v1, v2)
// scale to pixels (matches fontations `math::mul` sign-aware rounding)
tt_hint_mul_16_16(dist, gs.unscaled_to_pixels())
}
let cutin = gs.retained.single_width_cutin
let value = gs.retained.single_width
if cutin > 0 &&
original_distance < value + cutin &&
original_distance > value - cutin {
original_distance = if original_distance >= 0 { value } else { -value }
}
let mut distance = if (opcode & 4) != 0 {
self.graphics.round(original_distance)
} else {
original_distance
}
if (opcode & 8) != 0 {
let min_distance = gs.retained.min_distance
if original_distance >= 0 {
if distance < min_distance {
distance = min_distance
}
} else if distance > -min_distance {
distance = -min_distance
}
}
let cur = self.graphics.project(
match gs.zp1_zone().point(p) {
Err(e) => return Err(e)
Ok(v) => v
},
match gs.zp0_zone().point(gs.rp0) {
Err(e) => return Err(e)
Ok(v) => v
},
)
match self.graphics.move_point(gs.zp1, p, distance - cur) {
Err(e) => return Err(e)
Ok(_) => ()
}
self.graphics.rp1 = gs.rp0
self.graphics.rp2 = p
if (opcode & 16) != 0 {
self.graphics.rp0 = p
}
Ok(())
}
///|
fn TtEngine::op_mirp(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let n = match self.value_stack.pop() {
Err(e) => return Err(e)
Ok(v) => v + 1
}
let p = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let gs = self.graphics
if !gs.is_pedantic &&
(
!tt_in_bounds(gs, gs.zp1, p) ||
!tt_in_bounds(gs, gs.zp0, gs.rp0) ||
n > self.cvt.length()
) {
self.graphics.rp1 = gs.rp0
if (opcode & 16) != 0 {
self.graphics.rp0 = p
}
self.graphics.rp2 = p
return Ok(())
}
let mut cvt_distance = if n == 0 { 0 } else { self.cvt.at(n - 1) }
let cutin = gs.retained.single_width_cutin
let value = gs.retained.single_width
let mut delta = tt_abs_i(cvt_distance - value)
if delta < cutin {
cvt_distance = if cvt_distance >= 0 { value } else { -value }
}
if gs.zp1.is_twilight() {
let fv = gs.freedom_vector
let d = cvt_distance
let p2 = match gs.zp0_zone().original_point(gs.rp0) {
Err(e) => return Err(e)
Ok(v) => v
}
let p1 = TtPoint::{
x: p2.x + tt_hint_mul14(d, fv.x),
y: p2.y + tt_hint_mul14(d, fv.y),
}
let z1 = gs.zp1_zone()
match z1.set_original_point(p, p1) {
Err(e) => return Err(e)
Ok(_) => ()
}
match z1.set_point(p, p1) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
let original_distance = self.graphics.dual_project(
match gs.zp1_zone().original_point(p) {
Err(e) => return Err(e)
Ok(v) => v
},
match gs.zp0_zone().original_point(gs.rp0) {
Err(e) => return Err(e)
Ok(v) => v
},
)
let current_distance = self.graphics.project(
match gs.zp1_zone().point(p) {
Err(e) => return Err(e)
Ok(v) => v
},
match gs.zp0_zone().point(gs.rp0) {
Err(e) => return Err(e)
Ok(v) => v
},
)
if gs.retained.auto_flip && (original_distance ^ cvt_distance) < 0 {
cvt_distance = -cvt_distance
}
let mut distance = if (opcode & 4) != 0 {
if gs.zp0 == gs.zp1 {
delta = tt_abs_i(cvt_distance - original_distance)
if delta > gs.retained.control_value_cutin {
cvt_distance = original_distance
}
}
self.graphics.round(cvt_distance)
} else {
cvt_distance
}
if (opcode & 8) != 0 {
let min_distance = gs.retained.min_distance
if original_distance >= 0 {
if distance < min_distance {
distance = min_distance
}
} else if distance > -min_distance {
distance = -min_distance
}
}
match self.graphics.move_point(gs.zp1, p, distance - current_distance) {
Err(e) => return Err(e)
Ok(_) => ()
}
self.graphics.rp1 = gs.rp0
if (opcode & 16) != 0 {
self.graphics.rp0 = p
}
self.graphics.rp2 = p
Ok(())
}
///|
fn TtEngine::op_alignrp(self : TtEngine) -> Result[Unit, HintError] {
let gs = self.graphics
let count = gs.loop_counter
self.graphics.loop_counter = 1
for _ in 0.. return Err(e)
Ok(v) => v
}
let distance = self.graphics.project(
match gs.zp1_zone().point(p) {
Err(e) => return Err(e)
Ok(v) => v
},
match gs.zp0_zone().point(gs.rp0) {
Err(e) => return Err(e)
Ok(v) => v
},
)
match self.graphics.move_point(gs.zp1, p, -distance) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
Ok(())
}
///|
fn TtEngine::op_isect(self : TtEngine) -> Result[Unit, HintError] {
let gs = self.graphics
let b1 = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let b0 = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let a1 = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let a0 = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let point_ix = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let z1 = gs.zp1_zone()
let pa0 = match z1.point(a0) {
Err(e) => return Err(e)
Ok(v) => v
}
let pa1 = match z1.point(a1) {
Err(e) => return Err(e)
Ok(v) => v
}
let z0 = gs.zp0_zone()
let pb0 = match z0.point(b0) {
Err(e) => return Err(e)
Ok(v) => v
}
let pb1 = match z0.point(b1) {
Err(e) => return Err(e)
Ok(v) => v
}
let dbx = pb1.x - pb0.x
let dby = pb1.y - pb0.y
let dax = pa1.x - pa0.x
let day = pa1.y - pa0.y
let dx = pb0.x - pa0.x
let dy = pb0.y - pa0.y
let discriminant = tt_mul_div26(dax, -dby, 0x40) +
tt_mul_div26(day, dbx, 0x40)
let dotproduct = tt_mul_div26(dax, dbx, 0x40) + tt_mul_div26(day, dby, 0x40)
let z2 = gs.zp2_zone()
let (new_x, new_y) = if tt_abs_i(discriminant).to_int64() * 19 >
tt_abs_i(dotproduct).to_int64() {
let v = tt_mul_div26(dx, -dby, 0x40) + tt_mul_div26(dy, dbx, 0x40)
let x = tt_mul_div26(v, dax, discriminant)
let y = tt_mul_div26(v, day, discriminant)
(pa0.x + x, pa0.y + y)
} else {
((pa0.x + pa1.x + pb0.x + pb1.x) / 4, (pa0.y + pa1.y + pb0.y + pb1.y) / 4)
}
match z2.set_point(point_ix, { x: new_x, y: new_y }) {
Err(e) => return Err(e)
Ok(_) => ()
}
match z2.touch(point_ix, X) {
Err(e) => return Err(e)
Ok(_) => ()
}
z2.touch(point_ix, Y)
}
///|
fn TtEngine::op_alignpts(self : TtEngine) -> Result[Unit, HintError] {
let p2 = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let p1 = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let gs = self.graphics
let distance = self.graphics.project(
match gs.zp0_zone().point(p2) {
Err(e) => return Err(e)
Ok(v) => v
},
match gs.zp1_zone().point(p1) {
Err(e) => return Err(e)
Ok(v) => v
},
) /
2
match self.graphics.move_point(gs.zp1, p1, distance) {
Err(e) => return Err(e)
Ok(_) => ()
}
self.graphics.move_point(gs.zp0, p2, -distance)
}
///|
fn tt_mul_div26(a : Int, b : Int, c : Int) -> Int {
tt_mul_div_round(a, b, c)
}
///|
fn TtEngine::op_ip(self : TtEngine) -> Result[Unit, HintError] {
let gs = self.graphics
let count = gs.loop_counter
self.graphics.loop_counter = 1
if !gs.is_pedantic &&
(!tt_in_bounds(gs, gs.zp0, gs.rp1) || !tt_in_bounds(gs, gs.zp1, gs.rp2)) {
return Ok(())
}
let in_twilight = gs.zp0.is_twilight() ||
gs.zp1.is_twilight() ||
gs.zp2.is_twilight()
let orus_base = if in_twilight {
match gs.zp0_zone().original_point(gs.rp1) {
Err(e) => return Err(e)
Ok(v) => v
}
} else {
gs.zp0_zone().unscaled_point(gs.rp1)
}
let cur_base = match gs.zp0_zone().point(gs.rp1) {
Err(e) => return Err(e)
Ok(v) => v
}
let old_range = if in_twilight {
self.graphics.dual_project(
match gs.zp1_zone().original_point(gs.rp2) {
Err(e) => return Err(e)
Ok(v) => v
},
orus_base,
)
} else {
self.graphics.dual_project_unscaled(
gs.zp1_zone().unscaled_point(gs.rp2),
orus_base,
)
}
let cur_range = self.graphics.project(
match gs.zp1_zone().point(gs.rp2) {
Err(e) => return Err(e)
Ok(v) => v
},
cur_base,
)
for _ in 0.. return Err(e)
Ok(v) => v
}
if !gs.is_pedantic && !tt_in_bounds(gs, gs.zp2, point) {
continue
}
let original_distance = if in_twilight {
self.graphics.dual_project(
match gs.zp2_zone().original_point(point) {
Err(e) => return Err(e)
Ok(v) => v
},
orus_base,
)
} else {
self.graphics.dual_project_unscaled(
gs.zp2_zone().unscaled_point(point),
orus_base,
)
}
let cur_distance = self.graphics.project(
match gs.zp2_zone().point(point) {
Err(e) => return Err(e)
Ok(v) => v
},
cur_base,
)
let new_distance = if original_distance != 0 {
if old_range != 0 {
tt_mul_div26(original_distance, cur_range, old_range)
} else {
original_distance
}
} else {
0
}
match self.graphics.move_point(gs.zp2, point, new_distance - cur_distance) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
Ok(())
}
///|
fn TtEngine::op_iup(self : TtEngine, opcode : Int) -> Result[Unit, HintError] {
let axis = if (opcode & 1) != 0 { TtAxis::X } else { Y }
let mut run = true
if self.graphics.backward_compatibility {
if self.graphics.did_iup_x && self.graphics.did_iup_y {
run = false
}
if axis is X {
self.graphics.did_iup_x = true
} else {
self.graphics.did_iup_y = true
}
}
if run {
let glyph = self.graphics.glyph
match glyph.iup(axis) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
Ok(())
}
///|
fn TtEngine::op_utp(self : TtEngine) -> Result[Unit, HintError] {
let p = match self.value_stack.pop_usize() {
Err(e) => return Err(e)
Ok(v) => v
}
let has_x = self.graphics.freedom_vector.x != 0
let has_y = self.graphics.freedom_vector.y != 0
if !has_x && !has_y {
return Ok(())
}
let z0 = self.graphics.zp0_zone()
if has_x {
match z0.untouch(p, X) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
if has_y {
match z0.untouch(p, Y) {
Err(e) => return Err(e)
Ok(_) => ()
}
}
Ok(())
}