// 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.
///|
/// Value record for GPOS adjustments.
pub struct ValueRecord {
x_placement : Int
y_placement : Int
x_advance : Int
y_advance : Int
} derive(Eq, Show, ToJson)
///|
/// Pair adjustment result.
pub struct PairAdjust {
first : ValueRecord
second : ValueRecord
} derive(Eq, Show, ToJson)
///|
fn value_record_zero() -> ValueRecord {
ValueRecord::{ x_placement: 0, y_placement: 0, x_advance: 0, y_advance: 0 }
}
///|
fn add_value_record(a : ValueRecord, b : ValueRecord) -> ValueRecord {
ValueRecord::{
x_placement: a.x_placement + b.x_placement,
y_placement: a.y_placement + b.y_placement,
x_advance: a.x_advance + b.x_advance,
y_advance: a.y_advance + b.y_advance,
}
}
///|
fn sum_advances_between(
deltas : Array[ValueRecord],
advances_x : ArrayView[Int],
advances_y : ArrayView[Int],
start_index : Int,
end_index : Int,
) -> (Int, Int) {
if end_index <= start_index {
return (0, 0)
}
let use_advances_x = advances_x.length() == deltas.length()
let use_advances_y = advances_y.length() == deltas.length()
let mut x = 0
let mut y = 0
for i in start_index.. Int {
if component_count <= 0 {
return 0
}
if clusters.length() == 0 {
return 0
}
if ligature_index < 0 || ligature_index >= clusters.length() ||
mark_index < 0 || mark_index >= clusters.length() {
return 0
}
let diff = clusters[mark_index] - clusters[ligature_index] - 1
let mut component_index = diff
if component_index < 0 {
component_index = 0
}
if component_index >= component_count {
component_index = component_count - 1
}
component_index
}
///|
/// Compute GPOS positioning deltas for a glyph sequence.
pub fn GposTable::position_deltas(
self : GposTable,
glyphs : ArrayView[UInt],
) -> Result[Array[ValueRecord], OtLayoutError] {
let layout = self.layout
self.position_deltas_with_lookups(glyphs, layout.lookup_list.offsets[:])
}
///|
pub fn GposTable::position_deltas_with_lookups(
self : GposTable,
glyphs : ArrayView[UInt],
lookup_offsets : ArrayView[Int],
gdef? : GdefTable,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Array[ValueRecord], OtLayoutError] {
let deltas : Array[ValueRecord] = Array::make(
glyphs.length(),
value_record_zero(),
)
let data = self.layout.data
let gdef = gdef
let clusters = clusters
let advances_x = advances_x
let advances_y = advances_y
for lookup_offset in lookup_offsets {
let parsed = parse_lookup(data, lookup_offset, 9)
match parsed {
Err(err) => return Err(err)
Ok((lookup_type, lookup_flag, mark_filtering_set, subtable_offsets)) => {
if lookup_type == 1 {
for subtable_offset in subtable_offsets {
let res = apply_single_pos_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
} else if lookup_type == 2 {
for subtable_offset in subtable_offsets {
let res = apply_pair_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
} else if lookup_type == 3 {
for subtable_offset in subtable_offsets {
let res = apply_cursive_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
} else if lookup_type == 4 {
for subtable_offset in subtable_offsets {
let res = apply_mark_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
advances_x=advances_x,
advances_y=advances_y,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
} else if lookup_type == 7 {
let lookup_list_offsets = self.layout.lookup_list.offsets[:]
for subtable_offset in subtable_offsets {
let res = apply_context_pos_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
} else if lookup_type == 8 {
let lookup_list_offsets = self.layout.lookup_list.offsets[:]
for subtable_offset in subtable_offsets {
let res = apply_chain_pos_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
} else if lookup_type == 5 {
for subtable_offset in subtable_offsets {
let res = apply_mark_to_ligature_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
} else if lookup_type == 6 {
for subtable_offset in subtable_offsets {
let res = apply_mark_to_mark_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
advances_x=advances_x,
advances_y=advances_y,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
} else {
continue
}
}
}
}
Ok(deltas)
}
///|
/// Compute pair adjustment deltas for a glyph sequence.
pub fn GposTable::pair_adjust_deltas(
self : GposTable,
glyphs : ArrayView[UInt],
) -> Result[Array[ValueRecord], OtLayoutError] {
let layout = self.layout
self.pair_adjust_deltas_with_lookups(glyphs, layout.lookup_list.offsets[:])
}
///|
pub fn GposTable::pair_adjust_deltas_with_lookups(
self : GposTable,
glyphs : ArrayView[UInt],
lookup_offsets : ArrayView[Int],
gdef? : GdefTable,
) -> Result[Array[ValueRecord], OtLayoutError] {
let deltas : Array[ValueRecord] = Array::make(
glyphs.length(),
value_record_zero(),
)
let data = self.layout.data
let gdef = gdef
for lookup_offset in lookup_offsets {
let parsed = parse_lookup(data, lookup_offset, 9)
match parsed {
Err(err) => return Err(err)
Ok((lookup_type, lookup_flag, mark_filtering_set, subtable_offsets)) => {
if lookup_type != 2 {
continue
}
for subtable_offset in subtable_offsets {
let res = apply_pair_subtable(
data,
subtable_offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
match res {
Err(err) => return Err(err)
Ok(_) => ()
}
}
}
}
}
Ok(deltas)
}
///|
fn apply_pair_format1(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Unit, OtLayoutError] {
if glyphs.length() < 2 {
return Ok(())
}
let value_format2 = read_u16_int(data, offset + 6)
let advance_on_second = match value_format2 {
Err(err) => return Err(err)
Ok(value_format2) => value_format2 != 0
}
let mut i = 0
while i < glyphs.length() - 1 {
let input_indices = collect_forward_indices(
glyphs,
i,
2,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => {
i = i + 1
continue
}
Ok(Some(indices)) => indices
}
let first = glyphs[indices[0]]
let second = glyphs[indices[1]]
let adjust = pair_adjust_format1(data, offset, first, second)
match adjust {
Err(err) => return Err(err)
Ok(None) => {
i = i + 1
continue
}
Ok(Some(adjust)) => {
deltas[indices[0]] = add_value_record(deltas[indices[0]], adjust.first)
deltas[indices[1]] = add_value_record(deltas[indices[1]], adjust.second)
}
}
if !advance_on_second {
i = i + 1
continue
}
let mut next_index = indices[indices.length() - 1] + 1
if next_index <= i {
next_index = i + 1
}
if next_index > glyphs.length() {
next_index = glyphs.length()
}
i = next_index
}
Ok(())
}
///|
fn apply_pair_format2(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Unit, OtLayoutError] {
if glyphs.length() < 2 {
return Ok(())
}
let value_format2 = read_u16_int(data, offset + 6)
let advance_on_second = match value_format2 {
Err(err) => return Err(err)
Ok(value_format2) => value_format2 != 0
}
let mut i = 0
while i < glyphs.length() - 1 {
let input_indices = collect_forward_indices(
glyphs,
i,
2,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => {
i = i + 1
continue
}
Ok(Some(indices)) => indices
}
let first = glyphs[indices[0]]
let second = glyphs[indices[1]]
let adjust = pair_adjust_format2(data, offset, first, second)
match adjust {
Err(err) => return Err(err)
Ok(None) => {
i = i + 1
continue
}
Ok(Some(adjust)) => {
deltas[indices[0]] = add_value_record(deltas[indices[0]], adjust.first)
deltas[indices[1]] = add_value_record(deltas[indices[1]], adjust.second)
}
}
if !advance_on_second {
i = i + 1
continue
}
let mut next_index = indices[indices.length() - 1] + 1
if next_index <= i {
next_index = i + 1
}
if next_index > glyphs.length() {
next_index = glyphs.length()
}
i = next_index
}
Ok(())
}
///|
fn apply_pair_subtable(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Unit, OtLayoutError] {
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
apply_pair_format1(
data,
offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
} else if format == 2 {
apply_pair_format2(
data,
offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
} else {
Ok(())
}
}
}
///|
fn apply_context_pos_subtable(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if offset < 0 || offset + 2 > data.length() {
return Err(UnexpectedEof)
}
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
apply_context_pos_subtable_format1(
data,
offset,
glyphs,
deltas,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
} else if format == 2 {
apply_context_pos_subtable_format2(
data,
offset,
glyphs,
deltas,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
} else if format == 3 {
apply_context_pos_subtable_format3(
data,
offset,
glyphs,
deltas,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
} else {
Err(InvalidFormat)
}
}
}
///|
fn apply_context_pos_subtable_format1(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let set_count = read_u16_int(data, offset + 4)
match (coverage_offset, set_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(set_count)) => {
if coverage_offset == 0 || set_count <= 0 {
return Err(InvalidFormat)
}
let coverage_base = offset + coverage_offset
let set_base = offset + 6
if set_base < 0 || set_base + set_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mut changed = false
let mut i = 0
while i < glyphs.length() {
let glyph = glyphs[i]
let ignored = should_ignore_glyph(
glyph,
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => {
i = i + 1
continue
}
Ok(false) => ()
}
let index = coverage_index(data, coverage_base, glyph)
match index {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(index)) => {
if index < 0 || index >= set_count {
return Err(InvalidFormat)
}
let rule_set_offset = read_u16_int(data, set_base + index * 2)
match rule_set_offset {
Err(err) => return Err(err)
Ok(rule_set_offset) => {
if rule_set_offset == 0 {
return Err(InvalidFormat)
}
let rule_set_base = offset + rule_set_offset
if rule_set_base < 0 || rule_set_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let rule_count = read_u16_int(data, rule_set_base)
match rule_count {
Err(err) => return Err(err)
Ok(rule_count) => {
if rule_count <= 0 {
return Err(InvalidFormat)
}
let rule_list_base = rule_set_base + 2
if rule_list_base < 0 ||
rule_list_base + rule_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mut advance = i + 1
for r in 0.. return Err(err)
Ok(rule_offset) => {
if rule_offset == 0 {
return Err(InvalidFormat)
}
let rule_base = rule_set_base + rule_offset
let result = match apply_context_pos_rule(
data,
rule_base,
glyphs,
deltas,
i,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
if result.matched {
if result.changed {
changed = true
}
advance = result.next_index
if advance <= i {
advance = i + 1
}
if advance > glyphs.length() {
advance = glyphs.length()
}
break
}
}
}
}
i = advance
continue
}
}
}
}
}
}
i = i + 1
}
Ok(changed)
}
}
}
///|
fn apply_context_pos_subtable_format2(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if offset < 0 || offset + 8 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let class_def_offset = read_u16_int(data, offset + 4)
let class_set_count = read_u16_int(data, offset + 6)
match (coverage_offset, class_def_offset, class_set_count) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(class_def_offset), Ok(class_set_count)) => {
if coverage_offset == 0 || class_def_offset == 0 || class_set_count <= 0 {
return Err(InvalidFormat)
}
let coverage_base = offset + coverage_offset
let class_def_base = offset + class_def_offset
let class_set_base = offset + 8
if class_set_base < 0 ||
class_set_base + class_set_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mut changed = false
let mut i = 0
while i < glyphs.length() {
let glyph = glyphs[i]
let ignored = should_ignore_glyph(
glyph,
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => {
i = i + 1
continue
}
Ok(false) => ()
}
let covered = coverage_index(data, coverage_base, glyph)
match covered {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(_)) => {
let class_value = class_def_value(data, class_def_base, glyph)
match class_value {
Err(err) => return Err(err)
Ok(class_value) => {
if class_value < 0 || class_value >= class_set_count {
return Err(InvalidFormat)
}
let class_set_offset = read_u16_int(
data,
class_set_base + class_value * 2,
)
match class_set_offset {
Err(err) => return Err(err)
Ok(class_set_offset) => {
if class_set_offset == 0 {
return Err(InvalidFormat)
}
let rule_set_base = offset + class_set_offset
if rule_set_base < 0 || rule_set_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let rule_count = read_u16_int(data, rule_set_base)
match rule_count {
Err(err) => return Err(err)
Ok(rule_count) => {
if rule_count <= 0 {
return Err(InvalidFormat)
}
let rule_list_base = rule_set_base + 2
if rule_list_base < 0 ||
rule_list_base + rule_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mut advance = i + 1
for r in 0.. return Err(err)
Ok(rule_offset) => {
if rule_offset == 0 {
return Err(InvalidFormat)
}
let rule_base = rule_set_base + rule_offset
let result = match apply_context_pos_class_rule(
data,
rule_base,
glyphs,
deltas,
i,
class_def_base,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
if result.matched {
if result.changed {
changed = true
}
advance = result.next_index
if advance <= i {
advance = i + 1
}
if advance > glyphs.length() {
advance = glyphs.length()
}
break
}
}
}
}
i = advance
continue
}
}
}
}
}
}
}
}
i = i + 1
}
Ok(changed)
}
}
}
///|
fn apply_context_pos_subtable_format3(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let glyph_count = read_u16_int(data, offset + 2)
let pos_count = read_u16_int(data, offset + 4)
match (glyph_count, pos_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(glyph_count), Ok(pos_count)) => {
if glyph_count <= 0 || pos_count < 0 {
return Err(InvalidFormat)
}
let coverage_list_base = offset + 6
if coverage_list_base < 0 ||
coverage_list_base + glyph_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let record_base = coverage_list_base + glyph_count * 2
let mut changed = false
let mut i = 0
while i < glyphs.length() {
let input_indices = collect_forward_indices(
glyphs,
i,
glyph_count,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => {
i = i + 1
continue
}
Ok(Some(indices)) => indices
}
let mut matched = true
for j in 0.. return Err(err)
Ok(cov_offset) => {
if cov_offset == 0 {
return Err(InvalidFormat)
}
let cov_base = offset + cov_offset
let covered = coverage_index(data, cov_base, glyphs[indices[j]])
match covered {
Err(err) => return Err(err)
Ok(None) => {
matched = false
break
}
Ok(Some(_)) => ()
}
}
}
}
if matched {
let applied = match apply_pos_lookup_records(
data,
record_base,
pos_count,
glyph_count,
glyphs,
deltas,
indices[0],
lookup_list_offsets,
Some(indices),
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
if applied {
changed = true
}
let mut advance = indices[indices.length() - 1] + 1
if advance <= i {
advance = i + 1
}
if advance > glyphs.length() {
advance = glyphs.length()
}
i = advance
continue
}
i = i + 1
}
Ok(changed)
}
}
}
///|
priv struct PosApplyResult {
matched : Bool
changed : Bool
next_index : Int
}
///|
fn pos_no_match(index : Int) -> PosApplyResult {
PosApplyResult::{ matched: false, changed: false, next_index: index + 1 }
}
///|
fn apply_context_pos_class_rule(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
class_def_base : Int,
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[PosApplyResult, OtLayoutError] {
if offset < 0 || offset + 4 > data.length() {
return Err(UnexpectedEof)
}
let glyph_count = read_u16_int(data, offset)
let pos_count = read_u16_int(data, offset + 2)
match (glyph_count, pos_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(glyph_count), Ok(pos_count)) => {
if glyph_count <= 0 || pos_count < 0 {
return Err(InvalidFormat)
}
let input_indices = collect_forward_indices(
glyphs,
index,
glyph_count,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(pos_no_match(index))
Ok(Some(indices)) => indices
}
let class_list_base = offset + 4
if class_list_base < 0 ||
class_list_base + (glyph_count - 1) * 2 > data.length() {
return Err(UnexpectedEof)
}
for i in 0..<(glyph_count - 1) {
let expected = read_u16_int(data, class_list_base + i * 2)
match expected {
Err(err) => return Err(err)
Ok(expected) => {
let actual = class_def_value(
data,
class_def_base,
glyphs[indices[i + 1]],
)
match actual {
Err(InvalidFormat) => return Ok(pos_no_match(index))
Err(err) => return Err(err)
Ok(actual) => if actual != expected {
return Ok(pos_no_match(index))
}
}
}
}
}
let record_base = class_list_base + (glyph_count - 1) * 2
let changed = match apply_pos_lookup_records(
data,
record_base,
pos_count,
glyph_count,
glyphs,
deltas,
index,
lookup_list_offsets,
Some(indices),
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut next_index = indices[indices.length() - 1] + 1
if next_index <= index {
next_index = index + 1
}
if next_index > glyphs.length() {
next_index = glyphs.length()
}
Ok(PosApplyResult::{ matched: true, changed, next_index })
}
}
}
///|
fn apply_pos_lookup_records(
data : BytesView,
record_base : Int,
pos_count : Int,
glyph_count : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
lookup_list_offsets : ArrayView[Int],
input_indices : Array[Int]?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if pos_count < 0 {
return Err(InvalidFormat)
}
match input_indices {
None => ()
Some(indices) => if indices.length() < glyph_count { return Err(InvalidFormat) }
}
if record_base < 0 || record_base + pos_count * 4 > data.length() {
return Err(UnexpectedEof)
}
let mut changed = false
for i in 0.. return Err(err)
(_, Err(err)) => return Err(err)
(Ok(seq_index), Ok(lookup_index)) => {
if seq_index < 0 || seq_index >= glyph_count {
return Err(InvalidFormat)
}
if lookup_index < 0 || lookup_index >= lookup_list_offsets.length() {
return Err(InvalidFormat)
}
let target = match input_indices {
None => index + seq_index
Some(indices) => indices[seq_index]
}
if target < 0 || target >= glyphs.length() {
return Err(InvalidFormat)
}
let lookup_offset = lookup_list_offsets[lookup_index]
let did_change = match apply_pos_lookup_at(
data,
lookup_offset,
glyphs,
deltas,
target,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
if did_change {
changed = true
}
}
}
}
Ok(changed)
}
///|
fn apply_context_pos_rule(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[PosApplyResult, OtLayoutError] {
if offset < 0 || offset + 4 > data.length() {
return Err(UnexpectedEof)
}
let glyph_count = read_u16_int(data, offset)
let pos_count = read_u16_int(data, offset + 2)
match (glyph_count, pos_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(glyph_count), Ok(pos_count)) => {
if glyph_count <= 0 || pos_count < 0 {
return Err(InvalidFormat)
}
let input_indices = collect_forward_indices(
glyphs,
index,
glyph_count,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(pos_no_match(index))
Ok(Some(indices)) => indices
}
let input_base = offset + 4
if input_base < 0 || input_base + (glyph_count - 1) * 2 > data.length() {
return Err(UnexpectedEof)
}
for i in 0..<(glyph_count - 1) {
let expected = read_u16_int(data, input_base + i * 2)
match expected {
Err(err) => return Err(err)
Ok(expected) => {
let actual = glyphs[indices[i + 1]]
if expected != u16_to_int(actual) {
return Ok(pos_no_match(index))
}
}
}
}
let record_base = input_base + (glyph_count - 1) * 2
let changed = match apply_pos_lookup_records(
data,
record_base,
pos_count,
glyph_count,
glyphs,
deltas,
index,
lookup_list_offsets,
Some(indices),
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut next_index = indices[indices.length() - 1] + 1
if next_index <= index {
next_index = index + 1
}
if next_index > glyphs.length() {
next_index = glyphs.length()
}
Ok(PosApplyResult::{ matched: true, changed, next_index })
}
}
}
///|
fn apply_chain_pos_subtable(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if offset < 0 || offset + 2 > data.length() {
return Err(UnexpectedEof)
}
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
apply_chain_pos_subtable_format1(
data,
offset,
glyphs,
deltas,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
} else if format == 2 {
apply_chain_pos_subtable_format2(
data,
offset,
glyphs,
deltas,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
} else if format == 3 {
apply_chain_pos_subtable_format3(
data,
offset,
glyphs,
deltas,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
} else {
Err(InvalidFormat)
}
}
}
///|
fn apply_chain_pos_subtable_format1(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let set_count = read_u16_int(data, offset + 4)
match (coverage_offset, set_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(set_count)) => {
if coverage_offset == 0 || set_count <= 0 {
return Err(InvalidFormat)
}
let coverage_base = offset + coverage_offset
let set_base = offset + 6
if set_base < 0 || set_base + set_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mut changed = false
let mut i = 0
while i < glyphs.length() {
let glyph = glyphs[i]
let ignored = should_ignore_glyph(
glyph,
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => {
i = i + 1
continue
}
Ok(false) => ()
}
let index = coverage_index(data, coverage_base, glyph)
match index {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(index)) => {
if index < 0 || index >= set_count {
return Err(InvalidFormat)
}
let rule_set_offset = read_u16_int(data, set_base + index * 2)
match rule_set_offset {
Err(err) => return Err(err)
Ok(rule_set_offset) => {
if rule_set_offset == 0 {
return Err(InvalidFormat)
}
let rule_set_base = offset + rule_set_offset
if rule_set_base < 0 || rule_set_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let rule_count = read_u16_int(data, rule_set_base)
match rule_count {
Err(err) => return Err(err)
Ok(rule_count) => {
if rule_count <= 0 {
return Err(InvalidFormat)
}
let rule_list_base = rule_set_base + 2
if rule_list_base < 0 ||
rule_list_base + rule_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mut advance = i + 1
for r in 0.. return Err(err)
Ok(rule_offset) => {
if rule_offset == 0 {
return Err(InvalidFormat)
}
let rule_base = rule_set_base + rule_offset
let result = match apply_chain_pos_rule(
data,
rule_base,
glyphs,
deltas,
i,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
if result.matched {
if result.changed {
changed = true
}
advance = result.next_index
if advance <= i {
advance = i + 1
}
if advance > glyphs.length() {
advance = glyphs.length()
}
break
}
}
}
}
i = advance
continue
}
}
}
}
}
}
i = i + 1
}
Ok(changed)
}
}
}
///|
fn apply_chain_pos_subtable_format2(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if offset < 0 || offset + 12 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let backtrack_class_def_offset = read_u16_int(data, offset + 4)
let input_class_def_offset = read_u16_int(data, offset + 6)
let lookahead_class_def_offset = read_u16_int(data, offset + 8)
let class_set_count = read_u16_int(data, offset + 10)
match (
coverage_offset,
backtrack_class_def_offset,
input_class_def_offset,
lookahead_class_def_offset,
class_set_count,
) {
(Err(err), _, _, _, _) => Err(err)
(_, Err(err), _, _, _) => Err(err)
(_, _, Err(err), _, _) => Err(err)
(_, _, _, Err(err), _) => Err(err)
(_, _, _, _, Err(err)) => Err(err)
(
Ok(coverage_offset),
Ok(backtrack_class_def_offset),
Ok(input_class_def_offset),
Ok(lookahead_class_def_offset),
Ok(class_set_count),
) => {
if coverage_offset == 0 || backtrack_class_def_offset == 0 ||
input_class_def_offset == 0 || lookahead_class_def_offset == 0 {
return Ok(false)
}
if class_set_count <= 0 {
return Ok(false)
}
let coverage_base = offset + coverage_offset
let backtrack_class_def_base = offset + backtrack_class_def_offset
let input_class_def_base = offset + input_class_def_offset
let lookahead_class_def_base = offset + lookahead_class_def_offset
let class_set_base = offset + 12
if class_set_base < 0 ||
class_set_base + class_set_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mut changed = false
let mut i = 0
while i < glyphs.length() {
let glyph = glyphs[i]
let ignored = should_ignore_glyph(
glyph,
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => {
i = i + 1
continue
}
Ok(false) => ()
}
let covered = coverage_index(data, coverage_base, glyph)
match covered {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(_)) => {
let class_value = class_def_value(data, input_class_def_base, glyph)
match class_value {
Err(err) => return Err(err)
Ok(class_value) => {
if class_value < 0 || class_value >= class_set_count {
i = i + 1
continue
}
let class_set_offset = read_u16_int(
data,
class_set_base + class_value * 2,
)
match class_set_offset {
Err(err) => return Err(err)
Ok(class_set_offset) => {
if class_set_offset == 0 {
i = i + 1
continue
}
let rule_set_base = offset + class_set_offset
if rule_set_base < 0 || rule_set_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let rule_count = read_u16_int(data, rule_set_base)
match rule_count {
Err(err) => return Err(err)
Ok(rule_count) => {
if rule_count <= 0 {
i = i + 1
continue
}
let rule_list_base = rule_set_base + 2
if rule_list_base < 0 ||
rule_list_base + rule_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mut advance = i + 1
for r in 0.. return Err(err)
Ok(rule_offset) => {
if rule_offset == 0 {
continue
}
let rule_base = rule_set_base + rule_offset
let result = match apply_chain_pos_class_rule(
data,
rule_base,
glyphs,
deltas,
i,
backtrack_class_def_base,
input_class_def_base,
lookahead_class_def_base,
lookup_list_offsets,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
if result.matched {
if result.changed {
changed = true
}
advance = result.next_index
if advance <= i {
advance = i + 1
}
if advance > glyphs.length() {
advance = glyphs.length()
}
break
}
}
}
}
i = advance
continue
}
}
}
}
}
}
}
}
i = i + 1
}
Ok(changed)
}
}
}
///|
fn apply_chain_pos_subtable_format3(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if offset < 0 || offset + 4 > data.length() {
return Err(UnexpectedEof)
}
let backtrack_count = read_u16_int(data, offset + 2)
match backtrack_count {
Err(err) => Err(err)
Ok(backtrack_count) => {
if backtrack_count < 0 {
return Err(InvalidFormat)
}
let mut cursor = offset + 4
if cursor < 0 || cursor + backtrack_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let backtrack_bases : Array[Int] = []
for i in 0.. return Err(err)
Ok(cov_offset) => {
if cov_offset == 0 {
return Err(InvalidFormat)
}
let base = offset + cov_offset
if base < 0 || base >= data.length() {
return Err(UnexpectedEof)
}
backtrack_bases.push(base)
}
}
}
cursor = cursor + backtrack_count * 2
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let input_count = read_u16_int(data, cursor)
match input_count {
Err(err) => Err(err)
Ok(input_count) => {
cursor = cursor + 2
if input_count <= 0 {
return Err(InvalidFormat)
}
if cursor < 0 || cursor + input_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let input_bases : Array[Int] = []
for i in 0.. return Err(err)
Ok(cov_offset) => {
if cov_offset == 0 {
return Err(InvalidFormat)
}
let base = offset + cov_offset
if base < 0 || base >= data.length() {
return Err(UnexpectedEof)
}
input_bases.push(base)
}
}
}
cursor = cursor + input_count * 2
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let lookahead_count = read_u16_int(data, cursor)
match lookahead_count {
Err(err) => Err(err)
Ok(lookahead_count) => {
cursor = cursor + 2
if lookahead_count < 0 {
return Err(InvalidFormat)
}
if cursor < 0 || cursor + lookahead_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let lookahead_bases : Array[Int] = []
for i in 0.. return Err(err)
Ok(cov_offset) => {
if cov_offset == 0 {
return Err(InvalidFormat)
}
let base = offset + cov_offset
if base < 0 || base >= data.length() {
return Err(UnexpectedEof)
}
lookahead_bases.push(base)
}
}
}
cursor = cursor + lookahead_count * 2
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let pos_count = read_u16_int(data, cursor)
match pos_count {
Err(err) => Err(err)
Ok(pos_count) => {
cursor = cursor + 2
if pos_count < 0 {
return Err(InvalidFormat)
}
let record_base = cursor
let mut changed = false
let mut i = 0
while i < glyphs.length() {
let input_indices = collect_forward_indices(
glyphs,
i,
input_count,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => {
i = i + 1
continue
}
Ok(Some(indices)) => indices
}
let backtrack_indices = collect_backward_indices(
glyphs,
indices[0],
backtrack_bases.length(),
lookup_flag,
gdef,
mark_filtering_set,
)
let backtrack = match backtrack_indices {
Err(err) => return Err(err)
Ok(None) => {
i = i + 1
continue
}
Ok(Some(values)) => values
}
let lookahead_indices = if lookahead_bases.is_empty() {
Ok(Some([]))
} else {
collect_forward_indices(
glyphs,
indices[input_count - 1] + 1,
lookahead_bases.length(),
lookup_flag,
gdef,
mark_filtering_set,
allow_ignored_start=true,
)
}
let lookahead = match lookahead_indices {
Err(err) => return Err(err)
Ok(None) => {
i = i + 1
continue
}
Ok(Some(values)) => values
}
let mut matched = true
for j in 0.. return Err(err)
Ok(None) => {
matched = false
break
}
Ok(Some(_)) => ()
}
}
if matched {
for j in 0.. return Err(err)
Ok(None) => {
matched = false
break
}
Ok(Some(_)) => ()
}
}
}
if matched {
for j in 0.. return Err(err)
Ok(None) => {
matched = false
break
}
Ok(Some(_)) => ()
}
}
}
if matched {
let applied = match apply_pos_lookup_records(
data,
record_base,
pos_count,
input_count,
glyphs,
deltas,
indices[0],
lookup_list_offsets,
Some(indices),
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
if applied {
changed = true
}
let mut advance = indices[indices.length() - 1] + 1
if advance <= i {
advance = i + 1
}
if advance > glyphs.length() {
advance = glyphs.length()
}
i = advance
continue
}
i = i + 1
}
Ok(changed)
}
}
}
}
}
}
}
}
}
///|
fn apply_chain_pos_class_rule(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
backtrack_class_def_base : Int,
input_class_def_base : Int,
lookahead_class_def_base : Int,
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[PosApplyResult, OtLayoutError] {
if offset < 0 || offset + 2 > data.length() {
return Err(UnexpectedEof)
}
let backtrack_count = read_u16_int(data, offset)
match backtrack_count {
Err(err) => Err(err)
Ok(backtrack_count) => {
if backtrack_count < 0 {
return Err(InvalidFormat)
}
let mut cursor = offset + 2
if cursor < 0 || cursor + backtrack_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let backtrack : Array[Int] = []
for _ in 0.. return Err(err)
Ok(value) => backtrack.push(value)
}
}
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let input_count = read_u16_int(data, cursor)
match input_count {
Err(err) => Err(err)
Ok(input_count) => {
cursor = cursor + 2
if input_count <= 0 {
return Err(InvalidFormat)
}
if index + input_count > glyphs.length() {
return Ok(pos_no_match(index))
}
if cursor < 0 || cursor + (input_count - 1) * 2 > data.length() {
return Err(UnexpectedEof)
}
let input : Array[Int] = []
for _ in 0..<(input_count - 1) {
let value = read_u16_int(data, cursor)
cursor = cursor + 2
match value {
Err(err) => return Err(err)
Ok(value) => input.push(value)
}
}
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let lookahead_count = read_u16_int(data, cursor)
match lookahead_count {
Err(err) => Err(err)
Ok(lookahead_count) => {
cursor = cursor + 2
if lookahead_count < 0 {
return Err(InvalidFormat)
}
if cursor < 0 || cursor + lookahead_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let lookahead : Array[Int] = []
for _ in 0.. return Err(err)
Ok(value) => lookahead.push(value)
}
}
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let pos_count = read_u16_int(data, cursor)
match pos_count {
Err(err) => Err(err)
Ok(pos_count) => {
cursor = cursor + 2
if pos_count < 0 {
return Err(InvalidFormat)
}
let input_indices = collect_forward_indices(
glyphs,
index,
input_count,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(pos_no_match(index))
Ok(Some(indices)) => indices
}
let backtrack_indices = collect_backward_indices(
glyphs,
indices[0],
backtrack.length(),
lookup_flag,
gdef,
mark_filtering_set,
)
let backtrack_indices = match backtrack_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(pos_no_match(index))
Ok(Some(values)) => values
}
let lookahead_indices = if lookahead.is_empty() {
Ok(Some([]))
} else {
collect_forward_indices(
glyphs,
indices[input_count - 1] + 1,
lookahead.length(),
lookup_flag,
gdef,
mark_filtering_set,
allow_ignored_start=true,
)
}
let lookahead_indices = match lookahead_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(pos_no_match(index))
Ok(Some(values)) => values
}
for j in 0.. return Err(err)
Ok(actual) => if actual != expected {
return Ok(pos_no_match(index))
}
}
}
for j in 0.. return Err(err)
Ok(actual) => if actual != expected {
return Ok(pos_no_match(index))
}
}
}
for j in 0.. return Err(err)
Ok(actual) => if actual != expected {
return Ok(pos_no_match(index))
}
}
}
let changed = match apply_pos_lookup_records(
data,
cursor,
pos_count,
input_count,
glyphs,
deltas,
indices[0],
lookup_list_offsets,
Some(indices),
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
) {
Err(err) => return Err(err)
Ok(value) => value
}
let mut next_index = indices[indices.length() - 1] + 1
if next_index <= index {
next_index = index + 1
}
if next_index > glyphs.length() {
next_index = glyphs.length()
}
Ok(PosApplyResult::{ matched: true, changed, next_index })
}
}
}
}
}
}
}
}
}
///|
fn apply_chain_pos_rule(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
lookup_list_offsets : ArrayView[Int],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[PosApplyResult, OtLayoutError] {
if offset < 0 || offset + 2 > data.length() {
return Err(UnexpectedEof)
}
let backtrack_count = read_u16_int(data, offset)
match backtrack_count {
Err(err) => Err(err)
Ok(backtrack_count) => {
if backtrack_count < 0 {
return Err(InvalidFormat)
}
let mut cursor = offset + 2
if cursor < 0 || cursor + backtrack_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let backtrack : Array[Int] = []
for _ in 0.. return Err(err)
Ok(value) => backtrack.push(value)
}
}
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let input_count = read_u16_int(data, cursor)
match input_count {
Err(err) => Err(err)
Ok(input_count) => {
cursor = cursor + 2
if input_count <= 0 {
return Err(InvalidFormat)
}
if index + input_count > glyphs.length() {
return Ok(pos_no_match(index))
}
if cursor < 0 || cursor + (input_count - 1) * 2 > data.length() {
return Err(UnexpectedEof)
}
let input : Array[Int] = []
for _ in 0..<(input_count - 1) {
let value = read_u16_int(data, cursor)
cursor = cursor + 2
match value {
Err(err) => return Err(err)
Ok(value) => input.push(value)
}
}
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let lookahead_count = read_u16_int(data, cursor)
match lookahead_count {
Err(err) => Err(err)
Ok(lookahead_count) => {
cursor = cursor + 2
if lookahead_count < 0 {
return Err(InvalidFormat)
}
if cursor < 0 || cursor + lookahead_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let lookahead : Array[Int] = []
for _ in 0.. return Err(err)
Ok(value) => lookahead.push(value)
}
}
if cursor < 0 || cursor + 2 > data.length() {
return Err(UnexpectedEof)
}
let pos_count = read_u16_int(data, cursor)
match pos_count {
Err(err) => Err(err)
Ok(pos_count) => {
cursor = cursor + 2
if pos_count < 0 {
return Err(InvalidFormat)
}
if cursor < 0 || cursor + pos_count * 4 > data.length() {
return Err(UnexpectedEof)
}
let input_indices = collect_forward_indices(
glyphs,
index,
input_count,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(pos_no_match(index))
Ok(Some(indices)) => indices
}
let backtrack_indices = collect_backward_indices(
glyphs,
indices[0],
backtrack.length(),
lookup_flag,
gdef,
mark_filtering_set,
)
let backtrack_indices = match backtrack_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(pos_no_match(index))
Ok(Some(values)) => values
}
let lookahead_indices = if lookahead.is_empty() {
Ok(Some([]))
} else {
collect_forward_indices(
glyphs,
indices[input_count - 1] + 1,
lookahead.length(),
lookup_flag,
gdef,
mark_filtering_set,
allow_ignored_start=true,
)
}
let lookahead_indices = match lookahead_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(pos_no_match(index))
Ok(Some(values)) => values
}
for j in 0.. return Err(err)
Ok(value) => value
}
let mut next_index = indices[indices.length() - 1] + 1
if next_index <= index {
next_index = index + 1
}
if next_index > glyphs.length() {
next_index = glyphs.length()
}
Ok(PosApplyResult::{ matched: true, changed, next_index })
}
}
}
}
}
}
}
}
}
///|
fn apply_pos_lookup_at(
data : BytesView,
lookup_offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
let parsed = parse_lookup(data, lookup_offset, 9)
match parsed {
Err(err) => Err(err)
Ok((lookup_type, lookup_flag, mark_filtering_set, subtable_offsets)) => {
let ignored = should_ignore_glyph(
glyphs[index],
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => return Ok(false)
Ok(false) => ()
}
if lookup_type == 1 {
apply_single_pos_at(data, subtable_offsets, glyphs, deltas, index)
} else if lookup_type == 2 {
apply_pair_pos_at(
data,
subtable_offsets,
glyphs,
deltas,
index,
lookup_flag,
mark_filtering_set,
gdef,
)
} else if lookup_type == 3 {
apply_cursive_at(
data,
subtable_offsets,
glyphs,
deltas,
index,
lookup_flag,
mark_filtering_set,
gdef,
)
} else if lookup_type == 4 {
apply_mark_to_base_at(
data,
subtable_offsets,
glyphs,
deltas,
index,
lookup_flag,
mark_filtering_set,
gdef,
advances_x=advances_x,
advances_y=advances_y,
)
} else if lookup_type == 5 {
apply_mark_to_ligature_at(
data,
subtable_offsets,
glyphs,
deltas,
index,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
} else if lookup_type == 6 {
apply_mark_to_mark_at(
data,
subtable_offsets,
glyphs,
deltas,
index,
lookup_flag,
mark_filtering_set,
gdef,
advances_x=advances_x,
advances_y=advances_y,
)
} else {
Ok(false)
}
}
}
}
///|
fn apply_single_pos_at(
data : BytesView,
offsets : Array[Int],
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
) -> Result[Bool, OtLayoutError] {
if index < 0 || index >= glyphs.length() {
return Err(InvalidFormat)
}
let glyph = glyphs[index]
let mut changed = false
for offset in offsets {
let format = read_u16_int(data, offset)
match format {
Err(err) => return Err(err)
Ok(format) => if format == 1 {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let value_format = read_u16_int(data, offset + 4)
match (coverage_offset, value_format) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(coverage_offset), Ok(value_format)) => {
let coverage_base = offset + coverage_offset
let record_size = value_record_size(value_format)
let record_base = offset + 6
if record_base < 0 || record_base + record_size > data.length() {
return Err(UnexpectedEof)
}
let value = read_value_record(data, record_base, value_format)
match value {
Err(err) => return Err(err)
Ok((value, _)) => {
let covered = coverage_index(data, coverage_base, glyph)
match covered {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(_)) => {
deltas[index] = add_value_record(deltas[index], value)
changed = true
}
}
}
}
}
}
} else if format == 2 {
if offset < 0 || offset + 8 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let value_format = read_u16_int(data, offset + 4)
let value_count = read_u16_int(data, offset + 6)
match (coverage_offset, value_format, value_count) {
(Err(err), _, _) => return Err(err)
(_, Err(err), _) => return Err(err)
(_, _, Err(err)) => return Err(err)
(Ok(coverage_offset), Ok(value_format), Ok(value_count)) => {
if value_count <= 0 {
return Err(InvalidFormat)
}
let coverage_base = offset + coverage_offset
let record_size = value_record_size(value_format)
let record_base = offset + 8
let total_size = value_count * record_size
if record_base < 0 || record_base + total_size > data.length() {
return Err(UnexpectedEof)
}
let covered = coverage_index(data, coverage_base, glyph)
match covered {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(covered)) => {
if covered < 0 || covered >= value_count {
return Err(InvalidFormat)
}
let entry_base = record_base + covered * record_size
let value = read_value_record(data, entry_base, value_format)
match value {
Err(err) => return Err(err)
Ok((value, _)) => {
deltas[index] = add_value_record(deltas[index], value)
changed = true
}
}
}
}
}
}
} else {
return Err(InvalidFormat)
}
}
}
Ok(changed)
}
///|
fn apply_pair_pos_at(
data : BytesView,
offsets : Array[Int],
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Bool, OtLayoutError] {
if index < 0 || index >= glyphs.length() {
return Err(InvalidFormat)
}
let input_indices = collect_forward_indices(
glyphs,
index,
2,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(false)
Ok(Some(indices)) => indices
}
let first = glyphs[indices[0]]
let second = glyphs[indices[1]]
let mut changed = false
for offset in offsets {
let format = read_u16_int(data, offset)
match format {
Err(err) => return Err(err)
Ok(format) => {
let adjust = if format == 1 {
pair_adjust_format1(data, offset, first, second)
} else if format == 2 {
pair_adjust_format2(data, offset, first, second)
} else {
Err(InvalidFormat)
}
match adjust {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(adjust)) => {
deltas[indices[0]] = add_value_record(
deltas[indices[0]],
adjust.first,
)
deltas[indices[1]] = add_value_record(
deltas[indices[1]],
adjust.second,
)
changed = true
}
}
}
}
}
Ok(changed)
}
///|
fn apply_cursive_at(
data : BytesView,
offsets : Array[Int],
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Bool, OtLayoutError] {
if index < 0 || index >= glyphs.length() {
return Ok(false)
}
let mut changed = false
let input_indices = collect_forward_indices(
glyphs,
index,
2,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => return Ok(false)
Ok(Some(indices)) => indices
}
for offset in offsets {
let format = read_u16_int(data, offset)
match format {
Err(err) => return Err(err)
Ok(format) => if format == 1 {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let entry_exit_count = read_u16_int(data, offset + 4)
match (coverage_offset, entry_exit_count) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(coverage_offset), Ok(entry_exit_count)) => {
if entry_exit_count <= 0 || coverage_offset == 0 {
return Err(InvalidFormat)
}
let coverage_base = offset + coverage_offset
let record_base = offset + 6
let record_size = 4
if record_base < 0 ||
record_base + entry_exit_count * record_size > data.length() {
return Err(UnexpectedEof)
}
let current = glyphs[indices[0]]
let next = glyphs[indices[1]]
let current_index = coverage_index(data, coverage_base, current)
let next_index = coverage_index(data, coverage_base, next)
match (current_index, next_index) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(Some(current_index)), Ok(Some(next_index))) => {
if current_index < 0 || current_index >= entry_exit_count {
return Err(InvalidFormat)
}
if next_index < 0 || next_index >= entry_exit_count {
return Err(InvalidFormat)
}
let current_record_base = record_base + current_index * record_size
let next_record_base = record_base + next_index * record_size
let current_exit_offset = read_u16_int(
data,
current_record_base + 2,
)
let next_entry_offset = read_u16_int(data, next_record_base)
match (current_exit_offset, next_entry_offset) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(current_exit_offset), Ok(next_entry_offset)) => {
if current_exit_offset == 0 || next_entry_offset == 0 {
continue
}
let current_exit_base = offset + current_exit_offset
let next_entry_base = offset + next_entry_offset
let current_exit = read_anchor(data, current_exit_base)
let next_entry = read_anchor(data, next_entry_base)
match (current_exit, next_entry) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(current_exit), Ok(next_entry)) => {
let dx = current_exit.0 - next_entry.0
let dy = current_exit.1 - next_entry.1
let delta = ValueRecord::{
x_placement: dx,
y_placement: dy,
x_advance: 0,
y_advance: 0,
}
deltas[indices[1]] = add_value_record(
deltas[indices[1]],
delta,
)
changed = true
}
}
}
}
}
_ => ()
}
}
}
} else {
return Err(InvalidFormat)
}
}
}
Ok(changed)
}
///|
fn find_prev_coverage_index(
data : BytesView,
coverage_base : Int,
glyphs : ArrayView[UInt],
start_index : Int,
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[(Int, Int)?, OtLayoutError] {
if start_index <= 0 {
return Ok(None)
}
let mut cursor = start_index - 1
while cursor >= 0 {
let ignored = should_ignore_glyph(
glyphs[cursor],
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => cursor = cursor - 1
Ok(false) => {
let coverage = coverage_index(data, coverage_base, glyphs[cursor])
match coverage {
Err(err) => return Err(err)
Ok(Some(index)) => return Ok(Some((index, cursor)))
Ok(None) => cursor = cursor - 1
}
}
}
}
Ok(None)
}
///|
fn apply_mark_to_base_at(
data : BytesView,
offsets : Array[Int],
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if index <= 0 || index >= glyphs.length() {
return Ok(false)
}
let ignored = should_ignore_glyph(
glyphs[index],
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => return Ok(false)
Ok(false) => ()
}
let mut changed = false
let mark_glyph = glyphs[index]
for offset in offsets {
let format = read_u16_int(data, offset)
match format {
Err(err) => return Err(err)
Ok(format) => if format == 1 {
if offset < 0 || offset + 12 > data.length() {
return Err(UnexpectedEof)
}
let mark_coverage_offset = read_u16_int(data, offset + 2)
let base_coverage_offset = read_u16_int(data, offset + 4)
let class_count = read_u16_int(data, offset + 6)
let mark_array_offset = read_u16_int(data, offset + 8)
let base_array_offset = read_u16_int(data, offset + 10)
match (
mark_coverage_offset,
base_coverage_offset,
class_count,
mark_array_offset,
base_array_offset,
) {
(Err(err), _, _, _, _) => return Err(err)
(_, Err(err), _, _, _) => return Err(err)
(_, _, Err(err), _, _) => return Err(err)
(_, _, _, Err(err), _) => return Err(err)
(_, _, _, _, Err(err)) => return Err(err)
(
Ok(mark_coverage_offset),
Ok(base_coverage_offset),
Ok(class_count),
Ok(mark_array_offset),
Ok(base_array_offset),
) => {
if mark_coverage_offset == 0 || base_coverage_offset == 0 ||
mark_array_offset == 0 || base_array_offset == 0 {
return Err(InvalidFormat)
}
if class_count <= 0 {
return Err(InvalidFormat)
}
let mark_coverage_base = offset + mark_coverage_offset
let base_coverage_base = offset + base_coverage_offset
let mark_array_base = offset + mark_array_offset
let base_array_base = offset + base_array_offset
if mark_array_base < 0 || mark_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
if base_array_base < 0 || base_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let mark_count = read_u16_int(data, mark_array_base)
let base_count = read_u16_int(data, base_array_base)
match (mark_count, base_count) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_count), Ok(base_count)) => {
if mark_count <= 0 || base_count <= 0 {
return Err(InvalidFormat)
}
let mark_record_base = mark_array_base + 2
let mark_record_size = 4
if mark_record_base < 0 ||
mark_record_base + mark_count * mark_record_size > data.length() {
return Err(UnexpectedEof)
}
let base_record_base = base_array_base + 2
let base_record_size = class_count * 2
if base_record_base < 0 ||
base_record_base + base_count * base_record_size > data.length() {
return Err(UnexpectedEof)
}
let mark_index = coverage_index(
data,
mark_coverage_base,
mark_glyph,
)
match mark_index {
Err(err) => return Err(err)
Ok(Some(mark_index)) => {
let base_info = find_prev_coverage_index(
data,
base_coverage_base,
glyphs,
index,
lookup_flag,
mark_filtering_set,
gdef,
)
let (base_index, base_glyph_index) = match base_info {
Err(err) => return Err(err)
Ok(None) => continue
Ok(Some(values)) => values
}
if mark_index < 0 || mark_index >= mark_count {
return Err(InvalidFormat)
}
if base_index < 0 || base_index >= base_count {
return Err(InvalidFormat)
}
let mark_record_offset =
mark_record_base + mark_index * mark_record_size
let mark_class = read_u16_int(data, mark_record_offset)
let mark_anchor_offset = read_u16_int(
data,
mark_record_offset + 2,
)
match (mark_class, mark_anchor_offset) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_class), Ok(mark_anchor_offset)) => {
if mark_class < 0 || mark_class >= class_count {
return Err(InvalidFormat)
}
if mark_anchor_offset == 0 {
return Err(InvalidFormat)
}
let base_record_offset =
base_record_base + base_index * base_record_size
let base_anchor_offset = read_u16_int(
data,
base_record_offset + mark_class * 2,
)
match base_anchor_offset {
Err(err) => return Err(err)
Ok(base_anchor_offset) => {
if base_anchor_offset == 0 {
continue
}
let mark_anchor_base =
mark_array_base + mark_anchor_offset
let base_anchor_base =
base_array_base + base_anchor_offset
let mark_anchor = read_anchor(data, mark_anchor_base)
let base_anchor = read_anchor(data, base_anchor_base)
match (mark_anchor, base_anchor) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_anchor), Ok(base_anchor)) => {
let (advance_x, advance_y) = sum_advances_between(
deltas,
advances_x,
advances_y,
base_glyph_index,
index,
)
let dx = base_anchor.0 - mark_anchor.0 - advance_x
let dy = base_anchor.1 - mark_anchor.1 - advance_y
let delta = ValueRecord::{
x_placement: dx,
y_placement: dy,
x_advance: 0,
y_advance: 0,
}
deltas[index] = add_value_record(deltas[index], delta)
changed = true
}
}
}
}
}
}
}
Ok(None) => ()
}
}
}
}
}
} else {
return Err(InvalidFormat)
}
}
}
Ok(changed)
}
///|
fn apply_mark_to_ligature_at(
data : BytesView,
offsets : Array[Int],
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if index <= 0 || index >= glyphs.length() {
return Ok(false)
}
let ignored = should_ignore_glyph(
glyphs[index],
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => return Ok(false)
Ok(false) => ()
}
let mut changed = false
let mark_glyph = glyphs[index]
for offset in offsets {
let format = read_u16_int(data, offset)
match format {
Err(err) => return Err(err)
Ok(format) => if format == 1 {
if offset < 0 || offset + 12 > data.length() {
return Err(UnexpectedEof)
}
let mark_coverage_offset = read_u16_int(data, offset + 2)
let ligature_coverage_offset = read_u16_int(data, offset + 4)
let class_count = read_u16_int(data, offset + 6)
let mark_array_offset = read_u16_int(data, offset + 8)
let ligature_array_offset = read_u16_int(data, offset + 10)
match (
mark_coverage_offset,
ligature_coverage_offset,
class_count,
mark_array_offset,
ligature_array_offset,
) {
(Err(err), _, _, _, _) => return Err(err)
(_, Err(err), _, _, _) => return Err(err)
(_, _, Err(err), _, _) => return Err(err)
(_, _, _, Err(err), _) => return Err(err)
(_, _, _, _, Err(err)) => return Err(err)
(
Ok(mark_coverage_offset),
Ok(ligature_coverage_offset),
Ok(class_count),
Ok(mark_array_offset),
Ok(ligature_array_offset),
) => {
if mark_coverage_offset == 0 || ligature_coverage_offset == 0 ||
mark_array_offset == 0 || ligature_array_offset == 0 {
return Err(InvalidFormat)
}
if class_count <= 0 {
return Err(InvalidFormat)
}
let mark_coverage_base = offset + mark_coverage_offset
let ligature_coverage_base = offset + ligature_coverage_offset
let mark_array_base = offset + mark_array_offset
let ligature_array_base = offset + ligature_array_offset
if mark_array_base < 0 || mark_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
if ligature_array_base < 0 || ligature_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let mark_count = read_u16_int(data, mark_array_base)
let ligature_count = read_u16_int(data, ligature_array_base)
match (mark_count, ligature_count) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_count), Ok(ligature_count)) => {
if mark_count <= 0 || ligature_count <= 0 {
return Err(InvalidFormat)
}
let mark_record_base = mark_array_base + 2
let mark_record_size = 4
if mark_record_base < 0 ||
mark_record_base + mark_count * mark_record_size > data.length() {
return Err(UnexpectedEof)
}
let ligature_offset_base = ligature_array_base + 2
if ligature_offset_base < 0 ||
ligature_offset_base + ligature_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let mark_index = coverage_index(
data,
mark_coverage_base,
mark_glyph,
)
match mark_index {
Err(err) => return Err(err)
Ok(Some(mark_index)) => {
let ligature_info = find_prev_coverage_index(
data,
ligature_coverage_base,
glyphs,
index,
lookup_flag,
mark_filtering_set,
gdef,
)
let (ligature_index, ligature_glyph_index) = match ligature_info {
Err(err) => return Err(err)
Ok(None) => continue
Ok(Some(values)) => values
}
if mark_index < 0 || mark_index >= mark_count {
return Err(InvalidFormat)
}
if ligature_index < 0 || ligature_index >= ligature_count {
return Err(InvalidFormat)
}
let mark_record_offset =
mark_record_base + mark_index * mark_record_size
let mark_class = read_u16_int(data, mark_record_offset)
let mark_anchor_offset = read_u16_int(
data,
mark_record_offset + 2,
)
match (mark_class, mark_anchor_offset) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_class), Ok(mark_anchor_offset)) => {
if mark_class < 0 || mark_class >= class_count {
return Err(InvalidFormat)
}
if mark_anchor_offset == 0 {
return Err(InvalidFormat)
}
let ligature_attach_offset = read_u16_int(
data,
ligature_offset_base + ligature_index * 2,
)
match ligature_attach_offset {
Err(err) => return Err(err)
Ok(ligature_attach_offset) => {
if ligature_attach_offset == 0 {
return Err(InvalidFormat)
}
let ligature_attach_base =
ligature_array_base + ligature_attach_offset
if ligature_attach_base < 0 ||
ligature_attach_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let component_count = read_u16_int(
data,
ligature_attach_base,
)
match component_count {
Err(err) => return Err(err)
Ok(component_count) => {
if component_count <= 0 {
return Err(InvalidFormat)
}
let component_index = ligature_component_index(
clusters,
ligature_glyph_index,
index,
component_count,
)
if component_index < 0 ||
component_index >= component_count {
return Err(InvalidFormat)
}
let component_record_base =
ligature_attach_base + 2
let component_record_size = class_count * 2
let component_total =
component_record_size * component_count
if component_record_base < 0 ||
component_record_base + component_total > data.length() {
return Err(UnexpectedEof)
}
let component_base =
component_record_base +
component_index * component_record_size
let ligature_anchor_offset = read_u16_int(
data,
component_base + mark_class * 2,
)
match ligature_anchor_offset {
Err(err) => return Err(err)
Ok(ligature_anchor_offset) => {
if ligature_anchor_offset == 0 {
continue
}
let mark_anchor_base =
mark_array_base + mark_anchor_offset
let ligature_anchor_base =
ligature_attach_base + ligature_anchor_offset
let mark_anchor = read_anchor(
data,
mark_anchor_base,
)
let ligature_anchor = read_anchor(
data,
ligature_anchor_base,
)
match (mark_anchor, ligature_anchor) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_anchor), Ok(ligature_anchor)) => {
let (advance_x, advance_y) = sum_advances_between(
deltas,
advances_x,
advances_y,
ligature_glyph_index,
index,
)
let dx =
ligature_anchor.0 - mark_anchor.0 - advance_x
let dy =
ligature_anchor.1 - mark_anchor.1 - advance_y
let delta = ValueRecord::{
x_placement: dx,
y_placement: dy,
x_advance: 0,
y_advance: 0,
}
deltas[index] = add_value_record(
deltas[index],
delta,
)
changed = true
}
}
}
}
}
}
}
}
}
}
}
Ok(None) => ()
}
}
}
}
}
} else {
return Err(InvalidFormat)
}
}
}
Ok(changed)
}
///|
fn apply_cursive_subtable(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Unit, OtLayoutError] {
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
apply_cursive_format1(
data,
offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
} else {
Ok(())
}
}
}
///|
fn apply_cursive_format1(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Unit, OtLayoutError] {
if glyphs.length() < 2 {
return Ok(())
}
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let entry_exit_count = read_u16_int(data, offset + 4)
match (coverage_offset, entry_exit_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(entry_exit_count)) => {
if entry_exit_count <= 0 {
return Err(InvalidFormat)
}
if coverage_offset == 0 {
return Err(InvalidFormat)
}
let coverage_base = offset + coverage_offset
let record_base = offset + 6
let record_size = 4
if record_base < 0 ||
record_base + entry_exit_count * record_size > data.length() {
return Err(UnexpectedEof)
}
for i in 0..<(glyphs.length() - 1) {
let input_indices = collect_forward_indices(
glyphs,
i,
2,
lookup_flag,
gdef,
mark_filtering_set,
)
let indices = match input_indices {
Err(err) => return Err(err)
Ok(None) => continue
Ok(Some(indices)) => indices
}
let current = glyphs[indices[0]]
let next = glyphs[indices[1]]
let current_index = coverage_index(data, coverage_base, current)
let next_index = coverage_index(data, coverage_base, next)
match (current_index, next_index) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(Some(current_index)), Ok(Some(next_index))) => {
if current_index < 0 || current_index >= entry_exit_count {
return Err(InvalidFormat)
}
if next_index < 0 || next_index >= entry_exit_count {
return Err(InvalidFormat)
}
let current_record_base = record_base + current_index * record_size
let next_record_base = record_base + next_index * record_size
let current_exit_offset = read_u16_int(data, current_record_base + 2)
let next_entry_offset = read_u16_int(data, next_record_base)
match (current_exit_offset, next_entry_offset) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(current_exit_offset), Ok(next_entry_offset)) => {
if current_exit_offset == 0 || next_entry_offset == 0 {
continue
}
let current_exit_base = offset + current_exit_offset
let next_entry_base = offset + next_entry_offset
let current_exit = read_anchor(data, current_exit_base)
let next_entry = read_anchor(data, next_entry_base)
match (current_exit, next_entry) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(current_exit), Ok(next_entry)) => {
let dx = current_exit.0 - next_entry.0
let dy = current_exit.1 - next_entry.1
let delta = ValueRecord::{
x_placement: dx,
y_placement: dy,
x_advance: 0,
y_advance: 0,
}
deltas[indices[1]] = add_value_record(
deltas[indices[1]],
delta,
)
}
}
}
}
}
_ => ()
}
}
Ok(())
}
}
}
///|
fn apply_mark_subtable(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Unit, OtLayoutError] {
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
apply_mark_to_base_format1(
data,
offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
advances_x=advances_x,
advances_y=advances_y,
)
} else {
Ok(())
}
}
}
///|
fn apply_mark_to_base_format1(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Unit, OtLayoutError] {
if glyphs.length() < 2 {
return Ok(())
}
if offset < 0 || offset + 12 > data.length() {
return Err(UnexpectedEof)
}
let mark_coverage_offset = read_u16_int(data, offset + 2)
let base_coverage_offset = read_u16_int(data, offset + 4)
let class_count = read_u16_int(data, offset + 6)
let mark_array_offset = read_u16_int(data, offset + 8)
let base_array_offset = read_u16_int(data, offset + 10)
match (
mark_coverage_offset,
base_coverage_offset,
class_count,
mark_array_offset,
base_array_offset,
) {
(Err(err), _, _, _, _) => Err(err)
(_, Err(err), _, _, _) => Err(err)
(_, _, Err(err), _, _) => Err(err)
(_, _, _, Err(err), _) => Err(err)
(_, _, _, _, Err(err)) => Err(err)
(
Ok(mark_coverage_offset),
Ok(base_coverage_offset),
Ok(class_count),
Ok(mark_array_offset),
Ok(base_array_offset),
) => {
if mark_coverage_offset == 0 || base_coverage_offset == 0 ||
mark_array_offset == 0 || base_array_offset == 0 {
return Err(InvalidFormat)
}
if class_count <= 0 {
return Err(InvalidFormat)
}
let mark_coverage_base = offset + mark_coverage_offset
let base_coverage_base = offset + base_coverage_offset
let mark_array_base = offset + mark_array_offset
let base_array_base = offset + base_array_offset
if mark_array_base < 0 || mark_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
if base_array_base < 0 || base_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let mark_count = read_u16_int(data, mark_array_base)
let base_count = read_u16_int(data, base_array_base)
match (mark_count, base_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(mark_count), Ok(base_count)) => {
if mark_count <= 0 || base_count <= 0 {
return Err(InvalidFormat)
}
let mark_record_base = mark_array_base + 2
let mark_record_size = 4
if mark_record_base < 0 ||
mark_record_base + mark_count * mark_record_size > data.length() {
return Err(UnexpectedEof)
}
let base_record_base = base_array_base + 2
let base_record_size = class_count * 2
if base_record_base < 0 ||
base_record_base + base_count * base_record_size > data.length() {
return Err(UnexpectedEof)
}
for i in 1.. return Err(err)
Ok(true) => continue
Ok(false) => ()
}
let mark_index = coverage_index(data, mark_coverage_base, mark_glyph)
match mark_index {
Err(err) => return Err(err)
Ok(Some(mark_index)) => {
let base_info = find_prev_coverage_index(
data,
base_coverage_base,
glyphs,
i,
lookup_flag,
mark_filtering_set,
gdef,
)
let (base_index, base_glyph_index) = match base_info {
Err(err) => return Err(err)
Ok(None) => continue
Ok(Some(values)) => values
}
if mark_index < 0 || mark_index >= mark_count {
return Err(InvalidFormat)
}
if base_index < 0 || base_index >= base_count {
return Err(InvalidFormat)
}
let mark_record_offset = mark_record_base + mark_index * mark_record_size
let mark_class = read_u16_int(data, mark_record_offset)
let mark_anchor_offset = read_u16_int(data, mark_record_offset + 2)
match (mark_class, mark_anchor_offset) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_class), Ok(mark_anchor_offset)) => {
if mark_class < 0 || mark_class >= class_count {
return Err(InvalidFormat)
}
if mark_anchor_offset == 0 {
return Err(InvalidFormat)
}
let base_record_offset =
base_record_base + base_index * base_record_size
let base_anchor_offset = read_u16_int(
data,
base_record_offset + mark_class * 2,
)
match base_anchor_offset {
Err(err) => return Err(err)
Ok(base_anchor_offset) => {
if base_anchor_offset == 0 {
continue
}
let mark_anchor_base = mark_array_base + mark_anchor_offset
let base_anchor_base = base_array_base + base_anchor_offset
let mark_anchor = read_anchor(data, mark_anchor_base)
let base_anchor = read_anchor(data, base_anchor_base)
match (mark_anchor, base_anchor) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_anchor), Ok(base_anchor)) => {
let (advance_x, advance_y) = sum_advances_between(
deltas,
advances_x,
advances_y,
base_glyph_index,
i,
)
let dx = base_anchor.0 - mark_anchor.0 - advance_x
let dy = base_anchor.1 - mark_anchor.1 - advance_y
let delta = ValueRecord::{
x_placement: dx,
y_placement: dy,
x_advance: 0,
y_advance: 0,
}
deltas[i] = add_value_record(deltas[i], delta)
}
}
}
}
}
}
}
Ok(None) => ()
}
}
Ok(())
}
}
}
}
}
///|
fn apply_mark_to_ligature_subtable(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Unit, OtLayoutError] {
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
apply_mark_to_ligature_format1(
data,
offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
clusters=clusters,
advances_x=advances_x,
advances_y=advances_y,
)
} else {
Ok(())
}
}
}
///|
fn apply_mark_to_ligature_format1(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
clusters? : ArrayView[Int] = [],
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Unit, OtLayoutError] {
if glyphs.length() < 2 {
return Ok(())
}
if offset < 0 || offset + 12 > data.length() {
return Err(UnexpectedEof)
}
let mark_coverage_offset = read_u16_int(data, offset + 2)
let ligature_coverage_offset = read_u16_int(data, offset + 4)
let class_count = read_u16_int(data, offset + 6)
let mark_array_offset = read_u16_int(data, offset + 8)
let ligature_array_offset = read_u16_int(data, offset + 10)
match (
mark_coverage_offset,
ligature_coverage_offset,
class_count,
mark_array_offset,
ligature_array_offset,
) {
(Err(err), _, _, _, _) => Err(err)
(_, Err(err), _, _, _) => Err(err)
(_, _, Err(err), _, _) => Err(err)
(_, _, _, Err(err), _) => Err(err)
(_, _, _, _, Err(err)) => Err(err)
(
Ok(mark_coverage_offset),
Ok(ligature_coverage_offset),
Ok(class_count),
Ok(mark_array_offset),
Ok(ligature_array_offset),
) => {
if mark_coverage_offset == 0 || ligature_coverage_offset == 0 ||
mark_array_offset == 0 || ligature_array_offset == 0 {
return Err(InvalidFormat)
}
if class_count <= 0 {
return Err(InvalidFormat)
}
let mark_coverage_base = offset + mark_coverage_offset
let ligature_coverage_base = offset + ligature_coverage_offset
let mark_array_base = offset + mark_array_offset
let ligature_array_base = offset + ligature_array_offset
if mark_array_base < 0 || mark_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
if ligature_array_base < 0 || ligature_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let mark_count = read_u16_int(data, mark_array_base)
let ligature_count = read_u16_int(data, ligature_array_base)
match (mark_count, ligature_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(mark_count), Ok(ligature_count)) => {
if mark_count <= 0 || ligature_count <= 0 {
return Err(InvalidFormat)
}
let mark_record_base = mark_array_base + 2
let mark_record_size = 4
if mark_record_base < 0 ||
mark_record_base + mark_count * mark_record_size > data.length() {
return Err(UnexpectedEof)
}
let ligature_offset_base = ligature_array_base + 2
if ligature_offset_base < 0 ||
ligature_offset_base + ligature_count * 2 > data.length() {
return Err(UnexpectedEof)
}
for i in 1.. return Err(err)
Ok(true) => continue
Ok(false) => ()
}
let mark_index = coverage_index(data, mark_coverage_base, mark_glyph)
match mark_index {
Err(err) => return Err(err)
Ok(Some(mark_index)) => {
let ligature_info = find_prev_coverage_index(
data,
ligature_coverage_base,
glyphs,
i,
lookup_flag,
mark_filtering_set,
gdef,
)
let (ligature_index, ligature_glyph_index) = match ligature_info {
Err(err) => return Err(err)
Ok(None) => continue
Ok(Some(values)) => values
}
if mark_index < 0 || mark_index >= mark_count {
return Err(InvalidFormat)
}
if ligature_index < 0 || ligature_index >= ligature_count {
return Err(InvalidFormat)
}
let mark_record_offset =
mark_record_base + mark_index * mark_record_size
let mark_class = read_u16_int(data, mark_record_offset)
let mark_anchor_offset = read_u16_int(data, mark_record_offset + 2)
match (mark_class, mark_anchor_offset) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_class), Ok(mark_anchor_offset)) => {
if mark_class < 0 || mark_class >= class_count {
return Err(InvalidFormat)
}
if mark_anchor_offset == 0 {
return Err(InvalidFormat)
}
let ligature_attach_offset = read_u16_int(
data,
ligature_offset_base + ligature_index * 2,
)
match ligature_attach_offset {
Err(err) => return Err(err)
Ok(ligature_attach_offset) => {
if ligature_attach_offset == 0 {
return Err(InvalidFormat)
}
let ligature_attach_base =
ligature_array_base + ligature_attach_offset
if ligature_attach_base < 0 ||
ligature_attach_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let component_count = read_u16_int(data, ligature_attach_base)
match component_count {
Err(err) => return Err(err)
Ok(component_count) => {
if component_count <= 0 {
return Err(InvalidFormat)
}
let component_index = ligature_component_index(
clusters,
ligature_glyph_index,
i,
component_count,
)
if component_index < 0 || component_index >= component_count {
return Err(InvalidFormat)
}
let component_record_base = ligature_attach_base + 2
let component_record_size = class_count * 2
let component_total =
component_record_size * component_count
if component_record_base < 0 ||
component_record_base + component_total > data.length() {
return Err(UnexpectedEof)
}
let component_base =
component_record_base +
component_index * component_record_size
let ligature_anchor_offset = read_u16_int(
data,
component_base + mark_class * 2,
)
match ligature_anchor_offset {
Err(err) => return Err(err)
Ok(ligature_anchor_offset) => {
if ligature_anchor_offset == 0 {
continue
}
let mark_anchor_base =
mark_array_base + mark_anchor_offset
let ligature_anchor_base =
ligature_attach_base + ligature_anchor_offset
let mark_anchor = read_anchor(data, mark_anchor_base)
let ligature_anchor = read_anchor(
data,
ligature_anchor_base,
)
match (mark_anchor, ligature_anchor) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_anchor), Ok(ligature_anchor)) => {
let (advance_x, advance_y) = sum_advances_between(
deltas,
advances_x,
advances_y,
ligature_glyph_index,
i,
)
let dx =
ligature_anchor.0 - mark_anchor.0 - advance_x
let dy =
ligature_anchor.1 - mark_anchor.1 - advance_y
let delta = ValueRecord::{
x_placement: dx,
y_placement: dy,
x_advance: 0,
y_advance: 0,
}
deltas[i] = add_value_record(deltas[i], delta)
}
}
}
}
}
}
}
}
}
}
}
Ok(None) => ()
}
}
Ok(())
}
}
}
}
}
///|
fn apply_mark_to_mark_at(
data : BytesView,
offsets : Array[Int],
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
index : Int,
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Bool, OtLayoutError] {
if index <= 0 || index >= glyphs.length() {
return Ok(false)
}
let ignored = should_ignore_glyph(
glyphs[index],
lookup_flag,
gdef,
mark_filtering_set,
)
match ignored {
Err(err) => return Err(err)
Ok(true) => return Ok(false)
Ok(false) => ()
}
let mut changed = false
for offset in offsets {
let format = read_u16_int(data, offset)
match format {
Err(err) => return Err(err)
Ok(format) => if format == 1 {
if offset < 0 || offset + 12 > data.length() {
return Err(UnexpectedEof)
}
let mark1_coverage_offset = read_u16_int(data, offset + 2)
let mark2_coverage_offset = read_u16_int(data, offset + 4)
let class_count = read_u16_int(data, offset + 6)
let mark1_array_offset = read_u16_int(data, offset + 8)
let mark2_array_offset = read_u16_int(data, offset + 10)
match (
mark1_coverage_offset,
mark2_coverage_offset,
class_count,
mark1_array_offset,
mark2_array_offset,
) {
(Err(err), _, _, _, _) => return Err(err)
(_, Err(err), _, _, _) => return Err(err)
(_, _, Err(err), _, _) => return Err(err)
(_, _, _, Err(err), _) => return Err(err)
(_, _, _, _, Err(err)) => return Err(err)
(
Ok(mark1_coverage_offset),
Ok(mark2_coverage_offset),
Ok(class_count),
Ok(mark1_array_offset),
Ok(mark2_array_offset),
) => {
if mark1_coverage_offset == 0 || mark2_coverage_offset == 0 ||
mark1_array_offset == 0 || mark2_array_offset == 0 {
return Err(InvalidFormat)
}
if class_count <= 0 {
return Err(InvalidFormat)
}
let mark1_coverage_base = offset + mark1_coverage_offset
let mark2_coverage_base = offset + mark2_coverage_offset
let mark1_array_base = offset + mark1_array_offset
let mark2_array_base = offset + mark2_array_offset
if mark1_array_base < 0 || mark1_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
if mark2_array_base < 0 || mark2_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let mark1_count = read_u16_int(data, mark1_array_base)
let mark2_count = read_u16_int(data, mark2_array_base)
match (mark1_count, mark2_count) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark1_count), Ok(mark2_count)) => {
if mark1_count <= 0 || mark2_count <= 0 {
return Err(InvalidFormat)
}
let mark1_record_base = mark1_array_base + 2
let mark1_record_size = 4
if mark1_record_base < 0 ||
mark1_record_base + mark1_count * mark1_record_size > data.length() {
return Err(UnexpectedEof)
}
let mark2_record_base = mark2_array_base + 2
let mark2_record_size = class_count * 2
if mark2_record_base < 0 ||
mark2_record_base + mark2_count * mark2_record_size > data.length() {
return Err(UnexpectedEof)
}
let mark1_glyph = glyphs[index]
let mark1_index = coverage_index(
data,
mark1_coverage_base,
mark1_glyph,
)
match mark1_index {
Err(err) => return Err(err)
Ok(Some(mark1_index)) => {
let mark2_info = find_prev_coverage_index(
data,
mark2_coverage_base,
glyphs,
index,
lookup_flag,
mark_filtering_set,
gdef,
)
let (mark2_index, mark2_glyph_index) = match mark2_info {
Err(err) => return Err(err)
Ok(None) => continue
Ok(Some(values)) => values
}
if mark1_index < 0 || mark1_index >= mark1_count {
return Err(InvalidFormat)
}
if mark2_index < 0 || mark2_index >= mark2_count {
return Err(InvalidFormat)
}
let mark1_record_offset =
mark1_record_base + mark1_index * mark1_record_size
let mark_class = read_u16_int(data, mark1_record_offset)
let mark1_anchor_offset = read_u16_int(
data,
mark1_record_offset + 2,
)
match (mark_class, mark1_anchor_offset) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_class), Ok(mark1_anchor_offset)) => {
if mark_class < 0 || mark_class >= class_count {
return Err(InvalidFormat)
}
if mark1_anchor_offset == 0 {
return Err(InvalidFormat)
}
let mark2_record_offset =
mark2_record_base + mark2_index * mark2_record_size
let mark2_anchor_offset = read_u16_int(
data,
mark2_record_offset + mark_class * 2,
)
match mark2_anchor_offset {
Err(err) => return Err(err)
Ok(mark2_anchor_offset) => {
if mark2_anchor_offset == 0 {
continue
}
let mark1_anchor_base =
mark1_array_base + mark1_anchor_offset
let mark2_anchor_base =
mark2_array_base + mark2_anchor_offset
let mark1_anchor = read_anchor(
data,
mark1_anchor_base,
)
let mark2_anchor = read_anchor(
data,
mark2_anchor_base,
)
match (mark1_anchor, mark2_anchor) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark1_anchor), Ok(mark2_anchor)) => {
let (advance_x, advance_y) = sum_advances_between(
deltas,
advances_x,
advances_y,
mark2_glyph_index,
index,
)
let dx = mark2_anchor.0 - mark1_anchor.0 - advance_x
let dy = mark2_anchor.1 - mark1_anchor.1 - advance_y
let delta = ValueRecord::{
x_placement: dx,
y_placement: dy,
x_advance: 0,
y_advance: 0,
}
deltas[index] = add_value_record(
deltas[index],
delta,
)
changed = true
}
}
}
}
}
}
}
Ok(None) => ()
}
}
}
}
}
} else {
return Err(InvalidFormat)
}
}
}
Ok(changed)
}
///|
fn apply_mark_to_mark_subtable(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Unit, OtLayoutError] {
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
apply_mark_to_mark_format1(
data,
offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
advances_x=advances_x,
advances_y=advances_y,
)
} else {
Ok(())
}
}
}
///|
fn apply_mark_to_mark_format1(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
advances_x? : ArrayView[Int] = [],
advances_y? : ArrayView[Int] = [],
) -> Result[Unit, OtLayoutError] {
if glyphs.length() < 2 {
return Ok(())
}
if offset < 0 || offset + 12 > data.length() {
return Err(UnexpectedEof)
}
let mark1_coverage_offset = read_u16_int(data, offset + 2)
let mark2_coverage_offset = read_u16_int(data, offset + 4)
let class_count = read_u16_int(data, offset + 6)
let mark1_array_offset = read_u16_int(data, offset + 8)
let mark2_array_offset = read_u16_int(data, offset + 10)
match (
mark1_coverage_offset,
mark2_coverage_offset,
class_count,
mark1_array_offset,
mark2_array_offset,
) {
(Err(err), _, _, _, _) => Err(err)
(_, Err(err), _, _, _) => Err(err)
(_, _, Err(err), _, _) => Err(err)
(_, _, _, Err(err), _) => Err(err)
(_, _, _, _, Err(err)) => Err(err)
(
Ok(mark1_coverage_offset),
Ok(mark2_coverage_offset),
Ok(class_count),
Ok(mark1_array_offset),
Ok(mark2_array_offset),
) => {
if mark1_coverage_offset == 0 || mark2_coverage_offset == 0 ||
mark1_array_offset == 0 || mark2_array_offset == 0 {
return Err(InvalidFormat)
}
if class_count <= 0 {
return Err(InvalidFormat)
}
let mark1_coverage_base = offset + mark1_coverage_offset
let mark2_coverage_base = offset + mark2_coverage_offset
let mark1_array_base = offset + mark1_array_offset
let mark2_array_base = offset + mark2_array_offset
if mark1_array_base < 0 || mark1_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
if mark2_array_base < 0 || mark2_array_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let mark1_count = read_u16_int(data, mark1_array_base)
let mark2_count = read_u16_int(data, mark2_array_base)
match (mark1_count, mark2_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(mark1_count), Ok(mark2_count)) => {
if mark1_count <= 0 || mark2_count <= 0 {
return Err(InvalidFormat)
}
let mark1_record_base = mark1_array_base + 2
let mark1_record_size = 4
if mark1_record_base < 0 ||
mark1_record_base + mark1_count * mark1_record_size > data.length() {
return Err(UnexpectedEof)
}
let mark2_record_base = mark2_array_base + 2
let mark2_record_size = class_count * 2
if mark2_record_base < 0 ||
mark2_record_base + mark2_count * mark2_record_size > data.length() {
return Err(UnexpectedEof)
}
for i in 1.. return Err(err)
Ok(true) => continue
Ok(false) => ()
}
let mark1_index = coverage_index(
data,
mark1_coverage_base,
mark1_glyph,
)
match mark1_index {
Err(err) => return Err(err)
Ok(Some(mark1_index)) => {
let mark2_info = find_prev_coverage_index(
data,
mark2_coverage_base,
glyphs,
i,
lookup_flag,
mark_filtering_set,
gdef,
)
let (mark2_index, mark2_glyph_index) = match mark2_info {
Err(err) => return Err(err)
Ok(None) => continue
Ok(Some(values)) => values
}
if mark1_index < 0 || mark1_index >= mark1_count {
return Err(InvalidFormat)
}
if mark2_index < 0 || mark2_index >= mark2_count {
return Err(InvalidFormat)
}
let mark1_record_offset =
mark1_record_base + mark1_index * mark1_record_size
let mark_class = read_u16_int(data, mark1_record_offset)
let mark1_anchor_offset = read_u16_int(
data,
mark1_record_offset + 2,
)
match (mark_class, mark1_anchor_offset) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark_class), Ok(mark1_anchor_offset)) => {
if mark_class < 0 || mark_class >= class_count {
return Err(InvalidFormat)
}
if mark1_anchor_offset == 0 {
return Err(InvalidFormat)
}
let mark2_record_offset =
mark2_record_base + mark2_index * mark2_record_size
let mark2_anchor_offset = read_u16_int(
data,
mark2_record_offset + mark_class * 2,
)
match mark2_anchor_offset {
Err(err) => return Err(err)
Ok(mark2_anchor_offset) => {
if mark2_anchor_offset == 0 {
continue
}
let mark1_anchor_base =
mark1_array_base + mark1_anchor_offset
let mark2_anchor_base =
mark2_array_base + mark2_anchor_offset
let mark1_anchor = read_anchor(data, mark1_anchor_base)
let mark2_anchor = read_anchor(data, mark2_anchor_base)
match (mark1_anchor, mark2_anchor) {
(Err(err), _) => return Err(err)
(_, Err(err)) => return Err(err)
(Ok(mark1_anchor), Ok(mark2_anchor)) => {
let (advance_x, advance_y) = sum_advances_between(
deltas,
advances_x,
advances_y,
mark2_glyph_index,
i,
)
let dx = mark2_anchor.0 - mark1_anchor.0 - advance_x
let dy = mark2_anchor.1 - mark1_anchor.1 - advance_y
let delta = ValueRecord::{
x_placement: dx,
y_placement: dy,
x_advance: 0,
y_advance: 0,
}
deltas[i] = add_value_record(deltas[i], delta)
}
}
}
}
}
}
}
Ok(None) => ()
}
}
Ok(())
}
}
}
}
}
///|
fn read_anchor(
data : BytesView,
offset : Int,
) -> Result[(Int, Int), OtLayoutError] {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
let x = read_i16(data, offset + 2)
let y = read_i16(data, offset + 4)
match (x, y) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(x), Ok(y)) => Ok((x, y))
}
} else {
Err(InvalidFormat)
}
}
}
///|
fn apply_single_pos_subtable(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Unit, OtLayoutError] {
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
apply_single_pos_format1(
data,
offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
} else if format == 2 {
apply_single_pos_format2(
data,
offset,
glyphs,
deltas,
lookup_flag,
mark_filtering_set,
gdef,
)
} else {
Ok(())
}
}
}
///|
fn apply_single_pos_format1(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Unit, OtLayoutError] {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let value_format = read_u16_int(data, offset + 4)
match (coverage_offset, value_format) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(value_format)) => {
let coverage_base = offset + coverage_offset
let record_size = value_record_size(value_format)
let record_base = offset + 6
if record_base < 0 || record_base + record_size > data.length() {
return Err(UnexpectedEof)
}
let value = read_value_record(data, record_base, value_format)
match value {
Err(err) => Err(err)
Ok((value, _)) => {
for i in 0.. return Err(err)
Ok(true) => continue
Ok(false) => ()
}
let covered = coverage_index(data, coverage_base, glyph)
match covered {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(_)) =>
deltas[i] = add_value_record(deltas[i], value)
}
}
Ok(())
}
}
}
}
}
///|
fn apply_single_pos_format2(
data : BytesView,
offset : Int,
glyphs : ArrayView[UInt],
deltas : Array[ValueRecord],
lookup_flag : Int,
mark_filtering_set : Int?,
gdef : GdefTable?,
) -> Result[Unit, OtLayoutError] {
if offset < 0 || offset + 8 > data.length() {
return Err(UnexpectedEof)
}
let coverage_offset = read_u16_int(data, offset + 2)
let value_format = read_u16_int(data, offset + 4)
let value_count = read_u16_int(data, offset + 6)
match (coverage_offset, value_format, value_count) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(value_format), Ok(value_count)) => {
if value_count <= 0 {
return Err(InvalidFormat)
}
let coverage_base = offset + coverage_offset
let record_size = value_record_size(value_format)
let record_base = offset + 8
let total_size = value_count * record_size
if record_base < 0 || record_base + total_size > data.length() {
return Err(UnexpectedEof)
}
for i in 0.. return Err(err)
Ok(true) => continue
Ok(false) => ()
}
let index = coverage_index(data, coverage_base, glyph)
match index {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(index)) => {
if index < 0 || index >= value_count {
return Err(InvalidFormat)
}
let entry_base = record_base + index * record_size
let value = read_value_record(data, entry_base, value_format)
match value {
Err(err) => return Err(err)
Ok((value, _)) =>
deltas[i] = add_value_record(deltas[i], value)
}
}
}
}
Ok(())
}
}
}
///|
fn pair_adjust_format1(
data : BytesView,
offset : Int,
first : UInt,
second : UInt,
) -> Result[PairAdjust?, OtLayoutError] {
if offset < 0 || offset + 10 > data.length() {
return Err(UnexpectedEof)
}
if second > 0xffffU {
return Ok(None)
}
let coverage_offset = read_u16_int(data, offset + 2)
let value_format1 = read_u16_int(data, offset + 4)
let value_format2 = read_u16_int(data, offset + 6)
let pair_set_count = read_u16_int(data, offset + 8)
match (coverage_offset, value_format1, value_format2, pair_set_count) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(Ok(coverage_offset), Ok(value_format1), Ok(value_format2), Ok(pair_set_count)) => {
let coverage_base = offset + coverage_offset
let index = coverage_index(data, coverage_base, first)
match index {
Err(err) => Err(err)
Ok(None) => Ok(None)
Ok(Some(index)) => {
if index < 0 || index >= pair_set_count {
return Err(InvalidFormat)
}
let pair_offset_base = offset + 10
let pair_offset = read_u16_int(data, pair_offset_base + index * 2)
match pair_offset {
Err(err) => Err(err)
Ok(pair_offset) => {
let pair_base = offset + pair_offset
if pair_base < 0 || pair_base + 2 > data.length() {
return Err(UnexpectedEof)
}
let value_count = read_u16_int(data, pair_base)
match value_count {
Err(err) => Err(err)
Ok(value_count) => {
let record_size = 2 +
value_record_size(value_format1) +
value_record_size(value_format2)
let record_base = pair_base + 2
if record_base < 0 || record_base + value_count * record_size > data.length() {
return Err(UnexpectedEof)
}
for i in 0.. return Err(err)
Ok(second_glyph) => {
if second_glyph == u16_to_int(second) {
let value1 = read_value_record(
data,
entry_base + 2,
value_format1,
)
match value1 {
Err(err) => return Err(err)
Ok((value1, next_offset)) => {
let value2 = read_value_record(
data,
next_offset,
value_format2,
)
match value2 {
Err(err) => return Err(err)
Ok((value2, _)) =>
return Ok(
Some(PairAdjust::{
first: value1,
second: value2,
}),
)
}
}
}
}
}
}
}
Ok(None)
}
}
}
}
}
}
}
}
}
///|
fn pair_adjust_format2(
data : BytesView,
offset : Int,
first : UInt,
second : UInt,
) -> Result[PairAdjust?, OtLayoutError] {
if offset < 0 || offset + 16 > data.length() {
return Err(UnexpectedEof)
}
if first > 0xffffU || second > 0xffffU {
return Ok(None)
}
let coverage_offset = read_u16_int(data, offset + 2)
let value_format1 = read_u16_int(data, offset + 4)
let value_format2 = read_u16_int(data, offset + 6)
let class_def1_offset = read_u16_int(data, offset + 8)
let class_def2_offset = read_u16_int(data, offset + 10)
let class1_count = read_u16_int(data, offset + 12)
let class2_count = read_u16_int(data, offset + 14)
match (
coverage_offset,
value_format1,
value_format2,
class_def1_offset,
class_def2_offset,
class1_count,
class2_count,
) {
(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(coverage_offset),
Ok(value_format1),
Ok(value_format2),
Ok(class_def1_offset),
Ok(class_def2_offset),
Ok(class1_count),
Ok(class2_count),
) => {
if coverage_offset == 0 || class_def1_offset == 0 || class_def2_offset == 0 {
return Err(InvalidFormat)
}
if class1_count <= 0 || class2_count <= 0 {
return Err(InvalidFormat)
}
let coverage_base = offset + coverage_offset
let coverage = coverage_index(data, coverage_base, first)
match coverage {
Err(err) => Err(err)
Ok(None) => Ok(None)
Ok(Some(_)) => {
let class1 = class_def_value(data, offset + class_def1_offset, first)
let class2 = class_def_value(data, offset + class_def2_offset, second)
match (class1, class2) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(class1), Ok(class2)) => {
if class1 < 0 || class1 >= class1_count {
return Err(InvalidFormat)
}
if class2 < 0 || class2 >= class2_count {
return Err(InvalidFormat)
}
let record_size =
value_record_size(value_format1) + value_record_size(value_format2)
let class1_record_size = class2_count * record_size
let records_base = offset + 16
let total_size = class1_count * class1_record_size
if records_base < 0 || records_base + total_size > data.length() {
return Err(UnexpectedEof)
}
let entry_base =
records_base + class1 * class1_record_size + class2 * record_size
let value1 = read_value_record(data, entry_base, value_format1)
match value1 {
Err(err) => Err(err)
Ok((value1, next_offset)) => {
let value2 = read_value_record(data, next_offset, value_format2)
match value2 {
Err(err) => Err(err)
Ok((value2, _)) =>
Ok(Some(PairAdjust::{ first: value1, second: value2 }))
}
}
}
}
}
}
}
}
}
}
///|
fn value_record_size(format : Int) -> Int {
let mut size = 0
if (format & 0x0001) != 0 { size = size + 2 }
if (format & 0x0002) != 0 { size = size + 2 }
if (format & 0x0004) != 0 { size = size + 2 }
if (format & 0x0008) != 0 { size = size + 2 }
if (format & 0x0010) != 0 { size = size + 2 }
if (format & 0x0020) != 0 { size = size + 2 }
if (format & 0x0040) != 0 { size = size + 2 }
if (format & 0x0080) != 0 { size = size + 2 }
size
}
///|
fn read_value_record(
data : BytesView,
offset : Int,
format : Int,
) -> Result[(ValueRecord, Int), OtLayoutError] {
let mut current = offset
let mut record = value_record_zero()
if (format & 0x0001) != 0 {
let value = read_i16(data, current)
match value {
Err(err) => return Err(err)
Ok(value) => record = ValueRecord::{
x_placement: value,
y_placement: record.y_placement,
x_advance: record.x_advance,
y_advance: record.y_advance,
}
}
current = current + 2
}
if (format & 0x0002) != 0 {
let value = read_i16(data, current)
match value {
Err(err) => return Err(err)
Ok(value) => record = ValueRecord::{
x_placement: record.x_placement,
y_placement: value,
x_advance: record.x_advance,
y_advance: record.y_advance,
}
}
current = current + 2
}
if (format & 0x0004) != 0 {
let value = read_i16(data, current)
match value {
Err(err) => return Err(err)
Ok(value) => record = ValueRecord::{
x_placement: record.x_placement,
y_placement: record.y_placement,
x_advance: value,
y_advance: record.y_advance,
}
}
current = current + 2
}
if (format & 0x0008) != 0 {
let value = read_i16(data, current)
match value {
Err(err) => return Err(err)
Ok(value) => record = ValueRecord::{
x_placement: record.x_placement,
y_placement: record.y_placement,
x_advance: record.x_advance,
y_advance: value,
}
}
current = current + 2
}
if (format & 0x0010) != 0 {
let skip = read_u16_int(data, current)
match skip {
Err(err) => return Err(err)
Ok(_) => ()
}
current = current + 2
}
if (format & 0x0020) != 0 {
let skip = read_u16_int(data, current)
match skip {
Err(err) => return Err(err)
Ok(_) => ()
}
current = current + 2
}
if (format & 0x0040) != 0 {
let skip = read_u16_int(data, current)
match skip {
Err(err) => return Err(err)
Ok(_) => ()
}
current = current + 2
}
if (format & 0x0080) != 0 {
let skip = read_u16_int(data, current)
match skip {
Err(err) => return Err(err)
Ok(_) => ()
}
current = current + 2
}
Ok((record, current))
}
///|
fn class_def_value(
data : BytesView,
offset : Int,
glyph : UInt,
) -> Result[Int, OtLayoutError] {
if glyph > 0xffffU {
return Ok(0)
}
if offset < 0 || offset + 2 > data.length() {
return Err(UnexpectedEof)
}
let format = read_u16_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) => if format == 1 {
class_def_format1(data, offset, glyph)
} else if format == 2 {
class_def_format2(data, offset, glyph)
} else {
Err(InvalidFormat)
}
}
}
///|
fn class_def_format1(
data : BytesView,
offset : Int,
glyph : UInt,
) -> Result[Int, OtLayoutError] {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let start_glyph = read_u16_int(data, offset + 2)
let glyph_count = read_u16_int(data, offset + 4)
match (start_glyph, glyph_count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(start_glyph), Ok(glyph_count)) => {
if glyph_count <= 0 {
return Err(InvalidFormat)
}
let gid = u16_to_int(glyph)
if gid < start_glyph || gid >= start_glyph + glyph_count {
return Ok(0)
}
let index = gid - start_glyph
let class_base = offset + 6
if class_base < 0 || class_base + glyph_count * 2 > data.length() {
return Err(UnexpectedEof)
}
let value = read_u16_int(data, class_base + index * 2)
match value {
Err(err) => Err(err)
Ok(value) => Ok(value)
}
}
}
}
///|
fn class_def_format2(
data : BytesView,
offset : Int,
glyph : UInt,
) -> Result[Int, OtLayoutError] {
if offset < 0 || offset + 4 > data.length() {
return Err(UnexpectedEof)
}
let range_count = read_u16_int(data, offset + 2)
match range_count {
Err(err) => Err(err)
Ok(range_count) => {
if range_count < 0 {
return Err(InvalidFormat)
}
let record_base = offset + 4
if record_base < 0 || record_base + range_count * 6 > data.length() {
return Err(UnexpectedEof)
}
let gid = u16_to_int(glyph)
for i in 0.. return Err(err)
(_, Err(err), _) => return Err(err)
(_, _, Err(err)) => return Err(err)
(Ok(start), Ok(end), Ok(class_value)) => {
if gid >= start && gid <= end {
return Ok(class_value)
}
}
}
}
Ok(0)
}
}
}