// Copyright 2026 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.
let coverage_vertical = 0x80000000U
let coverage_cross_stream = 0x40000000U
let coverage_backwards = 0x10000000U
let coverage_type_mask = 0xffU
///|
pub struct KerxPair {
left : UInt
right : UInt
value : Int
} derive(Eq, Show, ToJson)
///|
pub struct KerxFormat1 {
table : StateTable
actions : Array[Int]
} derive(Show, ToJson)
///|
pub struct KerxFormat2 {
row_width : Int
left : LookupTable
right : LookupTable
values : Array[Int]
} derive(Show, ToJson)
///|
pub struct KerxFormat4 {
table : StateTable
flags : UInt
actions : Array[Int]
} derive(Show, ToJson)
///|
pub struct KerxFormat6 {
row_index : LookupTable
column_index : LookupTable
values : Array[Int]
long_values : Bool
} derive(Show, ToJson)
///|
pub struct KerxAdjustment {
x_advance : Int
y_advance : Int
x_offset : Int
y_offset : Int
} derive(Eq, Show, ToJson)
///|
pub struct KerxSubtableHeader {
coverage : UInt
tuple_count : Int
} derive(Eq, Show, ToJson)
///|
pub enum KerxSubtable {
Format0(KerxSubtableHeader, Array[KerxPair])
Format1(KerxSubtableHeader, KerxFormat1)
Format2(KerxSubtableHeader, KerxFormat2)
Format4(KerxSubtableHeader, KerxFormat4)
Format6(KerxSubtableHeader, KerxFormat6)
} derive(Show, ToJson)
///|
pub struct KerxTable {
version : Int
subtables : Array[KerxSubtable]
} derive(Show, ToJson)
fn coverage_type(coverage : UInt) -> Int {
(coverage & coverage_type_mask).reinterpret_as_int()
}
fn coverage_is_horizontal(coverage : UInt) -> Bool {
(coverage & coverage_vertical) == 0U
}
fn coverage_is_cross_stream(coverage : UInt) -> Bool {
(coverage & coverage_cross_stream) != 0U
}
fn coverage_is_backwards(coverage : UInt) -> Bool {
(coverage & coverage_backwards) != 0U
}
fn resolve_tuple_value(
data : BytesView,
base : Int,
tuple_count : Int,
value : Int,
) -> Int {
if tuple_count <= 0 {
return value
}
if value < 0 {
return 0
}
let offset = base + value
if offset < 0 || offset + tuple_count * 2 > data.length() {
return 0
}
match read_i16(data, offset) {
Err(_) => 0
Ok(v) => v
}
}
fn scale_value(value : Int, scale : Int, upem : Int) -> Int {
if upem == 0 { value } else { (value * scale) / upem }
}
fn make_adjustments(len : Int) -> Array[KerxAdjustment] {
let adjustments : Array[KerxAdjustment] = []
for _ in 0.. Result[KerxSubtable, AatError] {
let pair_count = read_u32_non_negative(data, offset + 12)
match pair_count {
Err(err) => Err(err)
Ok(pair_count) => {
let pair_base = offset + 28
if pair_base < 0 || pair_base + pair_count * 6 > offset + length {
return Err(UnexpectedEof)
}
let pairs : Array[KerxPair] = []
for i in 0.. return Err(err)
(_, Err(err), _) => return Err(err)
(_, _, Err(err)) => return Err(err)
(Ok(left), Ok(right), Ok(value)) => {
let resolved = resolve_tuple_value(data, offset, header.tuple_count, value)
pairs.push(KerxPair::{ left, right, value: resolved })
}
}
}
Ok(KerxSubtable::Format0(header, pairs))
}
}
}
fn parse_kerx_format1(
data : BytesView,
offset : Int,
length : Int,
header : KerxSubtableHeader,
num_glyphs : Int,
) -> Result[KerxSubtable, AatError] {
let machine_start = offset + 12
let table_end = offset + length
if machine_start < 0 || machine_start + 20 > table_end {
return Err(UnexpectedEof)
}
let machine_data = data[machine_start:table_end]
let table = match parse_state_table(machine_data, true, num_glyphs, 1) {
Err(err) => return Err(err)
Ok(value) => value
}
let action_offset = read_u32_non_negative(data, machine_start + 16)
let action_offset = match action_offset {
Err(err) => return Err(err)
Ok(value) => value
}
let action_base = machine_start + action_offset
if action_base < machine_start || action_base > table_end {
return Err(UnexpectedEof)
}
let bytes_len = table_end - action_base
if bytes_len < 0 || (bytes_len & 1) != 0 {
return Err(InvalidFormat)
}
let action_count = bytes_len / 2
let actions : Array[Int] = []
for i in 0.. return Err(err)
Ok(value) => actions.push(value)
}
}
Ok(KerxSubtable::Format1(header, KerxFormat1::{ table, actions }))
}
fn parse_kerx_format2(
data : BytesView,
offset : Int,
length : Int,
header : KerxSubtableHeader,
num_glyphs : Int,
) -> Result[KerxSubtable, AatError] {
let row_width = read_u32_non_negative(data, offset + 12)
let left_offset = read_u32_non_negative(data, offset + 16)
let right_offset = read_u32_non_negative(data, offset + 20)
let array_offset = read_u32_non_negative(data, offset + 24)
match (row_width, left_offset, right_offset, array_offset) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(Ok(row_width), Ok(left_offset), Ok(right_offset), Ok(array_offset)) => {
if row_width <= 0 || (row_width & 1) != 0 {
return Err(InvalidFormat)
}
let left_table = match parse_lookup(data, offset + left_offset, num_glyphs) {
Err(err) => return Err(err)
Ok(value) => value
}
let right_table = match parse_lookup(data, offset + right_offset, num_glyphs) {
Err(err) => return Err(err)
Ok(value) => value
}
let array_base = offset + array_offset
if array_base < 0 || array_base > offset + length {
return Err(UnexpectedEof)
}
let bytes_len = offset + length - array_base
if bytes_len < 0 || (bytes_len & 1) != 0 {
return Err(InvalidFormat)
}
let value_count = bytes_len / 2
let values : Array[Int] = []
for i in 0.. return Err(err)
Ok(value) => {
let resolved = resolve_tuple_value(data, offset, header.tuple_count, value)
values.push(resolved)
}
}
}
Ok(
KerxSubtable::Format2(
header,
KerxFormat2::{
row_width,
left: left_table,
right: right_table,
values,
},
),
)
}
}
}
fn parse_kerx_format4(
data : BytesView,
offset : Int,
length : Int,
header : KerxSubtableHeader,
num_glyphs : Int,
) -> Result[KerxSubtable, AatError] {
let machine_start = offset + 12
let table_end = offset + length
if machine_start < 0 || machine_start + 20 > table_end {
return Err(UnexpectedEof)
}
let machine_data = data[machine_start:table_end]
let table = match parse_state_table(machine_data, true, num_glyphs, 1) {
Err(err) => return Err(err)
Ok(value) => value
}
let flags = read_u32(data, machine_start + 16)
let flags = match flags {
Err(err) => return Err(err)
Ok(value) => value
}
let action_offset = (flags & 0x00FFFFFFU).reinterpret_as_int()
let action_base = machine_start + action_offset
if action_base < machine_start || action_base > table_end {
return Err(UnexpectedEof)
}
let bytes_len = table_end - action_base
if bytes_len < 0 || (bytes_len & 1) != 0 {
return Err(InvalidFormat)
}
let action_count = bytes_len / 2
let actions : Array[Int] = []
for i in 0.. return Err(err)
Ok(value) => actions.push(value)
}
}
Ok(KerxSubtable::Format4(header, KerxFormat4::{ table, flags, actions }))
}
fn parse_kerx_format6(
data : BytesView,
offset : Int,
length : Int,
header : KerxSubtableHeader,
num_glyphs : Int,
) -> Result[KerxSubtable, AatError] {
let flags = read_u32_int(data, offset + 12)
let row_count = read_u16_int(data, offset + 16)
let column_count = read_u16_int(data, offset + 18)
let row_index_offset = read_u32_non_negative(data, offset + 20)
let column_index_offset = read_u32_non_negative(data, offset + 24)
let array_offset = read_u32_non_negative(data, offset + 28)
let vector_offset = read_u32_non_negative(data, offset + 32)
match (
flags,
row_count,
column_count,
row_index_offset,
column_index_offset,
array_offset,
vector_offset,
) {
(Err(err), _, _, _, _, _, _) => Err(err)
(_, Err(err), _, _, _, _, _) => Err(err)
(_, _, Err(err), _, _, _, _) => Err(err)
(_, _, _, Err(err), _, _, _) => Err(err)
(_, _, _, _, Err(err), _, _) => Err(err)
(_, _, _, _, _, Err(err), _) => Err(err)
(_, _, _, _, _, _, Err(err)) => Err(err)
(
Ok(flags),
Ok(_),
Ok(_),
Ok(row_index_offset),
Ok(column_index_offset),
Ok(array_offset),
Ok(vector_offset),
) => {
let long_values = (flags & 1) != 0
let index_value_size = if long_values { 4 } else { 2 }
let row_table = match parse_lookup_with_value_size(
data,
offset + row_index_offset,
num_glyphs,
index_value_size,
) {
Err(err) => return Err(err)
Ok(value) => value
}
let column_table = match parse_lookup_with_value_size(
data,
offset + column_index_offset,
num_glyphs,
index_value_size,
) {
Err(err) => return Err(err)
Ok(value) => value
}
let array_base = offset + array_offset
let mut array_end = offset + length
if vector_offset > 0 && offset + vector_offset < array_end && offset + vector_offset > array_base {
array_end = offset + vector_offset
}
if array_base < 0 || array_base > array_end || array_end > offset + length {
return Err(UnexpectedEof)
}
let bytes_len = array_end - array_base
let value_size = if long_values { 4 } else { 2 }
if bytes_len < 0 || (bytes_len % value_size) != 0 {
return Err(InvalidFormat)
}
let value_count = bytes_len / value_size
let vector_base = if vector_offset > 0 { offset + vector_offset } else { -1 }
let values : Array[Int] = []
for i in 0.. return Err(err)
Ok(value) => {
let resolved =
if header.tuple_count > 0 && vector_base >= 0 {
resolve_tuple_value(data, vector_base, header.tuple_count, value)
} else {
value
}
values.push(resolved)
}
}
}
Ok(
KerxSubtable::Format6(
header,
KerxFormat6::{
row_index: row_table,
column_index: column_table,
values,
long_values,
},
),
)
}
}
}
fn lookup_value(lookup : LookupTable, glyph : UInt) -> Int {
match lookup.value_for(glyph) {
None => 0
Some(value) => value.reinterpret_as_int()
}
}
fn KerxSubtable::value_for(
self : KerxSubtable,
left : UInt,
right : UInt,
) -> Int {
match self {
Format0(_, pairs) => {
for pair in pairs {
if pair.left == left && pair.right == right {
return pair.value
}
}
0
}
Format2(_, format2) => {
let left_value = lookup_value(format2.left, left)
let right_value = lookup_value(format2.right, right)
let index = left_value + right_value
if index < 0 || index >= format2.values.length() {
0
} else {
format2.values[index]
}
}
Format6(_, format6) => {
let left_value = lookup_value(format6.row_index, left)
let right_value = lookup_value(format6.column_index, right)
let index = left_value + right_value
if index < 0 || index >= format6.values.length() {
0
} else {
format6.values[index]
}
}
Format1(_, _) => 0
Format4(_, _) => 0
}
}
fn KerxSubtable::header(self : KerxSubtable) -> KerxSubtableHeader {
match self {
Format0(header, _) => header
Format1(header, _) => header
Format2(header, _) => header
Format4(header, _) => header
Format6(header, _) => header
}
}
///|
pub fn KerxTable::parse(
data : BytesView,
num_glyphs : Int,
) -> Result[KerxTable, AatError] {
let version = read_u16_int(data, 0)
let table_count = read_u32_non_negative(data, 4)
match (version, table_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(version), Ok(table_count)) => {
let mut offset = 8
let subtables : Array[KerxSubtable] = []
for _ in 0.. return Err(err)
(_, Err(err), _) => return Err(err)
(_, _, Err(err)) => return Err(err)
(Ok(length), Ok(coverage), Ok(tuple_count)) => {
if length < 12 || offset + length > data.length() {
return Err(UnexpectedEof)
}
let header = KerxSubtableHeader::{ coverage, tuple_count }
let sub_type = coverage_type(coverage)
if sub_type == 0 {
let subtable = match parse_kerx_format0(data, offset, length, header) {
Err(err) => return Err(err)
Ok(value) => value
}
subtables.push(subtable)
} else if sub_type == 1 {
let subtable = match parse_kerx_format1(
data,
offset,
length,
header,
num_glyphs,
) {
Err(err) => return Err(err)
Ok(value) => value
}
subtables.push(subtable)
} else if sub_type == 2 {
let subtable = match parse_kerx_format2(data, offset, length, header, num_glyphs) {
Err(err) => return Err(err)
Ok(value) => value
}
subtables.push(subtable)
} else if sub_type == 4 {
let subtable = match parse_kerx_format4(
data,
offset,
length,
header,
num_glyphs,
) {
Err(err) => return Err(err)
Ok(value) => value
}
subtables.push(subtable)
} else if sub_type == 6 {
let subtable = match parse_kerx_format6(data, offset, length, header, num_glyphs) {
Err(err) => return Err(err)
Ok(value) => value
}
subtables.push(subtable)
}
offset = offset + length
}
}
}
Ok(KerxTable::{ version, subtables })
}
}
}
///|
pub fn KerxTable::has_data(self : KerxTable) -> Bool {
self.version != 0
}
///|
pub fn KerxTable::kern_value(
self : KerxTable,
left : UInt,
right : UInt,
horizontal : Bool,
) -> Int {
let mut value = 0
for subtable in self.subtables {
let header = subtable.header()
if coverage_is_cross_stream(header.coverage) || coverage_is_backwards(header.coverage) {
continue
}
if horizontal != coverage_is_horizontal(header.coverage) {
continue
}
let kern = subtable.value_for(left, right)
if kern != 0 {
value = value + kern
}
}
value
}
fn map_index(idx : Int, len : Int, backwards : Bool) -> Int {
if backwards { len - 1 - idx } else { idx }
}
fn apply_pair_kerning(
subtable : KerxSubtable,
header : KerxSubtableHeader,
glyphs : Array[UInt],
horizontal : Bool,
scale : Int,
upem : Int,
adjustments : Array[KerxAdjustment],
) -> Bool {
if glyphs.length() < 2 {
return false
}
let cross_stream = coverage_is_cross_stream(header.coverage)
let mut changed = false
for i in 0..<(glyphs.length() - 1) {
let kern = subtable.value_for(glyphs[i], glyphs[i + 1])
if kern == 0 {
continue
}
let scaled = scale_value(kern, scale, upem)
if scaled == 0 {
continue
}
changed = true
if cross_stream {
let right = adjustments[i + 1]
adjustments[i + 1] = if horizontal {
KerxAdjustment::{
x_advance: right.x_advance,
y_advance: right.y_advance,
x_offset: right.x_offset,
y_offset: right.y_offset + scaled,
}
} else {
KerxAdjustment::{
x_advance: right.x_advance,
y_advance: right.y_advance,
x_offset: right.x_offset + scaled,
y_offset: right.y_offset,
}
}
} else {
let kern1 = scaled >> 1
let kern2 = scaled - kern1
let left = adjustments[i]
let right = adjustments[i + 1]
if horizontal {
adjustments[i] = KerxAdjustment::{
x_advance: left.x_advance + kern1,
y_advance: left.y_advance,
x_offset: left.x_offset,
y_offset: left.y_offset,
}
adjustments[i + 1] = KerxAdjustment::{
x_advance: right.x_advance + kern2,
y_advance: right.y_advance,
x_offset: right.x_offset + kern2,
y_offset: right.y_offset,
}
} else {
adjustments[i] = KerxAdjustment::{
x_advance: left.x_advance,
y_advance: left.y_advance + kern1,
x_offset: left.x_offset,
y_offset: left.y_offset,
}
adjustments[i + 1] = KerxAdjustment::{
x_advance: right.x_advance,
y_advance: right.y_advance + kern2,
x_offset: right.x_offset,
y_offset: right.y_offset + kern2,
}
}
}
}
changed
}
let format1_push = 0x8000
let format1_dont_advance = 0x4000
let format1_reset = 0x2000
fn apply_format1(
header : KerxSubtableHeader,
format1 : KerxFormat1,
glyphs : Array[UInt],
horizontal : Bool,
scale : Int,
upem : Int,
adjustments : Array[KerxAdjustment],
) -> Bool {
if format1.table.n_classes <= 0 {
return false
}
let cross_stream = coverage_is_cross_stream(header.coverage)
let backwards = coverage_is_backwards(header.coverage)
let stride = if header.tuple_count > 0 { header.tuple_count } else { 1 }
let mut changed = false
let mut state = 0
let mut idx = 0
let len = glyphs.length()
let stack : Array[Int] = [0, 0, 0, 0, 0, 0, 0, 0]
let mut depth = 0
while true {
let klass =
if idx < len {
let actual = map_index(idx, len, backwards)
format1.table.class_for(glyphs[actual])
} else {
0
}
let entry = format1.table.entry_for(state, klass)
let flags = entry.flags
if (flags & format1_reset) != 0 {
depth = 0
}
if (flags & format1_push) != 0 && idx < len {
if depth < stack.length() {
let actual = map_index(idx, len, backwards)
stack[depth] = actual
depth = depth + 1
} else {
depth = 0
}
}
if entry.data1 != 0xffff && depth > 0 {
let mut action_index = entry.data1 / 2
let mut last = false
while !last && depth > 0 {
if action_index < 0 || action_index >= format1.actions.length() {
depth = 0
break
}
depth = depth - 1
let target = stack[depth]
let mut value = format1.actions[action_index]
action_index = action_index + stride
last = (value & 1) != 0
value = value & -2
let scaled = scale_value(value, scale, upem)
if scaled != 0 && target >= 0 && target < adjustments.length() {
let pos = adjustments[target]
if cross_stream {
adjustments[target] = if horizontal {
KerxAdjustment::{
x_advance: pos.x_advance,
y_advance: pos.y_advance,
x_offset: pos.x_offset,
y_offset: pos.y_offset + scaled,
}
} else {
KerxAdjustment::{
x_advance: pos.x_advance,
y_advance: pos.y_advance,
x_offset: pos.x_offset + scaled,
y_offset: pos.y_offset,
}
}
} else {
adjustments[target] = if horizontal {
KerxAdjustment::{
x_advance: pos.x_advance + scaled,
y_advance: pos.y_advance,
x_offset: pos.x_offset + scaled,
y_offset: pos.y_offset,
}
} else {
KerxAdjustment::{
x_advance: pos.x_advance,
y_advance: pos.y_advance + scaled,
x_offset: pos.x_offset,
y_offset: pos.y_offset + scaled,
}
}
}
changed = true
}
}
}
state = format1.table.new_state(entry.new_state)
if idx >= len {
break
}
if (flags & format1_dont_advance) == 0 {
idx = idx + 1
}
}
changed
}
let format4_mark = 0x8000
let format4_dont_advance = 0x4000
fn apply_format4(
header : KerxSubtableHeader,
format4 : KerxFormat4,
glyphs : Array[UInt],
scale_x : Int,
scale_y : Int,
upem : Int,
adjustments : Array[KerxAdjustment],
ankr : AnkrTable?,
contour_point : (UInt, Int) -> (Int, Int)?,
) -> Bool {
if format4.table.n_classes <= 0 {
return false
}
let backwards = coverage_is_backwards(header.coverage)
let action_type = ((format4.flags >> 30) & 0x3U).reinterpret_as_int()
let mut changed = false
let mut state = 0
let mut idx = 0
let len = glyphs.length()
let mut mark_set = false
let mut mark_index = 0
while true {
let klass =
if idx < len {
let actual = map_index(idx, len, backwards)
format4.table.class_for(glyphs[actual])
} else {
0
}
let entry = format4.table.entry_for(state, klass)
if mark_set && entry.data1 != 0xffff && idx < len {
let actual = map_index(idx, len, backwards)
if actual >= 0 && actual < adjustments.length() {
if action_type == 0 {
let base = entry.data1 * 2
if base >= 0 && base + 1 < format4.actions.length() {
let mark_point = format4.actions[base]
let curr_point = format4.actions[base + 1]
if mark_point >= 0 && curr_point >= 0 {
let mark = contour_point(glyphs[mark_index], mark_point)
let curr = contour_point(glyphs[actual], curr_point)
match (mark, curr) {
(Some((mark_x, mark_y)), Some((curr_x, curr_y))) => {
let dx = mark_x - curr_x
let dy = mark_y - curr_y
let pos = adjustments[actual]
let x_scaled = scale_value(dx, scale_x, upem)
let y_scaled = scale_value(dy, scale_y, upem)
adjustments[actual] = KerxAdjustment::{
x_advance: pos.x_advance,
y_advance: pos.y_advance,
x_offset: pos.x_offset + x_scaled,
y_offset: pos.y_offset + y_scaled,
}
changed = true
}
_ => ()
}
}
}
} else if action_type == 1 {
let base = entry.data1 * 2
if base >= 0 && base + 1 < format4.actions.length() {
let mark_anchor = format4.actions[base]
let curr_anchor = format4.actions[base + 1]
if mark_anchor >= 0 && curr_anchor >= 0 {
match ankr {
None => ()
Some(ankr) => {
let mark = ankr.get_anchor(glyphs[mark_index], mark_anchor)
let curr = ankr.get_anchor(glyphs[actual], curr_anchor)
match (mark, curr) {
(Some(mark), Some(curr)) => {
let dx = mark.x - curr.x
let dy = mark.y - curr.y
let pos = adjustments[actual]
let x_scaled = scale_value(dx, scale_x, upem)
let y_scaled = scale_value(dy, scale_y, upem)
adjustments[actual] = KerxAdjustment::{
x_advance: pos.x_advance,
y_advance: pos.y_advance,
x_offset: pos.x_offset + x_scaled,
y_offset: pos.y_offset + y_scaled,
}
changed = true
}
_ => ()
}
}
}
}
}
} else if action_type == 2 {
let base = entry.data1 * 4
if base >= 0 && base + 3 < format4.actions.length() {
let mark_x = format4.actions[base]
let mark_y = format4.actions[base + 1]
let curr_x = format4.actions[base + 2]
let curr_y = format4.actions[base + 3]
let dx = mark_x - curr_x
let dy = mark_y - curr_y
let pos = adjustments[actual]
let x_scaled = scale_value(dx, scale_x, upem)
let y_scaled = scale_value(dy, scale_y, upem)
adjustments[actual] = KerxAdjustment::{
x_advance: pos.x_advance,
y_advance: pos.y_advance,
x_offset: pos.x_offset + x_scaled,
y_offset: pos.y_offset + y_scaled,
}
changed = true
}
}
}
}
if (entry.flags & format4_mark) != 0 && idx < len {
mark_set = true
mark_index = map_index(idx, len, backwards)
}
state = format4.table.new_state(entry.new_state)
if idx >= len {
break
}
if (entry.flags & format4_dont_advance) == 0 {
idx = idx + 1
}
}
changed
}
///|
pub fn KerxTable::apply_scaled(
self : KerxTable,
glyphs : Array[UInt],
horizontal : Bool,
scale_x : Int,
scale_y : Int,
upem : Int,
ankr : AnkrTable?,
contour_point? : (UInt, Int) -> (Int, Int)? = (_, _) => None,
) -> Array[KerxAdjustment] {
let adjustments = make_adjustments(glyphs.length())
if self.version == 0 || glyphs.is_empty() {
return adjustments
}
let primary_scale = if horizontal { scale_x } else { scale_y }
for subtable in self.subtables {
let header = subtable.header()
if horizontal != coverage_is_horizontal(header.coverage) {
continue
}
match subtable {
Format0(_, _) | Format2(_, _) | Format6(_, _) => {
if coverage_is_backwards(header.coverage) {
continue
}
ignore(
apply_pair_kerning(
subtable,
header,
glyphs,
horizontal,
primary_scale,
upem,
adjustments,
),
)
}
Format1(_, format1) =>
ignore(
apply_format1(
header,
format1,
glyphs,
horizontal,
primary_scale,
upem,
adjustments,
),
)
Format4(_, format4) =>
ignore(
apply_format4(
header,
format4,
glyphs,
scale_x,
scale_y,
upem,
adjustments,
ankr,
contour_point,
),
)
}
}
adjustments
}