// 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.
///|
/// Storage/CVT + delta instruction implementations for the TT engine.
///
/// Ported from `fontations/skrifa/src/outline/glyf/hint/engine/{storage.rs,cvt.rs,delta.rs}`
/// (Apache-2.0 OR MIT).
fn tt_scale_funits_to_26_6(value : Int32, scale_bits : Int32) -> Int32 {
// value (font units) * scale_bits (16.16, includes *64) => 26.6
let v = value.to_int64() * scale_bits.to_int64()
let adj = 0x8000 - (if v < 0 { 1 } else { 0 })
((v + adj.to_int64()) >> 16).to_int()
}
///|
fn TtEngine::op_rs(self : TtEngine) -> Unit raise HintError {
let loc = self.value_stack.pop_usize()
if loc < 0 || loc >= self.storage.length() {
if self.graphics.is_pedantic {
raise InvalidStorageIndex(loc)
} else {
self.value_stack.push(0)
}
} else {
self.value_stack.push(self.storage.at(loc))
}
}
///|
fn TtEngine::op_ws(self : TtEngine) -> Unit raise HintError {
let value = self.value_stack.pop()
let loc = self.value_stack.pop_usize()
if loc < 0 || loc >= self.storage.length() {
if self.graphics.is_pedantic {
raise InvalidStorageIndex(loc)
} else {
()
}
} else {
self.storage.set(loc, value)
()
}
}
///|
fn TtEngine::op_wcvtp(self : TtEngine) -> Unit raise HintError {
let value = self.value_stack.pop()
let loc = self.value_stack.pop_usize()
if loc < 0 || loc >= self.cvt.length() {
if self.graphics.is_pedantic {
raise InvalidCvtIndex(loc)
} else {
()
}
} else {
self.cvt.set(loc, value)
()
}
}
///|
fn TtEngine::op_wcvtf(self : TtEngine) -> Unit raise HintError {
let value_funits = self.value_stack.pop()
let loc = self.value_stack.pop_usize()
if loc < 0 || loc >= self.cvt.length() {
if self.graphics.is_pedantic {
raise InvalidCvtIndex(loc)
} else {
()
}
} else {
let value = tt_scale_funits_to_26_6(
value_funits,
self.graphics.retained.scale,
)
self.cvt.set(loc, value)
()
}
}
///|
fn TtEngine::op_rcvt(self : TtEngine) -> Unit raise HintError {
let loc = self.value_stack.pop()
if loc < 0 || loc >= self.cvt.length() {
if self.graphics.is_pedantic {
raise InvalidCvtIndex(loc)
} else {
self.value_stack.push(0)
}
} else {
self.value_stack.push(self.cvt.at(loc))
}
}
///|
fn tt_delta_adjust(gs : TtGraphicsState, b0 : Int32) -> Int32 {
// See FreeType packing scheme.
let mut b = (b0 & 0xF) - 8
if b >= 0 {
b = b + 1
}
b * (1 << (6 - gs.retained.delta_shift))
}
///|
fn TtEngine::op_deltap(self : TtEngine, opcode : Int32) -> Unit raise HintError {
let ppem_u = self.graphics.retained.ppem.reinterpret_as_uint()
let point_count = self.graphics.zp0_zone().points.length()
let n0 = self.value_stack.pop()
if n0 < 0 {
if self.graphics.is_pedantic {
raise InvalidStackValue(n0)
} else {
return ()
}
}
// Each entry consumes 2 stack values.
let n = n0.min(self.value_stack.length() / 2)
let bias0 : UInt32 = (match opcode {
0x71 => 16
0x72 => 32
_ => 0
}).reinterpret_as_uint()
let bias = bias0 + self.graphics.retained.delta_base.reinterpret_as_uint()
let back_compat = self.graphics.backward_compatibility
let did_iup = self.graphics.did_iup_x && self.graphics.did_iup_y
for _ in 0..= point_count {
continue
}
let c : UInt32 = ((b0.reinterpret_as_uint() & 0xF0) >> 4) + bias
if ppem_u == c {
let adj = tt_delta_adjust(self.graphics, b0)
if back_compat {
let touched_y = self.graphics.zp0_zone().is_touched(point_ix, Y)
if !did_iup &&
(
(self.graphics.is_composite && self.graphics.freedom_vector.y != 0) ||
touched_y
) {
self.graphics.move_point(self.graphics.zp0, point_ix, adj)
}
} else {
self.graphics.move_point(self.graphics.zp0, point_ix, adj)
}
}
}
()
}
///|
fn TtEngine::op_deltac(self : TtEngine, opcode : Int32) -> Unit raise HintError {
let ppem_u = self.graphics.retained.ppem.reinterpret_as_uint()
let n0 = self.value_stack.pop()
if n0 < 0 {
if self.graphics.is_pedantic {
raise InvalidStackValue(n0)
} else {
return ()
}
}
let n = n0.min(self.value_stack.length() / 2)
let bias0 : UInt32 = (match opcode {
0x74 => 16
0x75 => 32
_ => 0
}).reinterpret_as_uint()
let bias = bias0 + self.graphics.retained.delta_base.reinterpret_as_uint()
for _ in 0..> 4) + bias
if ppem_u == c {
if cvt_ix < 0 || cvt_ix >= self.cvt.length() {
if self.graphics.is_pedantic {
raise InvalidCvtIndex(cvt_ix)
} else {
continue
}
}
let adj = tt_delta_adjust(self.graphics, b0)
self.cvt.set(cvt_ix, self.cvt.at(cvt_ix) + adj)
}
}
()
}
///|
fn TtEngine::op_sdb(self : TtEngine) -> Unit raise HintError {
let b = self.value_stack.pop()
self.graphics.retained.delta_base = b
()
}
///|
fn TtEngine::op_sds(self : TtEngine) -> Unit raise HintError {
let s = self.value_stack.pop()
// FreeType/fontations clamp delta_shift to [0, 6].
if s < 0 || s > 6 {
raise InvalidStackValue(s)
}
self.graphics.retained.delta_shift = s
()
}