// 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.
///|
pub struct GdefHeader {
version : UInt
glyph_class_def_offset : Int?
attach_list_offset : Int?
lig_caret_list_offset : Int?
mark_attach_class_def_offset : Int?
mark_glyph_sets_def_offset : Int?
} derive(Show, ToJson)
///|
pub struct GdefTable {
data : BytesView
header : GdefHeader
} derive(Show, ToJson)
///|
pub fn GdefTable::parse(blob : @blob.Blob) -> Result[GdefTable, OtLayoutError] {
let data = blob.as_view()
let version = read_u32(data, 0)
match version {
Err(err) => Err(err)
Ok(version) => {
if version < 0x00010000U {
return Err(InvalidFormat)
}
let header_len = if version >= 0x00010002U { 14 } else { 12 }
match check_range(data, 0, header_len) {
Err(err) => return Err(err)
Ok(_) => ()
}
let glyph_class_def_offset = read_u16_int(data, 4)
let attach_list_offset = read_u16_int(data, 6)
let lig_caret_list_offset = read_u16_int(data, 8)
let mark_attach_class_def_offset = read_u16_int(data, 10)
match (
glyph_class_def_offset,
attach_list_offset,
lig_caret_list_offset,
mark_attach_class_def_offset,
) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(
Ok(glyph_class_def_offset),
Ok(attach_list_offset),
Ok(lig_caret_list_offset),
Ok(mark_attach_class_def_offset),
) => {
let mark_glyph_sets_def_offset =
if version >= 0x00010002U {
match read_u16_int(data, 12) {
Err(err) => return Err(err)
Ok(value) => if value == 0 { None } else { Some(value) }
}
} else {
None
}
let header = GdefHeader::{
version,
glyph_class_def_offset: if glyph_class_def_offset == 0 {
None
} else {
Some(glyph_class_def_offset)
},
attach_list_offset: if attach_list_offset == 0 {
None
} else {
Some(attach_list_offset)
},
lig_caret_list_offset: if lig_caret_list_offset == 0 {
None
} else {
Some(lig_caret_list_offset)
},
mark_attach_class_def_offset: if mark_attach_class_def_offset == 0 {
None
} else {
Some(mark_attach_class_def_offset)
},
mark_glyph_sets_def_offset,
}
Ok(GdefTable::{ data, header })
}
}
}
}
}
///|
pub fn GdefTable::header(self : GdefTable) -> GdefHeader {
self.header
}
///|
pub fn GdefTable::glyph_class(
self : GdefTable,
glyph : UInt,
) -> Result[Int, OtLayoutError] {
match self.header.glyph_class_def_offset {
None => Ok(0)
Some(offset) => class_def_value(self.data, offset, glyph)
}
}
///|
pub fn GdefTable::mark_attach_class(
self : GdefTable,
glyph : UInt,
) -> Result[Int, OtLayoutError] {
match self.header.mark_attach_class_def_offset {
None => Ok(0)
Some(offset) => class_def_value(self.data, offset, glyph)
}
}
///|
pub fn GdefTable::mark_glyph_set_contains(
self : GdefTable,
set_index : Int,
glyph : UInt,
) -> Result[Bool, OtLayoutError] {
match self.header.mark_glyph_sets_def_offset {
None => Ok(false)
Some(offset) => {
if offset < 0 || offset + 4 > self.data.length() {
return Err(UnexpectedEof)
}
let format = read_u16_int(self.data, offset)
let set_count = read_u16_int(self.data, offset + 2)
match (format, set_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(format), Ok(set_count)) => {
if format != 1 || set_count <= 0 {
return Err(InvalidFormat)
}
if set_index < 0 || set_index >= set_count {
return Err(InvalidFormat)
}
let list_base = offset + 4
if list_base < 0 || list_base + set_count * 2 > self.data.length() {
return Err(UnexpectedEof)
}
let cov_offset = read_u16_int(self.data, list_base + set_index * 2)
match cov_offset {
Err(err) => Err(err)
Ok(cov_offset) => {
if cov_offset == 0 {
return Err(InvalidFormat)
}
let cov_base = offset + cov_offset
let covered = coverage_index(self.data, cov_base, glyph)
match covered {
Err(err) => Err(err)
Ok(None) => Ok(false)
Ok(Some(_)) => Ok(true)
}
}
}
}
}
}
}
}