// 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.
///|
/// Math value record with optional device table offset.
pub struct MathValueRecord {
value : Int
device_offset : Int
} derive(Eq, Show, ToJson)
///|
/// Math constants table.
pub struct MathConstants {
percent_scale_down : Array[Int]
min_height : Array[Int]
math_values : Array[MathValueRecord]
radical_degree_bottom_raise_percent : Int
} derive(Show, ToJson)
///|
/// Italics correction info.
pub struct MathItalicsCorrectionInfo {
coverage_offset : Int
records : Array[MathValueRecord]
} derive(Show, ToJson)
///|
/// Top accent attachment info.
pub struct MathTopAccentAttachment {
coverage_offset : Int
records : Array[MathValueRecord]
} derive(Show, ToJson)
///|
/// Math kern table.
pub struct MathKern {
height_count : Int
records : Array[MathValueRecord]
} derive(Show, ToJson)
///|
/// Math kern info record (four corners).
pub struct MathKernInfoRecord {
math_kerns : Array[MathKern?]
} derive(Show, ToJson)
///|
/// Math kern info table.
pub struct MathKernInfo {
coverage_offset : Int
records : Array[MathKernInfoRecord]
} derive(Show, ToJson)
///|
/// Math glyph info table.
pub struct MathGlyphInfo {
italics_correction : MathItalicsCorrectionInfo?
top_accent_attachment : MathTopAccentAttachment?
extended_shape_coverage_offset : Int
math_kern_info : MathKernInfo?
} derive(Show, ToJson)
///|
/// Math glyph variant record.
pub struct MathGlyphVariantRecord {
variant_glyph : Int
advance : Int
} derive(Show, ToJson)
///|
/// Math glyph part record.
pub struct MathGlyphPartRecord {
glyph : Int
start_connector_length : Int
end_connector_length : Int
full_advance : Int
flags : Int
} derive(Show, ToJson)
///|
/// Math glyph assembly table.
pub struct MathGlyphAssembly {
italics_correction : MathValueRecord
parts : Array[MathGlyphPartRecord]
} derive(Show, ToJson)
///|
/// Math glyph construction table.
pub struct MathGlyphConstruction {
glyph_assembly : MathGlyphAssembly?
variants : Array[MathGlyphVariantRecord]
} derive(Show, ToJson)
///|
/// Math variants table.
pub struct MathVariants {
min_connector_overlap : Int
vert_coverage_offset : Int
horiz_coverage_offset : Int
vert_glyph_count : Int
horiz_glyph_count : Int
constructions : Array[MathGlyphConstruction?]
} derive(Show, ToJson)
///|
/// Parsed MATH table.
pub struct MathTable {
major_version : Int
minor_version : Int
constants : MathConstants?
glyph_info : MathGlyphInfo?
variants : MathVariants?
} derive(Show, ToJson)
///|
fn read_math_value_record(
data : BytesView,
offset : Int,
base : Int,
) -> Result[MathValueRecord, SfntError] {
let value = read_i16(data, offset)
let device_offset = read_u16_int(data, offset + 2)
match (value, device_offset) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(value), Ok(device_offset)) => {
if device_offset < 0 {
return Err(InvalidFormat)
}
if device_offset != 0 {
let absolute = base + device_offset
if absolute < 0 || absolute > data.length() {
return Err(UnexpectedEof)
}
}
Ok(MathValueRecord::{ value, device_offset })
}
}
}
///|
fn parse_math_constants(
data : BytesView,
offset : Int,
) -> Result[MathConstants, SfntError] {
if offset < 0 || offset + 214 > data.length() {
return Err(UnexpectedEof)
}
let percent0 = read_i16(data, offset)
let percent1 = read_i16(data, offset + 2)
let min0 = read_u16_int(data, offset + 4)
let min1 = read_u16_int(data, offset + 6)
match (percent0, percent1, min0, min1) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(Ok(percent0), Ok(percent1), Ok(min0), Ok(min1)) => {
let percent_scale_down : Array[Int] = [percent0, percent1]
let min_height : Array[Int] = [min0, min1]
let math_values : Array[MathValueRecord] = []
let mut cursor = offset + 8
for _ in 0..<51 {
let record = match read_math_value_record(data, cursor, offset) {
Err(err) => return Err(err)
Ok(record) => record
}
math_values.push(record)
cursor = cursor + 4
}
let radical = read_i16(data, offset + 212)
match radical {
Err(err) => Err(err)
Ok(radical) =>
Ok(MathConstants::{
percent_scale_down,
min_height,
math_values,
radical_degree_bottom_raise_percent: radical,
})
}
}
}
}
///|
fn parse_math_italics_correction(
data : BytesView,
offset : Int,
) -> Result[MathItalicsCorrectionInfo, SfntError] {
let coverage_offset = read_u16_int(data, offset)
let count = read_u16_int(data, offset + 2)
match (coverage_offset, count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(count)) => {
if count < 0 {
return Err(InvalidFormat)
}
if coverage_offset < 0 {
return Err(InvalidFormat)
}
if coverage_offset != 0 {
let absolute = offset + coverage_offset
if absolute < 0 || absolute > data.length() {
return Err(UnexpectedEof)
}
}
let records : Array[MathValueRecord] = []
let record_base = offset + 4
if record_base + count * 4 > data.length() {
return Err(UnexpectedEof)
}
for i in 0.. return Err(err)
Ok(value) => value
}
records.push(record)
}
Ok(MathItalicsCorrectionInfo::{ coverage_offset, records })
}
}
}
///|
fn parse_math_top_accent_attachment(
data : BytesView,
offset : Int,
) -> Result[MathTopAccentAttachment, SfntError] {
let coverage_offset = read_u16_int(data, offset)
let count = read_u16_int(data, offset + 2)
match (coverage_offset, count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(count)) => {
if count < 0 {
return Err(InvalidFormat)
}
if coverage_offset < 0 {
return Err(InvalidFormat)
}
if coverage_offset != 0 {
let absolute = offset + coverage_offset
if absolute < 0 || absolute > data.length() {
return Err(UnexpectedEof)
}
}
let records : Array[MathValueRecord] = []
let record_base = offset + 4
if record_base + count * 4 > data.length() {
return Err(UnexpectedEof)
}
for i in 0.. return Err(err)
Ok(value) => value
}
records.push(record)
}
Ok(MathTopAccentAttachment::{ coverage_offset, records })
}
}
}
///|
fn parse_math_kern(data : BytesView, offset : Int) -> Result[MathKern, SfntError] {
let height_count = read_u16_int(data, offset)
match height_count {
Err(err) => Err(err)
Ok(height_count) => {
if height_count < 0 {
return Err(InvalidFormat)
}
let total = height_count * 2 + 1
let record_base = offset + 2
if record_base + total * 4 > data.length() {
return Err(UnexpectedEof)
}
let records : Array[MathValueRecord] = []
for i in 0.. return Err(err)
Ok(value) => value
}
records.push(record)
}
Ok(MathKern::{ height_count, records })
}
}
}
///|
fn parse_math_kern_info(
data : BytesView,
offset : Int,
) -> Result[MathKernInfo, SfntError] {
let coverage_offset = read_u16_int(data, offset)
let count = read_u16_int(data, offset + 2)
match (coverage_offset, count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(count)) => {
if count < 0 {
return Err(InvalidFormat)
}
if coverage_offset < 0 {
return Err(InvalidFormat)
}
if coverage_offset != 0 {
let absolute = offset + coverage_offset
if absolute < 0 || absolute > data.length() {
return Err(UnexpectedEof)
}
}
let records : Array[MathKernInfoRecord] = []
let record_base = offset + 4
if record_base + count * 8 > data.length() {
return Err(UnexpectedEof)
}
for i in 0.. return Err(err)
Ok(kern_offset) => {
if kern_offset < 0 {
return Err(InvalidFormat)
}
if kern_offset == 0 {
math_kerns.push(None)
} else {
let absolute = offset + kern_offset
let kern = match parse_math_kern(data, absolute) {
Err(err) => return Err(err)
Ok(value) => value
}
math_kerns.push(Some(kern))
}
}
}
}
records.push(MathKernInfoRecord::{ math_kerns })
}
Ok(MathKernInfo::{ coverage_offset, records })
}
}
}
///|
fn parse_math_glyph_info(
data : BytesView,
offset : Int,
) -> Result[MathGlyphInfo, SfntError] {
let italics_offset = read_u16_int(data, offset)
let top_offset = read_u16_int(data, offset + 2)
let extended_offset = read_u16_int(data, offset + 4)
let kern_offset = read_u16_int(data, offset + 6)
match (italics_offset, top_offset, extended_offset, kern_offset) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(Ok(italics_offset), Ok(top_offset), Ok(extended_offset), Ok(kern_offset)) => {
if italics_offset < 0 || top_offset < 0 || extended_offset < 0 || kern_offset < 0 {
return Err(InvalidFormat)
}
let italics_correction = if italics_offset == 0 {
None
} else {
let absolute = offset + italics_offset
Some(match parse_math_italics_correction(data, absolute) {
Err(err) => return Err(err)
Ok(value) => value
})
}
let top_accent_attachment = if top_offset == 0 {
None
} else {
let absolute = offset + top_offset
Some(match parse_math_top_accent_attachment(data, absolute) {
Err(err) => return Err(err)
Ok(value) => value
})
}
if extended_offset != 0 {
let absolute = offset + extended_offset
if absolute < 0 || absolute > data.length() {
return Err(UnexpectedEof)
}
}
let math_kern_info = if kern_offset == 0 {
None
} else {
let absolute = offset + kern_offset
Some(match parse_math_kern_info(data, absolute) {
Err(err) => return Err(err)
Ok(value) => value
})
}
Ok(MathGlyphInfo::{
italics_correction,
top_accent_attachment,
extended_shape_coverage_offset: extended_offset,
math_kern_info,
})
}
}
}
///|
fn parse_math_glyph_assembly(
data : BytesView,
offset : Int,
) -> Result[MathGlyphAssembly, SfntError] {
let italics = match read_math_value_record(data, offset, offset) {
Err(err) => return Err(err)
Ok(value) => value
}
let count = read_u16_int(data, offset + 4)
match count {
Err(err) => Err(err)
Ok(count) => {
if count < 0 {
return Err(InvalidFormat)
}
let parts : Array[MathGlyphPartRecord] = []
let record_base = offset + 6
if record_base + count * 10 > data.length() {
return Err(UnexpectedEof)
}
for i in 0.. return Err(err)
(_, Err(err), _, _, _) => return Err(err)
(_, _, Err(err), _, _) => return Err(err)
(_, _, _, Err(err), _) => return Err(err)
(_, _, _, _, Err(err)) => return Err(err)
(Ok(glyph), Ok(start_connector_length), Ok(end_connector_length), Ok(full_advance), Ok(flags)) =>
parts.push(MathGlyphPartRecord::{
glyph,
start_connector_length,
end_connector_length,
full_advance,
flags,
})
}
}
Ok(MathGlyphAssembly::{ italics_correction: italics, parts })
}
}
}
///|
fn parse_math_glyph_construction(
data : BytesView,
offset : Int,
) -> Result[MathGlyphConstruction, SfntError] {
let assembly_offset = read_u16_int(data, offset)
let variant_count = read_u16_int(data, offset + 2)
match (assembly_offset, variant_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(assembly_offset), Ok(variant_count)) => {
if assembly_offset < 0 || variant_count < 0 {
return Err(InvalidFormat)
}
let glyph_assembly = if assembly_offset == 0 {
None
} else {
let absolute = offset + assembly_offset
Some(match parse_math_glyph_assembly(data, absolute) {
Err(err) => return Err(err)
Ok(value) => value
})
}
let variants : Array[MathGlyphVariantRecord] = []
let record_base = offset + 4
if record_base + variant_count * 4 > data.length() {
return Err(UnexpectedEof)
}
for i in 0.. return Err(err)
(_, Err(err)) => return Err(err)
(Ok(glyph), Ok(advance)) =>
variants.push(MathGlyphVariantRecord::{ variant_glyph: glyph, advance })
}
}
Ok(MathGlyphConstruction::{ glyph_assembly, variants })
}
}
}
///|
fn parse_math_variants(
data : BytesView,
offset : Int,
) -> Result[MathVariants, SfntError] {
let min_connector_overlap = read_u16_int(data, offset)
let vert_coverage_offset = read_u16_int(data, offset + 2)
let horiz_coverage_offset = read_u16_int(data, offset + 4)
let vert_count = read_u16_int(data, offset + 6)
let horiz_count = read_u16_int(data, offset + 8)
match (
min_connector_overlap,
vert_coverage_offset,
horiz_coverage_offset,
vert_count,
horiz_count,
) {
(Err(err), _, _, _, _) => Err(err)
(_, Err(err), _, _, _) => Err(err)
(_, _, Err(err), _, _) => Err(err)
(_, _, _, Err(err), _) => Err(err)
(_, _, _, _, Err(err)) => Err(err)
(
Ok(min_connector_overlap),
Ok(vert_coverage_offset),
Ok(horiz_coverage_offset),
Ok(vert_count),
Ok(horiz_count),
) => {
if vert_coverage_offset < 0 || horiz_coverage_offset < 0 ||
vert_count < 0 || horiz_count < 0 {
return Err(InvalidFormat)
}
if vert_coverage_offset != 0 {
let absolute = offset + vert_coverage_offset
if absolute < 0 || absolute > data.length() {
return Err(UnexpectedEof)
}
}
if horiz_coverage_offset != 0 {
let absolute = offset + horiz_coverage_offset
if absolute < 0 || absolute > data.length() {
return Err(UnexpectedEof)
}
}
let total = vert_count + horiz_count
let constructions : Array[MathGlyphConstruction?] = []
let offsets_base = offset + 10
if offsets_base + total * 2 > data.length() {
return Err(UnexpectedEof)
}
for i in 0.. return Err(err)
Ok(construction_offset) => {
if construction_offset < 0 {
return Err(InvalidFormat)
}
if construction_offset == 0 {
constructions.push(None)
} else {
let absolute = offset + construction_offset
let construction = match parse_math_glyph_construction(data, absolute) {
Err(err) => return Err(err)
Ok(value) => value
}
constructions.push(Some(construction))
}
}
}
}
Ok(MathVariants::{
min_connector_overlap,
vert_coverage_offset,
horiz_coverage_offset,
vert_glyph_count: vert_count,
horiz_glyph_count: horiz_count,
constructions,
})
}
}
}
///|
/// Parse MATH table bytes.
pub fn MathTable::parse(data : BytesView) -> Result[MathTable, SfntError] {
if data.length() < 10 {
return Err(UnexpectedEof)
}
let version = read_u32_int(data, 0)
let constants_offset = read_u16_int(data, 4)
let glyph_info_offset = read_u16_int(data, 6)
let variants_offset = read_u16_int(data, 8)
match (version, constants_offset, glyph_info_offset, variants_offset) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(Ok(version), Ok(constants_offset), Ok(glyph_info_offset), Ok(variants_offset)) => {
if constants_offset < 0 || glyph_info_offset < 0 || variants_offset < 0 {
return Err(InvalidFormat)
}
let major = (version >> 16)
let minor = version & 0xffff
let constants = if constants_offset == 0 {
None
} else {
Some(match parse_math_constants(data, constants_offset) {
Err(err) => return Err(err)
Ok(value) => value
})
}
let glyph_info = if glyph_info_offset == 0 {
None
} else {
let absolute = glyph_info_offset
Some(match parse_math_glyph_info(data, absolute) {
Err(err) => return Err(err)
Ok(value) => value
})
}
let variants = if variants_offset == 0 {
None
} else {
let absolute = variants_offset
Some(match parse_math_variants(data, absolute) {
Err(err) => return Err(err)
Ok(value) => value
})
}
Ok(MathTable::{
major_version: major,
minor_version: minor,
constants,
glyph_info,
variants,
})
}
}
}