///|
/// Reconstruct glyf and loca tables from WOFF2 transformed format.
/// Returns (glyf_data, loca_data, x_mins) or None on error.
fn reconstruct_glyf_loca(
data : Bytes,
src_offset : Int,
src_length : Int,
) -> (Bytes, Bytes, Array[Int])? {
ignore(src_length)
let reader = BinaryReader::at(data, src_offset)
// Transformed glyf header (36 bytes)
let _reserved = reader.read_uint16()
let option_flags = reader.read_uint16()
let num_glyphs = reader.read_uint16()
let index_format = reader.read_uint16()
let n_contour_stream_size = reader.read_uint32()
let n_points_stream_size = reader.read_uint32()
let flag_stream_size = reader.read_uint32()
let glyph_stream_size = reader.read_uint32()
let composite_stream_size = reader.read_uint32()
let bbox_stream_size = reader.read_uint32()
let instruction_stream_size = reader.read_uint32()
// Set up 7 substream readers
let mut offset = src_offset + 36
let n_contour_reader = BinaryReader::at(data, offset)
offset += n_contour_stream_size
let n_points_reader = BinaryReader::at(data, offset)
offset += n_points_stream_size
let flag_reader = BinaryReader::at(data, offset)
offset += flag_stream_size
let glyph_reader = BinaryReader::at(data, offset)
offset += glyph_stream_size
let composite_reader = BinaryReader::at(data, offset)
offset += composite_stream_size
let bbox_reader = BinaryReader::at(data, offset)
offset += bbox_stream_size
let instruction_reader = BinaryReader::at(data, offset)
// Overlap bitmap (optional, after instruction stream)
let has_overlap_bitmap = (option_flags & 1) != 0
let overlap_bitmap_offset = offset + instruction_stream_size
// Read bbox bitmap
let bbox_bitmap_length = (num_glyphs + 31) >> 5 << 2
let bbox_bitmap_start = bbox_reader.position()
bbox_reader.skip(bbox_bitmap_length)
// Output
let glyf_out : Array[Byte] = []
let loca_values : Array[Int] = Array::make(num_glyphs + 1, 0)
let x_mins : Array[Int] = Array::make(num_glyphs, 0)
// Process each glyph
for glyph_id = 0; glyph_id < num_glyphs; glyph_id = glyph_id + 1 {
loca_values[glyph_id] = glyf_out.length()
let n_contours = n_contour_reader.read_int16()
let have_bbox = {
let byte_idx = glyph_id >> 3
let bit_idx = 7 - (glyph_id & 7)
(data[bbox_bitmap_start + byte_idx].to_int() & (1 << bit_idx)) != 0
}
if n_contours == 0 {
// Empty glyph - no data
()
} else if n_contours == -1 {
// Composite glyph (must have explicit bbox)
if !have_bbox {
return None
}
// nContours = -1
write_be16_arr(glyf_out, -1)
// bbox from bbox stream
let bx_min = bbox_reader.read_int16()
let by_min = bbox_reader.read_int16()
let bx_max = bbox_reader.read_int16()
let by_max = bbox_reader.read_int16()
write_be16_arr(glyf_out, bx_min)
write_be16_arr(glyf_out, by_min)
write_be16_arr(glyf_out, bx_max)
write_be16_arr(glyf_out, by_max)
x_mins[glyph_id] = bx_min
// Read composite data
let have_instructions = read_composite_glyph(composite_reader, glyf_out)
if have_instructions {
let instruction_size = read_255ushort(glyph_reader)
write_be16_arr(glyf_out, instruction_size)
for j = 0; j < instruction_size; j = j + 1 {
glyf_out.push(instruction_reader.read_uint8().to_byte())
}
}
// Pad to 4-byte boundary
while glyf_out.length() % 4 != 0 {
glyf_out.push(b'\x00')
}
} else {
// Simple glyph
let mut total_points = 0
let end_points : Array[Int] = Array::make(n_contours, 0)
let mut end_point = -1
for c = 0; c < n_contours; c = c + 1 {
let n = read_255ushort(n_points_reader)
total_points += n
end_point += n
end_points[c] = end_point
ignore(c)
}
// Check overlap bitmap
let has_overlap = has_overlap_bitmap &&
({
let byte_idx = glyph_id >> 3
let bit_idx = 7 - (glyph_id & 7)
(data[overlap_bitmap_offset + byte_idx].to_int() & (1 << bit_idx)) !=
0
})
// Decode triplet-encoded points → TrueType format
let (
flags_bytes,
x_bytes,
y_bytes,
comp_x_min,
comp_y_min,
comp_x_max,
comp_y_max,
) = decode_triplets_to_truetype(
flag_reader, glyph_reader, total_points, has_overlap,
)
// Read instruction size
let instruction_size = read_255ushort(glyph_reader)
// Write nContours
write_be16_arr(glyf_out, n_contours)
// Write bbox
if have_bbox {
let bx_min = bbox_reader.read_int16()
let by_min = bbox_reader.read_int16()
let bx_max = bbox_reader.read_int16()
let by_max = bbox_reader.read_int16()
write_be16_arr(glyf_out, bx_min)
write_be16_arr(glyf_out, by_min)
write_be16_arr(glyf_out, bx_max)
write_be16_arr(glyf_out, by_max)
x_mins[glyph_id] = bx_min
} else {
write_be16_arr(glyf_out, comp_x_min)
write_be16_arr(glyf_out, comp_y_min)
write_be16_arr(glyf_out, comp_x_max)
write_be16_arr(glyf_out, comp_y_max)
x_mins[glyph_id] = comp_x_min
}
// Write end points of contours
for c = 0; c < n_contours; c = c + 1 {
write_be16_arr(glyf_out, end_points[c])
ignore(c)
}
// Write instructions
write_be16_arr(glyf_out, instruction_size)
for j = 0; j < instruction_size; j = j + 1 {
glyf_out.push(instruction_reader.read_uint8().to_byte())
}
// Write flags
for j = 0; j < flags_bytes.length(); j = j + 1 {
glyf_out.push(flags_bytes[j])
}
// Write x coordinates
for j = 0; j < x_bytes.length(); j = j + 1 {
glyf_out.push(x_bytes[j])
}
// Write y coordinates
for j = 0; j < y_bytes.length(); j = j + 1 {
glyf_out.push(y_bytes[j])
}
// Pad to 4-byte boundary
while glyf_out.length() % 4 != 0 {
glyf_out.push(b'\x00')
}
}
ignore(glyph_id)
}
// Final loca entry
loca_values[num_glyphs] = glyf_out.length()
// Build loca table
let loca_size = if index_format != 0 {
(num_glyphs + 1) * 4
} else {
(num_glyphs + 1) * 2
}
let loca_out : Array[Byte] = Array::make(loca_size, b'\x00')
for i = 0; i <= num_glyphs; i = i + 1 {
if index_format != 0 {
loca_out[i * 4] = ((loca_values[i] >> 24) & 0xFF).to_byte()
loca_out[i * 4 + 1] = ((loca_values[i] >> 16) & 0xFF).to_byte()
loca_out[i * 4 + 2] = ((loca_values[i] >> 8) & 0xFF).to_byte()
loca_out[i * 4 + 3] = (loca_values[i] & 0xFF).to_byte()
} else {
let v = loca_values[i] >> 1
loca_out[i * 2] = ((v >> 8) & 0xFF).to_byte()
loca_out[i * 2 + 1] = (v & 0xFF).to_byte()
}
ignore(i)
}
let glyf_bytes = Bytes::from_array(glyf_out[:])
let loca_bytes = Bytes::from_array(loca_out[:])
Some((glyf_bytes, loca_bytes, x_mins))
}
///|
/// Read a composite glyph from the composite stream, appending data to glyf_out.
/// Returns whether the glyph has instructions.
fn read_composite_glyph(
composite_reader : BinaryReader,
glyf_out : Array[Byte],
) -> Bool {
let flag_arg_1_and_2_are_words = 1
let flag_we_have_a_scale = 8
let flag_more_components = 32
let flag_we_have_an_x_and_y_scale = 64
let flag_we_have_a_two_by_two = 128
let flag_we_have_instructions = 256
let mut have_instructions = false
let mut more = true
while more {
let flags = composite_reader.read_uint16()
have_instructions = have_instructions ||
(flags & flag_we_have_instructions) != 0
more = (flags & flag_more_components) != 0
// Write flags word
glyf_out.push(((flags >> 8) & 0xFF).to_byte())
glyf_out.push((flags & 0xFF).to_byte())
// Glyph index (uint16) + arguments + optional scale/matrix
let mut arg_size = 2 // glyph index
if (flags & flag_arg_1_and_2_are_words) != 0 {
arg_size += 4
} else {
arg_size += 2
}
if (flags & flag_we_have_a_scale) != 0 {
arg_size += 2
} else if (flags & flag_we_have_an_x_and_y_scale) != 0 {
arg_size += 4
} else if (flags & flag_we_have_a_two_by_two) != 0 {
arg_size += 8
}
for j = 0; j < arg_size; j = j + 1 {
glyf_out.push(composite_reader.read_uint8().to_byte())
}
}
have_instructions
}
///|
/// Decode WOFF2 triplet-encoded points and re-encode to TrueType format.
/// Returns (flags_bytes, x_bytes, y_bytes, xMin, yMin, xMax, yMax)
fn decode_triplets_to_truetype(
flag_reader : BinaryReader,
glyph_reader : BinaryReader,
n_points : Int,
has_overlap_bit : Bool,
) -> (Array[Byte], Array[Byte], Array[Byte], Int, Int, Int, Int) {
// TrueType simple glyph flag bits
let tt_on_curve = 1
let tt_x_short = 2
let tt_y_short = 4
let tt_repeat = 8
let tt_x_same = 16
let tt_y_same = 32
let tt_overlap_simple = 64
let flags_out : Array[Byte] = []
let x_out : Array[Byte] = []
let y_out : Array[Byte] = []
let mut x = 0
let mut y = 0
let mut x_min = 0
let mut y_min = 0
let mut x_max = 0
let mut y_max = 0
let mut last_flag = -1
let mut repeat_count = 0
for i = 0; i < n_points; i = i + 1 {
let flag = flag_reader.read_uint8()
let on_curve = (flag & 0x80) == 0 // bit 7 = 0 means on-curve in WOFF2
let flag_low = flag & 0x7F
let mut dx = 0
let mut dy = 0
if flag_low < 10 {
// dx = 0, dy from 1 byte
dx = 0
let b = glyph_reader.read_uint8()
dy = ((flag_low & 14) << 7) + b
if (flag_low & 1) == 0 {
dy = -dy
}
} else if flag_low < 20 {
// dy = 0, dx from 1 byte
let b = glyph_reader.read_uint8()
dx = (((flag_low - 10) & 14) << 7) + b
if (flag_low & 1) == 0 {
dx = -dx
}
dy = 0
} else if flag_low < 84 {
// 1 byte packed dx, dy (4 bits each with offsets)
let b = glyph_reader.read_uint8()
let b0 = flag_low - 20
dx = 1 + (b0 & 0x30) + (b >> 4)
dy = 1 + ((b0 & 0x0C) << 2) + (b & 0x0F)
if (flag_low & 1) == 0 {
dx = -dx
}
if (flag_low & 2) == 0 {
dy = -dy
}
} else if flag_low < 120 {
// 2 bytes: 1 byte dx, 1 byte dy with offsets
let b0 = glyph_reader.read_uint8()
let b1 = glyph_reader.read_uint8()
let idx = flag_low - 84
dx = 1 + ((idx / 12) << 8) + b0
dy = 1 + ((idx % 12) >> 2 << 8) + b1
if (flag_low & 1) == 0 {
dx = -dx
}
if (flag_low & 2) == 0 {
dy = -dy
}
} else if flag_low < 124 {
// 3 bytes: 12-bit dx, 12-bit dy
let b0 = glyph_reader.read_uint8()
let b1 = glyph_reader.read_uint8()
let b2 = glyph_reader.read_uint8()
dx = (b0 << 4) + (b1 >> 4)
dy = ((b1 & 0x0F) << 8) + b2
if (flag_low & 1) == 0 {
dx = -dx
}
if (flag_low & 2) == 0 {
dy = -dy
}
} else {
// 4 bytes: 16-bit dx, 16-bit dy
let b0 = glyph_reader.read_uint8()
let b1 = glyph_reader.read_uint8()
let b2 = glyph_reader.read_uint8()
let b3 = glyph_reader.read_uint8()
dx = (b0 << 8) + b1
dy = (b2 << 8) + b3
if (flag_low & 1) == 0 {
dx = -dx
}
if (flag_low & 2) == 0 {
dy = -dy
}
}
x += dx
y += dy
if i == 0 {
x_min = x
x_max = x
y_min = y
y_max = y
} else {
if x < x_min {
x_min = x
}
if x > x_max {
x_max = x
}
if y < y_min {
y_min = y
}
if y > y_max {
y_max = y
}
}
// Build TrueType flag byte
let mut out_flag = if on_curve { tt_on_curve } else { 0 }
if has_overlap_bit && i == 0 {
out_flag = out_flag | tt_overlap_simple
}
// Encode x coordinate delta
if dx == 0 {
out_flag = out_flag | tt_x_same
} else if dx >= -255 && dx <= 255 {
out_flag = out_flag | tt_x_short
if dx > 0 {
out_flag = out_flag | tt_x_same
}
let abs_dx = if dx > 0 { dx } else { -dx }
x_out.push(abs_dx.to_byte())
} else {
// 2-byte signed delta
x_out.push(((dx >> 8) & 0xFF).to_byte())
x_out.push((dx & 0xFF).to_byte())
}
// Encode y coordinate delta
if dy == 0 {
out_flag = out_flag | tt_y_same
} else if dy >= -255 && dy <= 255 {
out_flag = out_flag | tt_y_short
if dy > 0 {
out_flag = out_flag | tt_y_same
}
let abs_dy = if dy > 0 { dy } else { -dy }
y_out.push(abs_dy.to_byte())
} else {
// 2-byte signed delta
y_out.push(((dy >> 8) & 0xFF).to_byte())
y_out.push((dy & 0xFF).to_byte())
}
// TrueType flag repeat compression
if out_flag == last_flag && repeat_count < 255 {
let idx = flags_out.length() - 1
flags_out[idx] = (flags_out[idx].to_int() | tt_repeat).to_byte()
repeat_count += 1
} else {
if repeat_count > 0 {
flags_out.push(repeat_count.to_byte())
repeat_count = 0
}
flags_out.push(out_flag.to_byte())
last_flag = out_flag
}
ignore(i)
}
if repeat_count > 0 {
flags_out.push(repeat_count.to_byte())
}
(flags_out, x_out, y_out, x_min, y_min, x_max, y_max)
}
///|
/// Reconstruct hmtx table from WOFF2 transformed format
fn reconstruct_hmtx(
data : Bytes,
src_offset : Int,
src_length : Int,
num_glyphs : Int,
num_h_metrics : Int,
x_mins : Array[Int],
) -> Bytes {
ignore(src_length)
let reader = BinaryReader::at(data, src_offset)
let hmtx_flags = reader.read_uint8()
let has_proportional_lsbs = (hmtx_flags & 1) == 0
let has_monospace_lsbs = (hmtx_flags & 2) == 0
// Read advance widths
let advance_widths : Array[Int] = Array::make(num_h_metrics, 0)
for i = 0; i < num_h_metrics; i = i + 1 {
advance_widths[i] = reader.read_uint16()
ignore(i)
}
// Read LSBs
let lsbs : Array[Int] = Array::make(num_glyphs, 0)
for i = 0; i < num_h_metrics; i = i + 1 {
if has_proportional_lsbs {
lsbs[i] = reader.read_int16()
} else {
lsbs[i] = if i < x_mins.length() { x_mins[i] } else { 0 }
}
ignore(i)
}
for i = num_h_metrics; i < num_glyphs; i = i + 1 {
if has_monospace_lsbs {
lsbs[i] = reader.read_int16()
} else {
lsbs[i] = if i < x_mins.length() { x_mins[i] } else { 0 }
}
ignore(i)
}
// Build output: numHMetrics * 4 + (numGlyphs - numHMetrics) * 2
let output_size = num_h_metrics * 4 + (num_glyphs - num_h_metrics) * 2
let out : Array[Byte] = Array::make(output_size, b'\x00')
let mut offset = 0
for i = 0; i < num_glyphs; i = i + 1 {
if i < num_h_metrics {
out[offset] = ((advance_widths[i] >> 8) & 0xFF).to_byte()
out[offset + 1] = (advance_widths[i] & 0xFF).to_byte()
offset += 2
}
let lsb = lsbs[i]
out[offset] = ((lsb >> 8) & 0xFF).to_byte()
out[offset + 1] = (lsb & 0xFF).to_byte()
offset += 2
ignore(i)
}
Bytes::from_array(out[:])
}