// 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.
///|
suberror FontError {
FaceTable(@face.FaceTableError)
Parse(@sfnt.SfntError)
Var(@ot_var.VarError)
Cff(@ot_cff.CffError)
Layout(@ot_tables.OtLayoutError)
Color(@ot_color.ColorError)
Aat(@aat.AatError)
GlyphOutOfRange
} derive(Eq, Show, ToJson)
///|
/// Font ties a face to scale metrics.
pub struct Font {
face : @face.Face
mut scale_x : Int
mut scale_y : Int
mut ppem_x : Int
mut ppem_y : Int
mut head : @sfnt.HeadTable?
mut maxp : @sfnt.MaxpTable?
mut hhea : @sfnt.HheaTable?
mut hmtx : @sfnt.HmtxTable?
mut vhea : @sfnt.VheaTable?
mut vmtx : @sfnt.VmtxTable?
mut cmap : @sfnt.CmapTable?
mut loca : @sfnt.LocaTable?
mut glyf : @sfnt.GlyfTable?
mut os2 : @sfnt.Os2Table?
mut name : @sfnt.NameTable?
mut post : @sfnt.PostTable?
mut gasp : @sfnt.GaspTable?
mut meta : @sfnt.MetaTable?
mut vorg : @sfnt.VorgTable?
mut hdmx : @sfnt.HdmxTable?
mut stat : @sfnt.StatTable?
mut base : @sfnt.BaseTable?
mut jstf : @sfnt.JstfTable?
mut math : @sfnt.MathTable?
mut kern : @sfnt.KernTable?
mut trak : @aat.TrakTable?
mut morx : @aat.MorxTable?
mut mort : @aat.MortTable?
mut kerx : @aat.KerxTable?
mut ankr : @aat.AnkrTable?
mut bsln : @aat.BslnTable?
mut feat : @aat.FeatTable?
mut just : @aat.JustTable?
mut ltag : @aat.LtagTable?
mut opbd : @aat.OpbdTable?
mut gsub : @ot_tables.GsubTable?
mut gpos : @ot_tables.GposTable?
mut gdef : @ot_tables.GdefTable?
mut cpal : @ot_color.CpalTable?
mut colr : @ot_color.ColrTable?
mut hvar : @ot_var.HvarTable?
mut vvar : @ot_var.HvarTable?
mut mvar : @ot_var.MvarTable?
mut fvar : @ot_var.FvarTable?
mut avar : @ot_var.AvarTable?
mut cvt : @sfnt.CvtTable?
mut gvar : @ot_var.GvarTable?
mut cvar : @ot_var.CvarTable?
mut varc : @ot_var.VarcTable?
mut cff1 : @ot_cff.Cff1Table?
mut cff2 : @ot_cff.Cff2Table?
mut var_coords_design : Array[Double]?
mut var_coords_norm : Array[Int]?
} derive(Show, ToJson)
///|
let tag_head : @common.Tag = @common.Tag::from_chars('h', 'e', 'a', 'd')
///|
let tag_maxp : @common.Tag = @common.Tag::from_chars('m', 'a', 'x', 'p')
///|
let tag_hhea : @common.Tag = @common.Tag::from_chars('h', 'h', 'e', 'a')
///|
let tag_hmtx : @common.Tag = @common.Tag::from_chars('h', 'm', 't', 'x')
///|
let tag_vhea : @common.Tag = @common.Tag::from_chars('v', 'h', 'e', 'a')
///|
let tag_vmtx : @common.Tag = @common.Tag::from_chars('v', 'm', 't', 'x')
///|
let tag_cmap : @common.Tag = @common.Tag::from_chars('c', 'm', 'a', 'p')
///|
let tag_loca : @common.Tag = @common.Tag::from_chars('l', 'o', 'c', 'a')
///|
let tag_glyf : @common.Tag = @common.Tag::from_chars('g', 'l', 'y', 'f')
///|
let tag_os2 : @common.Tag = @common.Tag::from_chars('O', 'S', '/', '2')
///|
let tag_name : @common.Tag = @common.Tag::from_chars('n', 'a', 'm', 'e')
///|
let tag_post : @common.Tag = @common.Tag::from_chars('p', 'o', 's', 't')
///|
let tag_gasp : @common.Tag = @common.Tag::from_chars('g', 'a', 's', 'p')
///|
let tag_meta : @common.Tag = @common.Tag::from_chars('m', 'e', 't', 'a')
///|
let tag_vorg : @common.Tag = @common.Tag::from_chars('V', 'O', 'R', 'G')
///|
let tag_hdmx : @common.Tag = @common.Tag::from_chars('h', 'd', 'm', 'x')
///|
let tag_stat : @common.Tag = @common.Tag::from_chars('S', 'T', 'A', 'T')
///|
let tag_kern : @common.Tag = @common.Tag::from_chars('k', 'e', 'r', 'n')
///|
let tag_base : @common.Tag = @common.Tag::from_chars('B', 'A', 'S', 'E')
///|
let tag_jstf : @common.Tag = @common.Tag::from_chars('J', 'S', 'T', 'F')
///|
let tag_math : @common.Tag = @common.Tag::from_chars('M', 'A', 'T', 'H')
///|
let tag_gsub : @common.Tag = @common.Tag::from_chars('G', 'S', 'U', 'B')
///|
let tag_gpos : @common.Tag = @common.Tag::from_chars('G', 'P', 'O', 'S')
///|
let tag_gdef : @common.Tag = @common.Tag::from_chars('G', 'D', 'E', 'F')
///|
let tag_fvar : @common.Tag = @common.Tag::from_chars('f', 'v', 'a', 'r')
///|
let tag_avar : @common.Tag = @common.Tag::from_chars('a', 'v', 'a', 'r')
///|
let tag_hvar : @common.Tag = @common.Tag::from_chars('H', 'V', 'A', 'R')
///|
let tag_vvar : @common.Tag = @common.Tag::from_chars('V', 'V', 'A', 'R')
///|
let tag_mvar : @common.Tag = @common.Tag::from_chars('M', 'V', 'A', 'R')
///|
let tag_gvar : @common.Tag = @common.Tag::from_chars('g', 'v', 'a', 'r')
///|
let tag_cvar : @common.Tag = @common.Tag::from_chars('c', 'v', 'a', 'r')
///|
let tag_cvt : @common.Tag = @common.Tag::from_chars('c', 'v', 't', ' ')
///|
let tag_varc : @common.Tag = @common.Tag::from_chars('V', 'A', 'R', 'C')
///|
let tag_cff : @common.Tag = @common.Tag::from_chars('C', 'F', 'F', ' ')
///|
let tag_cff2 : @common.Tag = @common.Tag::from_chars('C', 'F', 'F', '2')
///|
let tag_cpal : @common.Tag = @common.Tag::from_chars('C', 'P', 'A', 'L')
///|
let tag_colr : @common.Tag = @common.Tag::from_chars('C', 'O', 'L', 'R')
///|
let tag_trak : @common.Tag = @common.Tag::from_chars('t', 'r', 'a', 'k')
///|
let tag_morx : @common.Tag = @common.Tag::from_chars('m', 'o', 'r', 'x')
///|
let tag_mort : @common.Tag = @common.Tag::from_chars('m', 'o', 'r', 't')
///|
let tag_kerx : @common.Tag = @common.Tag::from_chars('k', 'e', 'r', 'x')
///|
let tag_ankr : @common.Tag = @common.Tag::from_chars('a', 'n', 'k', 'r')
///|
let tag_bsln : @common.Tag = @common.Tag::from_chars('b', 's', 'l', 'n')
///|
let tag_feat : @common.Tag = @common.Tag::from_chars('f', 'e', 'a', 't')
///|
let tag_just : @common.Tag = @common.Tag::from_chars('j', 'u', 's', 't')
///|
let tag_ltag : @common.Tag = @common.Tag::from_chars('l', 't', 'a', 'g')
///|
let tag_opbd : @common.Tag = @common.Tag::from_chars('o', 'p', 'b', 'd')
///|
/// Create a font from a face.
pub fn Font::new(face : @face.Face) -> Font {
Font::{
face,
scale_x: 0,
scale_y: 0,
ppem_x: 0,
ppem_y: 0,
head: None,
maxp: None,
hhea: None,
hmtx: None,
vhea: None,
vmtx: None,
cmap: None,
loca: None,
glyf: None,
os2: None,
name: None,
post: None,
gasp: None,
meta: None,
vorg: None,
hdmx: None,
stat: None,
base: None,
jstf: None,
math: None,
kern: None,
trak: None,
morx: None,
mort: None,
kerx: None,
ankr: None,
bsln: None,
feat: None,
just: None,
ltag: None,
opbd: None,
gsub: None,
gpos: None,
gdef: None,
cpal: None,
colr: None,
hvar: None,
vvar: None,
mvar: None,
fvar: None,
avar: None,
cvt: None,
gvar: None,
cvar: None,
varc: None,
cff1: None,
cff2: None,
var_coords_design: None,
var_coords_norm: None,
}
}
///|
/// Create a font from raw bytes.
pub fn Font::from_bytes(bytes : Bytes) -> Font {
Font::new(@face.Face::from_bytes(bytes))
}
///|
/// Access the face.
pub fn Font::get_face(self : Font) -> @face.Face {
self.face
}
///|
/// Set scale values (in 26.6 fixed-point like HarfBuzz).
pub fn Font::set_scale(self : Font, x : Int, y : Int) -> Unit {
self.scale_x = x
self.scale_y = y
}
///|
/// Get scale values.
pub fn Font::get_scale(self : Font) -> (Int, Int) {
(self.scale_x, self.scale_y)
}
///|
/// Set ppem values.
pub fn Font::set_ppem(self : Font, x : Int, y : Int) -> Unit {
self.ppem_x = x
self.ppem_y = y
}
///|
/// Get ppem values.
pub fn Font::get_ppem(self : Font) -> (Int, Int) {
(self.ppem_x, self.ppem_y)
}
///|
fn Font::table_blob(
self : Font,
tag : @common.Tag,
) -> Result[@blob.Blob, FontError] {
match self.face.reference_table(tag) {
Err(err) => Err(FaceTable(err))
Ok(blob) => Ok(blob)
}
}
///|
fn Font::ensure_head(self : Font) -> Result[@sfnt.HeadTable, FontError] {
match self.head {
Some(head) => Ok(head)
None =>
match self.table_blob(tag_head) {
Err(err) => Err(err)
Ok(blob) =>
match @sfnt.HeadTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(head) => {
self.head = Some(head)
self.face.set_upem(head.units_per_em)
if self.scale_x == 0 {
self.scale_x = head.units_per_em
}
if self.scale_y == 0 {
self.scale_y = head.units_per_em
}
Ok(head)
}
}
}
}
}
///|
fn scale_value(value : Int, scale : Int, upem : Int) -> Int {
if upem == 0 {
return value
}
(value * scale) / upem
}
///|
fn Font::ensure_maxp(self : Font) -> Result[@sfnt.MaxpTable, FontError] {
match self.maxp {
Some(maxp) => Ok(maxp)
None =>
match self.table_blob(tag_maxp) {
Err(err) => Err(err)
Ok(blob) =>
match @sfnt.MaxpTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(maxp) => {
self.maxp = Some(maxp)
self.face.set_glyph_count(maxp.num_glyphs)
Ok(maxp)
}
}
}
}
}
///|
fn Font::ensure_hhea(self : Font) -> Result[@sfnt.HheaTable, FontError] {
match self.hhea {
Some(hhea) => Ok(hhea)
None =>
match self.table_blob(tag_hhea) {
Err(err) => Err(err)
Ok(blob) =>
match @sfnt.HheaTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(hhea) => {
self.hhea = Some(hhea)
Ok(hhea)
}
}
}
}
}
///|
fn Font::ensure_hmtx(self : Font) -> Result[@sfnt.HmtxTable, FontError] {
match self.hmtx {
Some(hmtx) => Ok(hmtx)
None => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(value) => value
}
let hhea = match self.ensure_hhea() {
Err(err) => return Err(err)
Ok(value) => value
}
match self.table_blob(tag_hmtx) {
Err(err) => Err(err)
Ok(blob) =>
match
@sfnt.HmtxTable::parse(
blob.as_view(),
maxp.num_glyphs,
hhea.number_of_hmetrics,
) {
Err(err) => Err(Parse(err))
Ok(hmtx) => {
self.hmtx = Some(hmtx)
Ok(hmtx)
}
}
}
}
}
}
///|
fn Font::ensure_vhea(self : Font) -> Result[@sfnt.VheaTable, FontError] {
match self.vhea {
Some(vhea) => Ok(vhea)
None =>
match self.table_blob(tag_vhea) {
Err(err) => Err(err)
Ok(blob) =>
match @sfnt.VheaTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(vhea) => {
self.vhea = Some(vhea)
Ok(vhea)
}
}
}
}
}
///|
///|
fn Font::ensure_cmap(self : Font) -> Result[@sfnt.CmapTable, FontError] {
match self.cmap {
Some(cmap) => Ok(cmap)
None =>
match self.table_blob(tag_cmap) {
Err(err) => Err(err)
Ok(blob) =>
match @sfnt.CmapTable::parse(blob) {
Err(err) => Err(Parse(err))
Ok(cmap) => {
self.cmap = Some(cmap)
Ok(cmap)
}
}
}
}
}
///|
fn Font::ensure_loca(self : Font) -> Result[@sfnt.LocaTable, FontError] {
match self.loca {
Some(loca) => Ok(loca)
None => {
let head = match self.ensure_head() {
Err(err) => return Err(err)
Ok(value) => value
}
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(value) => value
}
match self.table_blob(tag_loca) {
Err(err) => Err(err)
Ok(blob) =>
match
@sfnt.LocaTable::parse(
blob.as_view(),
maxp.num_glyphs,
head.index_to_loc_format,
) {
Err(err) => Err(Parse(err))
Ok(loca) => {
self.loca = Some(loca)
Ok(loca)
}
}
}
}
}
}
///|
fn Font::ensure_glyf(self : Font) -> Result[@sfnt.GlyfTable, FontError] {
match self.glyf {
Some(glyf) => Ok(glyf)
None =>
match self.table_blob(tag_glyf) {
Err(err) => Err(err)
Ok(blob) =>
match @sfnt.GlyfTable::parse(blob) {
Err(err) => Err(Parse(err))
Ok(glyf) => {
self.glyf = Some(glyf)
Ok(glyf)
}
}
}
}
}
///|
pub fn Font::os2(self : Font) -> Result[@sfnt.Os2Table?, FontError] {
match self.os2 {
Some(os2) => Ok(Some(os2))
None =>
match self.face.reference_table_optional(tag_os2) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.Os2Table::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(os2) => {
self.os2 = Some(os2)
Ok(Some(os2))
}
}
}
}
}
///|
pub fn Font::name(self : Font) -> Result[@sfnt.NameTable?, FontError] {
match self.name {
Some(name) => Ok(Some(name))
None =>
match self.face.reference_table_optional(tag_name) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.NameTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(name) => {
self.name = Some(name)
Ok(Some(name))
}
}
}
}
}
///|
pub fn Font::post(self : Font) -> Result[@sfnt.PostTable?, FontError] {
match self.post {
Some(post) => Ok(Some(post))
None =>
match self.face.reference_table_optional(tag_post) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.PostTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(post) => {
self.post = Some(post)
Ok(Some(post))
}
}
}
}
}
///|
pub fn Font::gasp(self : Font) -> Result[@sfnt.GaspTable?, FontError] {
match self.gasp {
Some(gasp) => Ok(Some(gasp))
None =>
match self.face.reference_table_optional(tag_gasp) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.GaspTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(gasp) => {
self.gasp = Some(gasp)
Ok(Some(gasp))
}
}
}
}
}
///|
pub fn Font::meta(self : Font) -> Result[@sfnt.MetaTable?, FontError] {
match self.meta {
Some(meta) => Ok(Some(meta))
None =>
match self.face.reference_table_optional(tag_meta) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.MetaTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(meta) => {
self.meta = Some(meta)
Ok(Some(meta))
}
}
}
}
}
///|
pub fn Font::vorg(self : Font) -> Result[@sfnt.VorgTable?, FontError] {
match self.vorg {
Some(vorg) => Ok(Some(vorg))
None =>
match self.face.reference_table_optional(tag_vorg) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.VorgTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(vorg) => {
self.vorg = Some(vorg)
Ok(Some(vorg))
}
}
}
}
}
///|
pub fn Font::hdmx(self : Font) -> Result[@sfnt.HdmxTable?, FontError] {
match self.hdmx {
Some(hdmx) => Ok(Some(hdmx))
None =>
match self.face.reference_table_optional(tag_hdmx) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.HdmxTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(hdmx) => {
self.hdmx = Some(hdmx)
Ok(Some(hdmx))
}
}
}
}
}
///|
pub fn Font::stat(self : Font) -> Result[@sfnt.StatTable?, FontError] {
match self.stat {
Some(stat) => Ok(Some(stat))
None =>
match self.face.reference_table_optional(tag_stat) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.StatTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(stat) => {
self.stat = Some(stat)
Ok(Some(stat))
}
}
}
}
}
///|
pub fn Font::vhea(self : Font) -> Result[@sfnt.VheaTable?, FontError] {
match self.vhea {
Some(vhea) => Ok(Some(vhea))
None =>
match self.face.reference_table_optional(tag_vhea) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.VheaTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(vhea) => {
self.vhea = Some(vhea)
Ok(Some(vhea))
}
}
}
}
}
///|
pub fn Font::vmtx(self : Font) -> Result[@sfnt.VmtxTable?, FontError] {
match self.vmtx {
Some(vmtx) => Ok(Some(vmtx))
None =>
match self.face.reference_table_optional(tag_vmtx) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(value) => value
}
let vhea = match self.ensure_vhea() {
Err(err) => return Err(err)
Ok(value) => value
}
match
@sfnt.VmtxTable::parse(
blob.as_view(),
maxp.num_glyphs,
vhea.number_of_vmetrics,
) {
Err(err) => Err(Parse(err))
Ok(vmtx) => {
self.vmtx = Some(vmtx)
Ok(Some(vmtx))
}
}
}
}
}
}
///|
pub fn Font::base(self : Font) -> Result[@sfnt.BaseTable?, FontError] {
match self.base {
Some(base) => Ok(Some(base))
None =>
match self.face.reference_table_optional(tag_base) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.BaseTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(base) => {
self.base = Some(base)
Ok(Some(base))
}
}
}
}
}
///|
pub fn Font::jstf(self : Font) -> Result[@sfnt.JstfTable?, FontError] {
match self.jstf {
Some(jstf) => Ok(Some(jstf))
None =>
match self.face.reference_table_optional(tag_jstf) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.JstfTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(jstf) => {
self.jstf = Some(jstf)
Ok(Some(jstf))
}
}
}
}
}
///|
pub fn Font::math(self : Font) -> Result[@sfnt.MathTable?, FontError] {
match self.math {
Some(math) => Ok(Some(math))
None =>
match self.face.reference_table_optional(tag_math) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.MathTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(math) => {
self.math = Some(math)
Ok(Some(math))
}
}
}
}
}
///|
pub fn Font::gsub(self : Font) -> Result[@ot_tables.GsubTable?, FontError] {
match self.gsub {
Some(gsub) => Ok(Some(gsub))
None =>
match self.face.reference_table_optional(tag_gsub) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_tables.GsubTable::parse(blob) {
Err(err) => Err(Layout(err))
Ok(gsub) => {
self.gsub = Some(gsub)
Ok(Some(gsub))
}
}
}
}
}
///|
pub fn Font::kern(self : Font) -> Result[@sfnt.KernTable?, FontError] {
match self.kern {
Some(kern) => Ok(Some(kern))
None =>
match self.face.reference_table_optional(tag_kern) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.KernTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(kern) => {
self.kern = Some(kern)
Ok(Some(kern))
}
}
}
}
}
///|
pub fn Font::trak(self : Font) -> Result[@aat.TrakTable?, FontError] {
match self.trak {
Some(trak) => Ok(Some(trak))
None =>
match self.face.reference_table_optional(tag_trak) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @aat.TrakTable::parse(blob.as_view()) {
Err(err) => Err(Aat(err))
Ok(trak) => {
self.trak = Some(trak)
Ok(Some(trak))
}
}
}
}
}
///|
pub fn Font::morx(self : Font) -> Result[@aat.MorxTable?, FontError] {
match self.morx {
Some(morx) => Ok(Some(morx))
None =>
match self.face.reference_table_optional(tag_morx) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(maxp) => maxp
}
match @aat.MorxTable::parse(blob.as_view(), maxp.num_glyphs) {
Err(err) => Err(Aat(err))
Ok(morx) => {
self.morx = Some(morx)
Ok(Some(morx))
}
}
}
}
}
}
///|
pub fn Font::mort(self : Font) -> Result[@aat.MortTable?, FontError] {
match self.mort {
Some(mort) => Ok(Some(mort))
None =>
match self.face.reference_table_optional(tag_mort) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(maxp) => maxp
}
match @aat.MortTable::parse(blob.as_view(), maxp.num_glyphs) {
Err(err) => Err(Aat(err))
Ok(mort) => {
self.mort = Some(mort)
Ok(Some(mort))
}
}
}
}
}
}
///|
pub fn Font::kerx(self : Font) -> Result[@aat.KerxTable?, FontError] {
match self.kerx {
Some(kerx) => Ok(Some(kerx))
None =>
match self.face.reference_table_optional(tag_kerx) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(maxp) => maxp
}
match @aat.KerxTable::parse(blob.as_view(), maxp.num_glyphs) {
Err(err) => Err(Aat(err))
Ok(kerx) => {
self.kerx = Some(kerx)
Ok(Some(kerx))
}
}
}
}
}
}
///|
pub fn Font::ankr(self : Font) -> Result[@aat.AnkrTable?, FontError] {
match self.ankr {
Some(ankr) => Ok(Some(ankr))
None =>
match self.face.reference_table_optional(tag_ankr) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(maxp) => maxp
}
match @aat.AnkrTable::parse(blob.as_view(), maxp.num_glyphs) {
Err(err) => Err(Aat(err))
Ok(ankr) => {
self.ankr = Some(ankr)
Ok(Some(ankr))
}
}
}
}
}
}
///|
pub fn Font::bsln(self : Font) -> Result[@aat.BslnTable?, FontError] {
match self.bsln {
Some(bsln) => Ok(Some(bsln))
None =>
match self.face.reference_table_optional(tag_bsln) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(maxp) => maxp
}
match @aat.BslnTable::parse(blob.as_view(), maxp.num_glyphs) {
Err(err) => Err(Aat(err))
Ok(bsln) => {
self.bsln = Some(bsln)
Ok(Some(bsln))
}
}
}
}
}
}
///|
pub fn Font::feat(self : Font) -> Result[@aat.FeatTable?, FontError] {
match self.feat {
Some(feat) => Ok(Some(feat))
None =>
match self.face.reference_table_optional(tag_feat) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @aat.FeatTable::parse(blob.as_view()) {
Err(err) => Err(Aat(err))
Ok(feat) => {
self.feat = Some(feat)
Ok(Some(feat))
}
}
}
}
}
///|
pub fn Font::just(self : Font) -> Result[@aat.JustTable?, FontError] {
match self.just {
Some(just) => Ok(Some(just))
None =>
match self.face.reference_table_optional(tag_just) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(maxp) => maxp
}
match @aat.JustTable::parse(blob.as_view(), maxp.num_glyphs) {
Err(err) => Err(Aat(err))
Ok(just) => {
self.just = Some(just)
Ok(Some(just))
}
}
}
}
}
}
///|
pub fn Font::ltag(self : Font) -> Result[@aat.LtagTable?, FontError] {
match self.ltag {
Some(ltag) => Ok(Some(ltag))
None =>
match self.face.reference_table_optional(tag_ltag) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @aat.LtagTable::parse(blob.as_view()) {
Err(err) => Err(Aat(err))
Ok(ltag) => {
self.ltag = Some(ltag)
Ok(Some(ltag))
}
}
}
}
}
///|
pub fn Font::opbd(self : Font) -> Result[@aat.OpbdTable?, FontError] {
match self.opbd {
Some(opbd) => Ok(Some(opbd))
None =>
match self.face.reference_table_optional(tag_opbd) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) => {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(maxp) => maxp
}
match @aat.OpbdTable::parse(blob.as_view(), maxp.num_glyphs) {
Err(err) => Err(Aat(err))
Ok(opbd) => {
self.opbd = Some(opbd)
Ok(Some(opbd))
}
}
}
}
}
}
///|
pub fn Font::gpos(self : Font) -> Result[@ot_tables.GposTable?, FontError] {
match self.gpos {
Some(gpos) => Ok(Some(gpos))
None =>
match self.face.reference_table_optional(tag_gpos) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_tables.GposTable::parse(blob) {
Err(err) => Err(Layout(err))
Ok(gpos) => {
self.gpos = Some(gpos)
Ok(Some(gpos))
}
}
}
}
}
///|
pub fn Font::gdef(self : Font) -> Result[@ot_tables.GdefTable?, FontError] {
match self.gdef {
Some(gdef) => Ok(Some(gdef))
None =>
match self.face.reference_table_optional(tag_gdef) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_tables.GdefTable::parse(blob) {
Err(err) => Err(Layout(err))
Ok(gdef) => {
self.gdef = Some(gdef)
Ok(Some(gdef))
}
}
}
}
}
///|
pub fn Font::cpal(self : Font) -> Result[@ot_color.CpalTable?, FontError] {
match self.cpal {
Some(cpal) => Ok(Some(cpal))
None =>
match self.face.reference_table_optional(tag_cpal) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_color.CpalTable::parse(blob.as_view()) {
Err(err) => Err(Color(err))
Ok(cpal) => {
self.cpal = Some(cpal)
Ok(Some(cpal))
}
}
}
}
}
///|
pub fn Font::colr(self : Font) -> Result[@ot_color.ColrTable?, FontError] {
match self.colr {
Some(colr) => Ok(Some(colr))
None =>
match self.face.reference_table_optional(tag_colr) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_color.ColrTable::parse(blob.as_view()) {
Err(err) => Err(Color(err))
Ok(colr) => {
self.colr = Some(colr)
Ok(Some(colr))
}
}
}
}
}
///|
pub fn Font::hvar(self : Font) -> Result[@ot_var.HvarTable?, FontError] {
match self.hvar {
Some(hvar) => Ok(Some(hvar))
None =>
match self.face.reference_table_optional(tag_hvar) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_var.HvarTable::parse(blob.as_view()) {
Err(err) => Err(Var(err))
Ok(hvar) => {
self.hvar = Some(hvar)
Ok(Some(hvar))
}
}
}
}
}
///|
pub fn Font::fvar(self : Font) -> Result[@ot_var.FvarTable?, FontError] {
match self.fvar {
Some(fvar) => Ok(Some(fvar))
None =>
match self.face.reference_table_optional(tag_fvar) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_var.FvarTable::parse(blob.as_view()) {
Err(err) => Err(Var(err))
Ok(fvar) => {
self.fvar = Some(fvar)
Ok(Some(fvar))
}
}
}
}
}
///|
pub fn Font::vvar(self : Font) -> Result[@ot_var.HvarTable?, FontError] {
match self.vvar {
Some(vvar) => Ok(Some(vvar))
None =>
match self.face.reference_table_optional(tag_vvar) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_var.HvarTable::parse(blob.as_view()) {
Err(err) => Err(Var(err))
Ok(vvar) => {
self.vvar = Some(vvar)
Ok(Some(vvar))
}
}
}
}
}
///|
pub fn Font::mvar(self : Font) -> Result[@ot_var.MvarTable?, FontError] {
match self.mvar {
Some(mvar) => Ok(Some(mvar))
None =>
match self.face.reference_table_optional(tag_mvar) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_var.MvarTable::parse(blob.as_view()) {
Err(err) => Err(Var(err))
Ok(mvar) => {
self.mvar = Some(mvar)
Ok(Some(mvar))
}
}
}
}
}
///|
pub fn Font::gvar(self : Font) -> Result[@ot_var.GvarTable?, FontError] {
match self.gvar {
Some(gvar) => Ok(Some(gvar))
None =>
match self.face.reference_table_optional(tag_gvar) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_var.GvarTable::parse(blob.as_view()) {
Err(err) => Err(Var(err))
Ok(gvar) => {
self.gvar = Some(gvar)
Ok(Some(gvar))
}
}
}
}
}
///|
pub fn Font::cvar(self : Font) -> Result[@ot_var.CvarTable?, FontError] {
match self.cvar {
Some(cvar) => Ok(Some(cvar))
None => {
let fvar = match self.fvar() {
Err(err) => return Err(err)
Ok(value) => value
}
let axis_count = match fvar {
None => return Ok(None)
Some(value) => value.axes().length()
}
match self.face.reference_table_optional(tag_cvar) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_var.CvarTable::parse(blob.as_view(), axis_count) {
Err(err) => Err(Var(err))
Ok(cvar) => {
self.cvar = Some(cvar)
Ok(Some(cvar))
}
}
}
}
}
}
///|
pub fn Font::varc(self : Font) -> Result[@ot_var.VarcTable?, FontError] {
match self.varc {
Some(varc) => Ok(Some(varc))
None =>
match self.face.reference_table_optional(tag_varc) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_var.VarcTable::parse(blob.as_view()) {
Err(err) => Err(Var(err))
Ok(varc) => {
self.varc = Some(varc)
Ok(Some(varc))
}
}
}
}
}
///|
pub fn Font::cff1(self : Font) -> Result[@ot_cff.Cff1Table?, FontError] {
match self.cff1 {
Some(cff1) => Ok(Some(cff1))
None =>
match self.face.reference_table_optional(tag_cff) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_cff.Cff1Table::parse(blob.as_view()) {
Err(err) => Err(Cff(err))
Ok(cff1) => {
self.cff1 = Some(cff1)
Ok(Some(cff1))
}
}
}
}
}
///|
pub fn Font::cff2(self : Font) -> Result[@ot_cff.Cff2Table?, FontError] {
match self.cff2 {
Some(cff2) => Ok(Some(cff2))
None =>
match self.face.reference_table_optional(tag_cff2) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_cff.Cff2Table::parse(blob.as_view()) {
Err(err) => Err(Cff(err))
Ok(cff2) => {
self.cff2 = Some(cff2)
Ok(Some(cff2))
}
}
}
}
}
///|
pub fn Font::varc_components(
self : Font,
glyph : UInt,
) -> Result[Array[@ot_var.VarcComponent]?, FontError] {
let varc = match self.varc() {
Err(err) => return Err(err)
Ok(value) => value
}
match varc {
None => Ok(None)
Some(varc) => {
let coords : Array[Int] = match self.var_coords_norm {
None => []
Some(value) => value
}
match varc.glyph_components(glyph.reinterpret_as_int(), coords, coords) {
Err(err) => Err(Var(err))
Ok(value) => Ok(Some(value))
}
}
}
}
///|
pub fn Font::mvar_delta(self : Font, tag : @common.Tag) -> Result[Double, FontError] {
match self.var_coords_norm {
None => Ok(0.0)
Some(coords) =>
match self.mvar() {
Err(err) => Err(err)
Ok(None) => Ok(0.0)
Ok(Some(mvar)) => Ok(mvar.get_var(tag, coords))
}
}
}
///|
pub fn Font::avar(self : Font) -> Result[@ot_var.AvarTable?, FontError] {
match self.avar {
Some(avar) => Ok(Some(avar))
None =>
match self.face.reference_table_optional(tag_avar) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @ot_var.AvarTable::parse(blob.as_view()) {
Err(err) => Err(Var(err))
Ok(avar) => {
self.avar = Some(avar)
Ok(Some(avar))
}
}
}
}
}
///|
pub fn Font::cvt(self : Font) -> Result[@sfnt.CvtTable?, FontError] {
match self.cvt {
Some(cvt) => Ok(Some(cvt))
None =>
match self.face.reference_table_optional(tag_cvt) {
Err(err) => Err(FaceTable(err))
Ok(None) => Ok(None)
Ok(Some(blob)) =>
match @sfnt.CvtTable::parse(blob.as_view()) {
Err(err) => Err(Parse(err))
Ok(cvt) => {
self.cvt = Some(cvt)
Ok(Some(cvt))
}
}
}
}
}
///|
pub fn Font::cvt_values(self : Font) -> Result[Array[Int]?, FontError] {
let cvt = match self.cvt() {
Err(err) => return Err(err)
Ok(None) => return Ok(None)
Ok(Some(value)) => value
}
let base = cvt.values().to_array()
match self.var_coords_norm {
None => Ok(Some(base))
Some(coords) =>
match self.cvar() {
Err(err) => Err(err)
Ok(None) => Ok(Some(base))
Ok(Some(cvar)) =>
match cvar.apply_to_cvt(base, coords) {
Err(err) => Err(Var(err))
Ok(values) => Ok(Some(values))
}
}
}
}
///|
/// Map a codepoint to a glyph id.
pub fn Font::glyph_for_codepoint(
self : Font,
codepoint : UInt,
) -> Result[UInt?, FontError] {
match self.ensure_cmap() {
Err(err) => Err(err)
Ok(cmap) =>
match cmap.glyph_for(codepoint) {
Err(err) => Err(Parse(err))
Ok(value) => Ok(value)
}
}
}
///|
/// Map a codepoint + variation selector to a glyph id, if supported.
pub fn Font::variation_glyph_for(
self : Font,
codepoint : UInt,
selector : UInt,
) -> Result[(Bool, UInt?), FontError] {
match self.ensure_cmap() {
Err(err) => Err(err)
Ok(cmap) =>
match cmap.variation_mapping(codepoint, selector) {
Err(err) => Err(Parse(err))
Ok(value) => Ok(value)
}
}
}
///|
pub fn Font::glyph_name(
self : Font,
glyph : UInt,
) -> Result[String?, FontError] {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(value) => value
}
let index = glyph.reinterpret_as_int()
if index < 0 || index >= maxp.num_glyphs {
return Ok(None)
}
let post = match self.post() {
Err(err) => return Err(err)
Ok(value) => value
}
match post {
Some(post) =>
match post.glyph_name(index) {
Some(name) => return Ok(Some(name))
None => ()
}
None => ()
}
let cff1 = match self.cff1() {
Err(err) => return Err(err)
Ok(value) => value
}
match cff1 {
None => Ok(None)
Some(cff1) =>
match cff1.glyph_name(index) {
Err(err) => Err(Cff(err))
Ok(value) => Ok(value)
}
}
}
///|
pub fn Font::glyph_from_name(
self : Font,
name : String,
) -> Result[UInt?, FontError] {
if name == "" {
return Ok(None)
}
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(value) => value
}
let post = match self.post() {
Err(err) => return Err(err)
Ok(value) => value
}
match post {
Some(post) =>
match post.glyph_from_name(name) {
None => ()
Some(glyph) => if glyph >= 0 && glyph < maxp.num_glyphs {
return Ok(Some(glyph.reinterpret_as_uint()))
}
}
None => ()
}
let cff1 = match self.cff1() {
Err(err) => return Err(err)
Ok(value) => value
}
match cff1 {
None => Ok(None)
Some(cff1) =>
match cff1.glyph_from_name(name) {
Err(err) => Err(Cff(err))
Ok(None) => Ok(None)
Ok(Some(glyph)) =>
if glyph < 0 || glyph >= maxp.num_glyphs {
Ok(None)
} else {
Ok(Some(glyph.reinterpret_as_uint()))
}
}
}
}
///|
pub fn Font::set_variations(
self : Font,
variations : Array[@ot_var.AxisCoord],
) -> Result[Unit, FontError] {
let fvar = match self.fvar() {
Err(err) => return Err(err)
Ok(value) => value
}
match fvar {
None => {
self.var_coords_design = None
self.var_coords_norm = None
Ok(())
}
Some(fvar) => {
let axis_count = fvar.axes.length()
let design_coords : Array[Double] = Array::make(axis_count, 0.0)
for i in 0.. ()
Some(index) => if index >= 0 && index < axis_count {
design_coords[index] = variation.value
}
}
}
let mut normalized = fvar.normalize_design_coords(design_coords.copy())
match self.avar() {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(avar)) => normalized = avar.map_coords_16_16(normalized)
}
for i in 0.. Array[Int] {
match self.var_coords_norm {
None => []
Some(coords) => coords.copy()
}
}
///|
/// Return glyph horizontal advance.
pub fn Font::glyph_h_advance(
self : Font,
glyph : UInt,
) -> Result[Int, FontError] {
let head = match self.ensure_head() {
Err(err) => return Err(err)
Ok(value) => value
}
let hmtx = match self.ensure_hmtx() {
Err(err) => return Err(err)
Ok(value) => value
}
let index = glyph.reinterpret_as_int()
if index < 0 || index >= hmtx.advances.length() {
return Err(GlyphOutOfRange)
}
let mut advance = hmtx.advances[index]
match self.var_coords_norm {
None => ()
Some(coords) => {
let hvar = match self.hvar() {
Err(err) => return Err(err)
Ok(value) => value
}
match hvar {
Some(hvar) => {
let delta = hvar.advance_delta(glyph, coords)
advance = advance + delta.round().to_int()
}
None =>
match self.gvar() {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(_)) =>
match self.glyph_gvar_advance(glyph, coords, false) {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(value)) => advance = value
}
}
}
}
}
Ok(scale_value(advance, self.scale_x, head.units_per_em))
}
///|
/// Return glyph bounds from glyf header (font units).
pub fn Font::glyph_bounds(
self : Font,
glyph : UInt,
) -> Result[@sfnt.GlyphBounds?, FontError] {
let coords : Array[Int] = match self.var_coords_norm {
None => []
Some(value) => value
}
self.glyph_bounds_with_coords(glyph, coords, 8)
}
fn Font::glyph_bounds_with_coords(
self : Font,
glyph : UInt,
coords : Array[Int],
depth : Int,
) -> Result[@sfnt.GlyphBounds?, FontError] {
if depth <= 0 {
return self.glyph_bounds_raw(glyph, coords)
}
let varc = match self.varc() {
Err(err) => return Err(err)
Ok(value) => value
}
match varc {
None => self.glyph_bounds_raw(glyph, coords)
Some(varc) => {
let components = match varc.glyph_components(glyph.reinterpret_as_int(), coords, coords) {
Err(err) => return Err(Var(err))
Ok(value) => value
}
if components.is_empty() {
return self.glyph_bounds_raw(glyph, coords)
}
let mut min_x : Double? = None
let mut min_y : Double? = None
let mut max_x : Double? = None
let mut max_y : Double? = None
for comp in components {
if !comp.visible {
continue
}
if comp.glyph < 0 {
continue
}
let bounds = match self.glyph_bounds_with_coords(
comp.glyph.reinterpret_as_uint(),
comp.coords,
depth - 1,
) {
Err(err) => return Err(err)
Ok(value) => value
}
match bounds {
None => ()
Some(bounds) => {
let (x0, y0, x1, y1) = comp.transform.apply_to_bounds(
bounds.x_min.to_double(),
bounds.y_min.to_double(),
bounds.x_max.to_double(),
bounds.y_max.to_double(),
)
let next_min_x = match min_x {
None => x0
Some(v) => if x0 < v { x0 } else { v }
}
let next_min_y = match min_y {
None => y0
Some(v) => if y0 < v { y0 } else { v }
}
let next_max_x = match max_x {
None => x1
Some(v) => if x1 > v { x1 } else { v }
}
let next_max_y = match max_y {
None => y1
Some(v) => if y1 > v { y1 } else { v }
}
min_x = Some(next_min_x)
min_y = Some(next_min_y)
max_x = Some(next_max_x)
max_y = Some(next_max_y)
}
}
}
match (min_x, min_y, max_x, max_y) {
(Some(min_x), Some(min_y), Some(max_x), Some(max_y)) => {
let x_min = @math.floor(min_x).to_int()
let y_min = @math.floor(min_y).to_int()
let x_max = @math.ceil(max_x).to_int()
let y_max = @math.ceil(max_y).to_int()
Ok(Some(@sfnt.GlyphBounds::new(-1, x_min, y_min, x_max, y_max)))
}
_ => self.glyph_bounds_raw(glyph, coords)
}
}
}
}
fn Font::glyph_bounds_raw(
self : Font,
glyph : UInt,
coords : Array[Int],
) -> Result[@sfnt.GlyphBounds?, FontError] {
let maxp = match self.ensure_maxp() {
Err(err) => return Err(err)
Ok(value) => value
}
let index = glyph.reinterpret_as_int()
if index < 0 || index >= maxp.num_glyphs {
return Err(GlyphOutOfRange)
}
let loca_blob = match self.face.reference_table_optional(tag_loca) {
Err(err) => return Err(FaceTable(err))
Ok(value) => value
}
let glyf_blob = match self.face.reference_table_optional(tag_glyf) {
Err(err) => return Err(FaceTable(err))
Ok(value) => value
}
if loca_blob is None || glyf_blob is None {
let cff2_bounds = match self.glyph_bounds_cff2(index, coords) {
Err(err) => return Err(err)
Ok(value) => value
}
match cff2_bounds {
Some(value) => return Ok(Some(value))
None => return self.glyph_bounds_cff1(index)
}
}
let loca = match self.ensure_loca() {
Err(err) => return Err(err)
Ok(value) => value
}
let glyf = match self.ensure_glyf() {
Err(err) => return Err(err)
Ok(value) => value
}
let offsets = loca.offsets
if index + 1 >= offsets.length() {
return Err(GlyphOutOfRange)
}
let start = offsets[index]
let end = offsets[index + 1]
let length = end - start
if !coords.is_empty() {
let gvar = match self.gvar() {
Err(err) => return Err(err)
Ok(value) => value
}
match gvar {
None => ()
Some(_) => {
let points = match self.glyph_points_with_gvar(glyph, coords) {
Err(err) => return Err(err)
Ok(value) => value
}
match points {
None => ()
Some(points) =>
match glyph_bounds_from_points_for_font(points) {
None => ()
Some(bounds) => return Ok(Some(bounds))
}
}
}
}
}
match glyf.glyph_bounds(start, length) {
Err(err) => Err(Parse(err))
Ok(bounds) => Ok(bounds)
}
}
fn Font::glyph_bounds_cff1(
self : Font,
glyph : Int,
) -> Result[@sfnt.GlyphBounds?, FontError] {
let cff1 = match self.cff1() {
Err(err) => return Err(err)
Ok(None) => return Ok(None)
Ok(Some(value)) => value
}
let bounds = match cff1.glyph_bounds(glyph) {
Err(err) => return Err(Cff(err))
Ok(value) => value
}
match bounds {
None => Ok(None)
Some(bounds) => {
let x_min = @math.floor(bounds.x_min).to_int()
let y_min = @math.floor(bounds.y_min).to_int()
let x_max = @math.ceil(bounds.x_max).to_int()
let y_max = @math.ceil(bounds.y_max).to_int()
Ok(Some(@sfnt.GlyphBounds::new(-1, x_min, y_min, x_max, y_max)))
}
}
}
fn Font::glyph_bounds_cff2(
self : Font,
glyph : Int,
coords : Array[Int],
) -> Result[@sfnt.GlyphBounds?, FontError] {
let cff2 = match self.cff2() {
Err(err) => return Err(err)
Ok(None) => return Ok(None)
Ok(Some(value)) => value
}
let bounds = match cff2.glyph_bounds(glyph, coords) {
Err(err) => return Err(Cff(err))
Ok(value) => value
}
match bounds {
None => Ok(None)
Some(bounds) => {
let x_min = @math.floor(bounds.x_min).to_int()
let y_min = @math.floor(bounds.y_min).to_int()
let x_max = @math.ceil(bounds.x_max).to_int()
let y_max = @math.ceil(bounds.y_max).to_int()
Ok(Some(@sfnt.GlyphBounds::new(-1, x_min, y_min, x_max, y_max)))
}
}
}
///|
/// Return glyph vertical advance.
pub fn Font::glyph_v_advance(
self : Font,
glyph : UInt,
) -> Result[Int, FontError] {
let head = match self.ensure_head() {
Err(err) => return Err(err)
Ok(value) => value
}
let vmtx = match self.vmtx() {
Err(err) => return Err(err)
Ok(None) => return Ok(0)
Ok(Some(value)) => value
}
let index = glyph.reinterpret_as_int()
if index < 0 || index >= vmtx.advances.length() {
return Err(GlyphOutOfRange)
}
let mut advance = vmtx.advances[index]
match self.var_coords_norm {
None => ()
Some(coords) => {
let vvar = match self.vvar() {
Err(err) => return Err(err)
Ok(value) => value
}
match vvar {
Some(vvar) => {
let delta = vvar.advance_delta(glyph, coords)
advance = advance + delta.round().to_int()
}
None =>
match self.gvar() {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(_)) =>
match self.glyph_gvar_advance(glyph, coords, true) {
Err(err) => return Err(err)
Ok(None) => ()
Ok(Some(value)) => advance = value
}
}
}
}
}
Ok(-scale_value(advance, self.scale_y, head.units_per_em))
}