// 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 op_charstrings_cff2 : Int = 0x11
///|
let op_fdarray_cff2 : Int = (12 << 8) | 36
///|
let op_fdselect_cff2 : Int = (12 << 8) | 37
///|
let op_vstore_cff2 : Int = 0x18
///|
let op_private_cff2 : Int = 0x12
///|
let op_subrs_cff2 : Int = 0x13
///|
let op_vsindexdict_cff2 : Int = 0x16
///|
pub struct Cff2PrivateDict {
local_subrs : CffIndex?
ivs : Int
} derive(Eq, Show, ToJson)
///|
pub struct Cff2Table {
data : Bytes
top_dict : CffDict
global_subrs : CffIndex
charstrings : CffIndex
fd_array : CffIndex
private_dicts : Array[Cff2PrivateDict]
var_store : @ot_var.ItemVariationStore?
fd_select : Array[Int]?
fdselect_offset : Int
vstore_offset : Int
top_dict_offset : Int
top_dict_size : Int
} derive(Eq, Show, ToJson)
///|
pub fn Cff2Table::parse(data : BytesView) -> Result[Cff2Table, CffError] {
if data.length() < 5 {
return Err(UnexpectedEof)
}
let major = data[0].to_int()
if major != 2 {
return Err(InvalidFormat)
}
let top_dict_offset = read_u8_int(data, 2)
let top_dict_size = read_u16_int(data, 3)
match (top_dict_offset, top_dict_size) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(offset), Ok(size)) => {
if offset < 5 || size < 0 || offset + size > data.length() {
return Err(InvalidFormat)
}
let top_dict_bytes = data[offset:offset + size]
let top_dict = match parse_cff_dict(top_dict_bytes) {
Err(err) => return Err(err)
Ok(value) => value
}
let charstrings_offset = match top_dict.get_int(op_charstrings_cff2) {
None => return Err(InvalidFormat)
Some(value) => value
}
let fdarray_offset = match top_dict.get_int(op_fdarray_cff2) {
None => return Err(InvalidFormat)
Some(value) => value
}
let fdselect_offset = match top_dict.get_int(op_fdselect_cff2) {
None => 0
Some(value) => value
}
let vstore_offset = match top_dict.get_int(op_vstore_cff2) {
None => 0
Some(value) => value
}
if charstrings_offset < 0 || charstrings_offset > data.length() {
return Err(InvalidFormat)
}
if fdarray_offset < 0 || fdarray_offset > data.length() {
return Err(InvalidFormat)
}
if fdselect_offset < 0 || fdselect_offset > data.length() {
return Err(InvalidFormat)
}
if vstore_offset < 0 || vstore_offset > data.length() {
return Err(InvalidFormat)
}
let global_offset = offset + size
let global_subrs = match parse_cff2_index(data, global_offset) {
Err(err) => return Err(err)
Ok(value) => value
}
let charstrings = match parse_cff2_index(data, charstrings_offset) {
Err(err) => return Err(err)
Ok(value) => value
}
let fd_array = match parse_cff2_index(data, fdarray_offset) {
Err(err) => return Err(err)
Ok(value) => value
}
let fd_select =
if fdselect_offset == 0 || charstrings.count == 0 {
None
} else {
match parse_fdselect(data, fdselect_offset, charstrings.count) {
Err(err) => return Err(err)
Ok(value) => Some(value)
}
}
let private_dicts = match parse_fd_array_private_dicts(data, fd_array) {
Err(err) => return Err(err)
Ok(value) => value
}
let var_store =
if vstore_offset == 0 {
None
} else {
match parse_cff2_var_store(data, vstore_offset) {
Err(err) => return Err(err)
Ok(value) => Some(value)
}
}
Ok(Cff2Table::{
data: data.to_bytes(),
top_dict,
global_subrs,
charstrings,
fd_array,
private_dicts,
var_store,
fd_select,
fdselect_offset,
vstore_offset,
top_dict_offset: offset,
top_dict_size: size,
})
}
}
}
///|
pub fn Cff2Table::glyph_bounds(
self : Cff2Table,
glyph : Int,
coords : Array[Int],
) -> Result[CffBounds?, CffError] {
if glyph < 0 || glyph >= self.charstrings.count {
return Err(InvalidFormat)
}
let fd =
match self.fd_select {
None => 0
Some(values) => {
if glyph < 0 || glyph >= values.length() {
return Err(InvalidFormat)
}
values[glyph]
}
}
if fd < 0 || fd >= self.private_dicts.length() {
return Err(InvalidFormat)
}
let priv_dict = self.private_dicts[fd]
let bytes = match self.charstrings.item_bytes(glyph) {
Err(err) => return Err(err)
Ok(value) => value
}
cff2_charstring_bounds(
bytes[:],
Some(self.global_subrs),
priv_dict.local_subrs,
self.var_store,
priv_dict.ivs,
coords,
)
}
///|
pub fn Cff2Table::glyph_count(self : Cff2Table) -> Int {
self.charstrings.count
}
fn cff2_clone_entries(entries : Map[Int, Array[CffNumber]]) -> Map[Int, Array[CffNumber]] {
let next : Map[Int, Array[CffNumber]] = {}
entries.eachi((_, key, value) => {
next[key] = value.copy()
})
next
}
fn cff2_build_index_items(index : CffIndex) -> Result[Array[Bytes], CffError] {
let items : Array[Bytes] = []
for i in 0.. return Err(err)
Ok(value) => value
}
items.push(bytes)
}
Ok(items)
}
fn cff2_replace_entry(
entries : Map[Int, Array[CffNumber]],
op : Int,
values : Array[CffNumber],
) -> Unit {
entries[op] = values
}
fn cff2_remove_entry(entries : Map[Int, Array[CffNumber]], op : Int) -> Unit {
match entries.get(op) {
None => ()
Some(_) => entries.remove(op)
}
}
fn build_private_dict_cff2(
private_dict : CffDict,
local_subrs : CffIndex?,
) -> Result[(Bytes, Bytes?), CffError] {
let entries = cff2_clone_entries(private_dict.entries_map())
cff2_remove_entry(entries, op_subrs_cff2)
match local_subrs {
None => {
let private_bytes = match write_cff_dict(entries) {
Err(err) => return Err(err)
Ok(value) => value
}
Ok((private_bytes, None))
}
Some(subrs) => {
let subr_items = match cff2_build_index_items(subrs) {
Err(err) => return Err(err)
Ok(value) => value
}
let subr_index = match write_cff_index(subr_items, 4) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut dict_bytes = match write_cff_dict(entries) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut done = false
let mut iter = 0
while !done && iter < 5 {
cff2_replace_entry(entries, op_subrs_cff2, [Int(dict_bytes.length())])
let next = match write_cff_dict(entries) {
Err(err) => return Err(err)
Ok(value) => value
}
if next.length() == dict_bytes.length() {
dict_bytes = next
done = true
} else {
dict_bytes = next
}
iter = iter + 1
}
if !done {
return Err(InvalidFormat)
}
Ok((dict_bytes, Some(subr_index)))
}
}
}
fn build_fdselect_format0(fds : Array[Int]) -> Result[Bytes, CffError] {
let bytes : Array[Byte] = []
bytes.push(0)
for fd in fds {
if fd < 0 || fd > 255 {
return Err(InvalidFormat)
}
bytes.push(fd.to_byte())
}
Ok(Bytes::from_array(bytes))
}
fn parse_cff2_private_dict_entries(
data : BytesView,
fd_dict : CffDict,
) -> Result[(CffDict, CffIndex?), CffError] {
let private_size_opt = fd_dict.get_int(op_private_cff2, index=0)
let private_offset_opt = fd_dict.get_int(op_private_cff2, index=1)
let (private_size, private_offset) =
match (private_size_opt, private_offset_opt) {
(None, None) => (0, 0)
(Some(size), Some(offset)) => (size, offset)
_ => return Err(InvalidFormat)
}
if private_size <= 0 {
return Ok((CffDict::{ entries: {} }, None))
}
if private_offset < 0 || private_offset + private_size > data.length() {
return Err(UnexpectedEof)
}
let priv_bytes = data[private_offset:private_offset + private_size]
let priv_dict = match parse_cff_dict(priv_bytes) {
Err(err) => return Err(err)
Ok(value) => value
}
let local_subrs =
match priv_dict.get_int(op_subrs_cff2) {
None => None
Some(subrs_offset) => {
let subrs_base = private_offset + subrs_offset
if subrs_base < 0 || subrs_base > data.length() {
return Err(UnexpectedEof)
}
match parse_cff2_index(data, subrs_base) {
Err(err) => return Err(err)
Ok(value) => Some(value)
}
}
}
Ok((priv_dict, local_subrs))
}
fn build_top_dict_cff2(
base : Map[Int, Array[CffNumber]],
charstrings_offset : Int,
fdarray_offset : Int,
fdselect_offset : Int,
vstore_offset : Int,
) -> Result[Bytes, CffError] {
let entries = cff2_clone_entries(base)
cff2_replace_entry(entries, op_charstrings_cff2, [Int(charstrings_offset)])
cff2_replace_entry(entries, op_fdarray_cff2, [Int(fdarray_offset)])
if fdselect_offset <= 0 {
cff2_remove_entry(entries, op_fdselect_cff2)
} else {
cff2_replace_entry(entries, op_fdselect_cff2, [Int(fdselect_offset)])
}
if vstore_offset <= 0 {
cff2_remove_entry(entries, op_vstore_cff2)
} else {
cff2_replace_entry(entries, op_vstore_cff2, [Int(vstore_offset)])
}
write_cff_dict(entries)
}
fn cff2_var_store_bytes(data : BytesView, offset : Int) -> Result[Bytes?, CffError] {
if offset <= 0 {
return Ok(None)
}
let size = read_u16_int(data, offset)
let size = match size {
Err(err) => return Err(err)
Ok(value) => value
}
if size <= 0 {
return Err(InvalidFormat)
}
if offset + 2 + size > data.length() {
return Err(UnexpectedEof)
}
let bytes = data[offset:offset + 2 + size].to_bytes()
Ok(Some(bytes))
}
///|
pub fn Cff2Table::subset(
self : Cff2Table,
glyphs : Array[Int],
) -> Result[Bytes, CffError] {
if glyphs.is_empty() {
return Err(InvalidFormat)
}
if glyphs[0] != 0 {
return Err(InvalidFormat)
}
let glyph_count = self.charstrings.count
for gid in glyphs {
if gid < 0 || gid >= glyph_count {
return Err(InvalidFormat)
}
}
let char_items : Array[Bytes] = []
for gid in glyphs {
let bytes = match self.charstrings.item_bytes(gid) {
Err(err) => return Err(err)
Ok(value) => value
}
char_items.push(bytes)
}
let charstrings_index = match write_cff_index(char_items, 4) {
Err(err) => return Err(err)
Ok(value) => value
}
let global_items = match cff2_build_index_items(self.global_subrs) {
Err(err) => return Err(err)
Ok(value) => value
}
let global_index = match write_cff_index(global_items, 4) {
Err(err) => return Err(err)
Ok(value) => value
}
let fd_values =
match self.fd_select {
None => None
Some(values) => Some(values)
}
let unique_fds : Array[Int] = []
let fd_seen : Array[Bool] = Array::make(self.fd_array.count, false)
let glyph_fds : Array[Int] = []
for gid in glyphs {
let fd =
match fd_values {
None => 0
Some(values) => {
if gid < 0 || gid >= values.length() {
return Err(InvalidFormat)
}
values[gid]
}
}
glyph_fds.push(fd)
if fd >= 0 && fd < fd_seen.length() && !fd_seen[fd] {
fd_seen[fd] = true
unique_fds.push(fd)
}
}
let fd_map : Array[Int] = Array::make(self.fd_array.count, -1)
for i in 0..= 0 && old_fd < fd_map.length() {
fd_map[old_fd] = i
}
}
let new_glyph_fds : Array[Int] = []
for fd in glyph_fds {
if fd < 0 || fd >= fd_map.length() {
return Err(InvalidFormat)
}
let mapped = fd_map[fd]
if mapped < 0 {
return Err(InvalidFormat)
}
new_glyph_fds.push(mapped)
}
let fdselect_bytes = match build_fdselect_format0(new_glyph_fds) {
Err(err) => return Err(err)
Ok(value) => value
}
let fd_entries : Array[(CffDict, Bytes, Bytes?)] = []
for old_fd in unique_fds {
let fd_bytes = match self.fd_array.item_bytes(old_fd) {
Err(err) => return Err(err)
Ok(value) => value
}
let fd_dict = match parse_cff_dict(fd_bytes[:]) {
Err(err) => return Err(err)
Ok(value) => value
}
let (priv_dict, local_subrs) =
match parse_cff2_private_dict_entries(self.data[:], fd_dict) {
Err(err) => return Err(err)
Ok(value) => value
}
let (priv_bytes, subrs_bytes) = match build_private_dict_cff2(priv_dict, local_subrs) {
Err(err) => return Err(err)
Ok(value) => value
}
fd_entries.push((fd_dict, priv_bytes, subrs_bytes))
}
let vstore_bytes = match cff2_var_store_bytes(self.data[:], self.vstore_offset) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut top_dict_bytes = match write_cff_dict(self.top_dict.entries_map()) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut fdarray_index = match write_cff_index([], 4) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut done = false
let mut iter = 0
while !done && iter < 6 {
let top_offset = 5
let global_offset = top_offset + top_dict_bytes.length()
let charstrings_offset = global_offset + global_index.length()
let fdselect_offset = charstrings_offset + charstrings_index.length()
let fdarray_offset = fdselect_offset + fdselect_bytes.length()
let mut private_offset = fdarray_offset + fdarray_index.length()
let fd_dict_bytes : Array[Bytes] = []
for entry in fd_entries {
let (fd_dict, priv_bytes, subrs_bytes) = entry
let dict_entries = cff2_clone_entries(fd_dict.entries_map())
let priv_size = priv_bytes.length()
cff2_replace_entry(
dict_entries,
op_private_cff2,
[Int(priv_size), Int(private_offset)],
)
let dict_bytes = match write_cff_dict(dict_entries) {
Err(err) => return Err(err)
Ok(value) => value
}
fd_dict_bytes.push(dict_bytes)
private_offset = private_offset + priv_bytes.length()
match subrs_bytes {
None => ()
Some(subrs) => private_offset = private_offset + subrs.length()
}
}
let new_fdarray_index = match write_cff_index(fd_dict_bytes, 4) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut vstore_offset = 0
if vstore_bytes is Some(_) {
vstore_offset = private_offset
}
let new_top_dict = match build_top_dict_cff2(
self.top_dict.entries_map(),
charstrings_offset,
fdarray_offset,
fdselect_offset,
vstore_offset,
) {
Err(err) => return Err(err)
Ok(value) => value
}
if new_top_dict.length() == top_dict_bytes.length() &&
new_fdarray_index.length() == fdarray_index.length() {
top_dict_bytes = new_top_dict
fdarray_index = new_fdarray_index
done = true
} else {
top_dict_bytes = new_top_dict
fdarray_index = new_fdarray_index
}
iter = iter + 1
}
if !done {
return Err(InvalidFormat)
}
let header : Array[Byte] = []
header.push(self.data[0])
header.push(self.data[1])
header.push(5)
push_u16(header, top_dict_bytes.length())
let bytes : Array[Byte] = []
for b in header { bytes.push(b) }
for b in top_dict_bytes { bytes.push(b) }
for b in global_index { bytes.push(b) }
for b in charstrings_index { bytes.push(b) }
for b in fdselect_bytes { bytes.push(b) }
for b in fdarray_index { bytes.push(b) }
for entry in fd_entries {
let (_, priv_bytes, subrs_bytes) = entry
for b in priv_bytes { bytes.push(b) }
match subrs_bytes {
None => ()
Some(subrs) => for b in subrs { bytes.push(b) }
}
}
match vstore_bytes {
None => ()
Some(vstore) => for b in vstore { bytes.push(b) }
}
Ok(Bytes::from_array(bytes))
}
fn parse_fd_array_private_dicts(
data : BytesView,
fd_array : CffIndex,
) -> Result[Array[Cff2PrivateDict], CffError] {
if fd_array.count < 0 {
return Err(InvalidFormat)
}
let values : Array[Cff2PrivateDict] = []
for i in 0.. return Err(err)
Ok(value) => value
}
let dict = match parse_cff_dict(bytes[:]) {
Err(err) => return Err(err)
Ok(value) => value
}
let private_size_opt = dict.get_int(op_private_cff2, index=0)
let private_offset_opt = dict.get_int(op_private_cff2, index=1)
let (private_size, private_offset) =
match (private_size_opt, private_offset_opt) {
(None, None) => (0, 0)
(Some(size), Some(offset)) => (size, offset)
_ => return Err(InvalidFormat)
}
let priv_dict = match parse_cff2_private_dict(data, private_offset, private_size) {
Err(err) => return Err(err)
Ok(value) => value
}
values.push(priv_dict)
}
Ok(values)
}
fn parse_cff2_private_dict(
data : BytesView,
offset : Int,
size : Int,
) -> Result[Cff2PrivateDict, CffError] {
if size <= 0 {
return Ok(Cff2PrivateDict::{ local_subrs: None, ivs: 0 })
}
if offset < 0 || offset + size > data.length() {
return Err(UnexpectedEof)
}
let priv_bytes = data[offset:offset + size]
let dict = match parse_cff_dict(priv_bytes) {
Err(err) => return Err(err)
Ok(value) => value
}
let ivs = match dict.get_int(op_vsindexdict_cff2) {
None => 0
Some(value) => value
}
let local_subrs =
match dict.get_int(op_subrs_cff2) {
None => None
Some(subrs_offset) => {
let subrs_base = offset + subrs_offset
if subrs_base < 0 || subrs_base > data.length() {
return Err(UnexpectedEof)
}
match parse_cff2_index(data, subrs_base) {
Err(err) => return Err(err)
Ok(value) => Some(value)
}
}
}
Ok(Cff2PrivateDict::{ local_subrs, ivs })
}
fn parse_cff2_var_store(
data : BytesView,
offset : Int,
) -> Result[@ot_var.ItemVariationStore, CffError] {
let size = read_u16_int(data, offset)
let size = match size {
Err(err) => return Err(err)
Ok(value) => value
}
if size <= 0 {
return Err(InvalidFormat)
}
if offset + 2 + size > data.length() {
return Err(UnexpectedEof)
}
let bytes = data[offset + 2:offset + 2 + size]
match @ot_var.ItemVariationStore::parse(bytes) {
Err(err) => Err(map_var_error(err))
Ok(value) => Ok(value)
}
}
fn map_var_error(err : @ot_var.VarError) -> CffError {
match err {
@ot_var.VarError::UnexpectedEof => UnexpectedEof
@ot_var.VarError::InvalidFormat => InvalidFormat
}
}
fn parse_fdselect(
data : BytesView,
offset : Int,
glyph_count : Int,
) -> Result[Array[Int], CffError] {
if glyph_count < 0 {
return Err(InvalidFormat)
}
let format = read_u8_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) =>
if format == 0 {
if offset + 1 + glyph_count > data.length() {
return Err(UnexpectedEof)
}
let values : Array[Int] = []
for i in 0.. Err(err)
Ok(range_count) => {
if range_count < 0 {
return Err(InvalidFormat)
}
let mut pos = offset + 3
let starts : Array[Int] = []
let fds : Array[Int] = []
for _ in 0.. return Err(err)
(_, Err(err)) => return Err(err)
(Ok(start), Ok(fd)) => {
starts.push(start)
fds.push(fd)
}
}
pos = pos + 3
}
let sentinel = read_u16_int(data, pos)
let sentinel = match sentinel {
Err(err) => return Err(err)
Ok(value) => value
}
let values : Array[Int] = Array::make(glyph_count, 0)
for i in 0.. Err(err)
Ok(range_count) => {
if range_count < 0 {
return Err(InvalidFormat)
}
let mut pos = offset + 5
let starts : Array[Int] = []
let fds : Array[Int] = []
for _ in 0.. return Err(err)
(_, Err(err)) => return Err(err)
(Ok(start), Ok(fd)) => {
starts.push(start)
fds.push(fd)
}
}
pos = pos + 6
}
let sentinel = read_u32_int(data, pos)
let sentinel = match sentinel {
Err(err) => return Err(err)
Ok(value) => value
}
let values : Array[Int] = Array::make(glyph_count, 0)
for i in 0..