diff --git a/CHANGELOG.md b/CHANGELOG.md index 538bbbf..7af35a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- `Face::permissions` +- `Face::is_subsetting_allowed` +- `Face::is_bitmap_embedding_allowed` +- `Face::unicode_ranges` +- `os2::Table::permissions` +- `os2::Table::is_subsetting_allowed` +- `os2::Table::is_bitmap_embedding_allowed` +- `os2::Table::unicode_ranges` ## [0.17.0] - 2022-09-28 ### Added diff --git a/examples/font-info.rs b/examples/font-info.rs index 7f974c0..6b2c42c 100644 --- a/examples/font-info.rs +++ b/examples/font-info.rs @@ -48,6 +48,7 @@ fn main() { println!("Strikeout: {:?}", face.strikeout_metrics()); println!("Subscript: {:?}", face.subscript_metrics()); println!("Superscript: {:?}", face.superscript_metrics()); + println!("Permissions: {:?}", face.permissions()); println!("Variable: {:?}", face.is_variable()); #[cfg(feature = "opentype-layout")] diff --git a/src/lib.rs b/src/lib.rs index c930c27..9efc90a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ use parser::{NumFrom, Offset, Offset32, Stream, TryNumFrom}; pub use fvar::VariationAxis; pub use name::{name_id, PlatformId}; -pub use os2::{ScriptMetrics, Style, Weight, Width}; +pub use os2::{Permissions, ScriptMetrics, Style, UnicodeRanges, Weight, Width}; pub use tables::CFFError; #[cfg(feature = "apple-layout")] pub use tables::{ankr, feat, kerx, morx, trak}; @@ -1490,6 +1490,41 @@ impl<'a> Face<'a> { Some(metrics) } + /// Returns face permissions. + /// + /// Returns `None` in case of a malformed value. + #[inline] + pub fn permissions(&self) -> Option { + self.tables.os2?.permissions() + } + + /// Checks if the face subsetting is allowed. + #[inline] + pub fn is_subsetting_allowed(&self) -> bool { + self.tables + .os2 + .map(|t| t.is_subsetting_allowed()) + .unwrap_or(false) + } + + /// Checks if the face bitmaps embedding is allowed. + #[inline] + pub fn is_bitmap_embedding_allowed(&self) -> bool { + self.tables + .os2 + .map(|t| t.is_bitmap_embedding_allowed()) + .unwrap_or(false) + } + + /// Checks if the face bitmaps embedding is allowed. + #[inline] + pub fn unicode_ranges(&self) -> UnicodeRanges { + self.tables + .os2 + .map(|t| t.unicode_ranges()) + .unwrap_or_default() + } + /// Returns a total number of glyphs in the face. /// /// Never zero. diff --git a/src/tables/os2.rs b/src/tables/os2.rs index bde42e8..9040565 100644 --- a/src/tables/os2.rs +++ b/src/tables/os2.rs @@ -6,11 +6,13 @@ use crate::LineMetrics; const WEIGHT_CLASS_OFFSET: usize = 4; const WIDTH_CLASS_OFFSET: usize = 6; +const TYPE_OFFSET: usize = 8; const Y_SUBSCRIPT_X_SIZE_OFFSET: usize = 10; const Y_SUPERSCRIPT_X_SIZE_OFFSET: usize = 18; const Y_STRIKEOUT_SIZE_OFFSET: usize = 26; const Y_STRIKEOUT_POSITION_OFFSET: usize = 28; -const FS_SELECTION_OFFSET: usize = 62; +const UNICODE_RANGES_OFFSET: usize = 42; +const SELECTION_OFFSET: usize = 62; const TYPO_ASCENDER_OFFSET: usize = 68; const TYPO_DESCENDER_OFFSET: usize = 70; const TYPO_LINE_GAP_OFFSET: usize = 72; @@ -119,6 +121,16 @@ impl Default for Width { } } +/// Face [permissions](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fst). +#[allow(missing_docs)] +#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] +pub enum Permissions { + Installable, + Restricted, + PreviewAndPrint, + Editable, +} + /// A face style. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum Style { @@ -167,6 +179,186 @@ impl SelectionFlags { #[inline] fn oblique(self) -> bool { self.0 & (1 << 9) != 0 } } +/// [Unicode Ranges](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur). +#[derive(Clone, Copy, Default, Debug)] +pub struct UnicodeRanges(u128); + +impl UnicodeRanges { + /// Checks if ranges contain the specified character. + pub fn contains_char(&self, c: char) -> bool { + let range = char_range_index(c); + if range >= 0 { + self.0 & (1 << range as u128) != 0 + } else { + false + } + } +} + +fn char_range_index(c: char) -> i8 { + match c as u32 { + 0x0000..=0x007F => 0, + 0x0080..=0x00FF => 1, + 0x0100..=0x017F => 2, + 0x0180..=0x024F => 3, + 0x0250..=0x02AF => 4, + 0x1D00..=0x1DBF => 4, + 0x02B0..=0x02FF => 5, + 0xA700..=0xA71F => 5, + 0x0300..=0x036F => 6, + 0x1DC0..=0x1DFF => 6, + 0x0370..=0x03FF => 7, + 0x2C80..=0x2CFF => 8, + 0x0400..=0x052F => 9, + 0x2DE0..=0x2DFF => 9, + 0xA640..=0xA69F => 9, + 0x0530..=0x058F => 10, + 0x0590..=0x05FF => 11, + 0xA500..=0xA63F => 12, + 0x0600..=0x06FF => 13, + 0x0750..=0x077F => 13, + 0x07C0..=0x07FF => 14, + 0x0900..=0x097F => 15, + 0x0980..=0x09FF => 16, + 0x0A00..=0x0A7F => 17, + 0x0A80..=0x0AFF => 18, + 0x0B00..=0x0B7F => 19, + 0x0B80..=0x0BFF => 20, + 0x0C00..=0x0C7F => 21, + 0x0C80..=0x0CFF => 22, + 0x0D00..=0x0D7F => 23, + 0x0E00..=0x0E7F => 24, + 0x0E80..=0x0EFF => 25, + 0x10A0..=0x10FF => 26, + 0x2D00..=0x2D2F => 26, + 0x1B00..=0x1B7F => 27, + 0x1100..=0x11FF => 28, + 0x1E00..=0x1EFF => 29, + 0x2C60..=0x2C7F => 29, + 0xA720..=0xA7FF => 29, + 0x1F00..=0x1FFF => 30, + 0x2000..=0x206F => 31, + 0x2E00..=0x2E7F => 31, + 0x2070..=0x209F => 32, + 0x20A0..=0x20CF => 33, + 0x20D0..=0x20FF => 34, + 0x2100..=0x214F => 35, + 0x2150..=0x218F => 36, + 0x2190..=0x21FF => 37, + 0x27F0..=0x27FF => 37, + 0x2900..=0x297F => 37, + 0x2B00..=0x2BFF => 37, + 0x2200..=0x22FF => 38, + 0x2A00..=0x2AFF => 38, + 0x27C0..=0x27EF => 38, + 0x2980..=0x29FF => 38, + 0x2300..=0x23FF => 39, + 0x2400..=0x243F => 40, + 0x2440..=0x245F => 41, + 0x2460..=0x24FF => 42, + 0x2500..=0x257F => 43, + 0x2580..=0x259F => 44, + 0x25A0..=0x25FF => 45, + 0x2600..=0x26FF => 46, + 0x2700..=0x27BF => 47, + 0x3000..=0x303F => 48, + 0x3040..=0x309F => 49, + 0x30A0..=0x30FF => 50, + 0x31F0..=0x31FF => 50, + 0x3100..=0x312F => 51, + 0x31A0..=0x31BF => 51, + 0x3130..=0x318F => 52, + 0xA840..=0xA87F => 53, + 0x3200..=0x32FF => 54, + 0x3300..=0x33FF => 55, + 0xAC00..=0xD7AF => 56, + // Ignore Non-Plane 0 (57), since this is not a real range. + 0x10900..=0x1091F => 58, + 0x4E00..=0x9FFF => 59, + 0x2E80..=0x2FDF => 59, + 0x2FF0..=0x2FFF => 59, + 0x3400..=0x4DBF => 59, + 0x20000..=0x2A6DF => 59, + 0x3190..=0x319F => 59, + 0xE000..=0xF8FF => 60, + 0x31C0..=0x31EF => 61, + 0xF900..=0xFAFF => 61, + 0x2F800..=0x2FA1F => 61, + 0xFB00..=0xFB4F => 62, + 0xFB50..=0xFDFF => 63, + 0xFE20..=0xFE2F => 64, + 0xFE10..=0xFE1F => 65, + 0xFE30..=0xFE4F => 65, + 0xFE50..=0xFE6F => 66, + 0xFE70..=0xFEFF => 67, + 0xFF00..=0xFFEF => 68, + 0xFFF0..=0xFFFF => 69, + 0x0F00..=0x0FFF => 70, + 0x0700..=0x074F => 71, + 0x0780..=0x07BF => 72, + 0x0D80..=0x0DFF => 73, + 0x1000..=0x109F => 74, + 0x1200..=0x139F => 75, + 0x2D80..=0x2DDF => 75, + 0x13A0..=0x13FF => 76, + 0x1400..=0x167F => 77, + 0x1680..=0x169F => 78, + 0x16A0..=0x16FF => 79, + 0x1780..=0x17FF => 80, + 0x19E0..=0x19FF => 80, + 0x1800..=0x18AF => 81, + 0x2800..=0x28FF => 82, + 0xA000..=0xA48F => 83, + 0xA490..=0xA4CF => 83, + 0x1700..=0x177F => 84, + 0x10300..=0x1032F => 85, + 0x10330..=0x1034F => 86, + 0x10400..=0x1044F => 87, + 0x1D000..=0x1D24F => 88, + 0x1D400..=0x1D7FF => 89, + 0xF0000..=0xFFFFD => 90, + 0x100000..=0x10FFFD => 90, + 0xFE00..=0xFE0F => 91, + 0xE0100..=0xE01EF => 91, + 0xE0000..=0xE007F => 92, + 0x1900..=0x194F => 93, + 0x1950..=0x197F => 94, + 0x1980..=0x19DF => 95, + 0x1A00..=0x1A1F => 96, + 0x2C00..=0x2C5F => 97, + 0x2D30..=0x2D7F => 98, + 0x4DC0..=0x4DFF => 99, + 0xA800..=0xA82F => 100, + 0x10000..=0x1013F => 101, + 0x10140..=0x1018F => 102, + 0x10380..=0x1039F => 103, + 0x103A0..=0x103DF => 104, + 0x10450..=0x1047F => 105, + 0x10480..=0x104AF => 106, + 0x10800..=0x1083F => 107, + 0x10A00..=0x10A5F => 108, + 0x1D300..=0x1D35F => 109, + 0x12000..=0x123FF => 110, + 0x12400..=0x1247F => 110, + 0x1D360..=0x1D37F => 111, + 0x1B80..=0x1BBF => 112, + 0x1C00..=0x1C4F => 113, + 0x1C50..=0x1C7F => 114, + 0xA880..=0xA8DF => 115, + 0xA900..=0xA92F => 116, + 0xA930..=0xA95F => 117, + 0xAA00..=0xAA5F => 118, + 0x10190..=0x101CF => 119, + 0x101D0..=0x101FF => 120, + 0x102A0..=0x102DF => 121, + 0x10280..=0x1029F => 121, + 0x10920..=0x1093F => 121, + 0x1F030..=0x1F09F => 122, + 0x1F000..=0x1F02F => 122, + _ => -1, + } +} + /// A [OS/2 and Windows Metrics Table](https://docs.microsoft.com/en-us/typography/opentype/spec/os2). #[derive(Clone, Copy)] pub struct Table<'a> { @@ -226,6 +418,35 @@ impl<'a> Table<'a> { } } + /// Returns face permissions. + /// + /// Returns `None` in case of a malformed value. + #[inline] + pub fn permissions(&self) -> Option { + let n = Stream::read_at::(self.data, TYPE_OFFSET).unwrap_or(0); + match n & 0xF { + 0 => Some(Permissions::Installable), + 2 => Some(Permissions::Restricted), + 4 => Some(Permissions::PreviewAndPrint), + 8 => Some(Permissions::Editable), + _ => None, + } + } + + /// Checks if the face subsetting is allowed. + #[inline] + pub fn is_subsetting_allowed(&self) -> bool { + let n = Stream::read_at::(self.data, TYPE_OFFSET).unwrap_or(0); + n & 0x0100 == 0 + } + + /// Checks if the face bitmaps embedding is allowed. + #[inline] + pub fn is_bitmap_embedding_allowed(&self) -> bool { + let n = Stream::read_at::(self.data, TYPE_OFFSET).unwrap_or(0); + n & 0x0200 == 0 + } + /// Returns subscript metrics. #[inline] pub fn subscript_metrics(&self) -> ScriptMetrics { @@ -259,9 +480,20 @@ impl<'a> Table<'a> { } } + /// Returns Unicode ranges. + #[inline] + pub fn unicode_ranges(&self) -> UnicodeRanges { + let mut s = Stream::new_at(self.data, UNICODE_RANGES_OFFSET).unwrap(); + let n1 = s.read::().unwrap_or(0) as u128; + let n2 = s.read::().unwrap_or(0) as u128; + let n3 = s.read::().unwrap_or(0) as u128; + let n4 = s.read::().unwrap_or(0) as u128; + UnicodeRanges(n4 << 96 | n3 << 64 | n2 << 32 | n1) + } + #[inline] fn fs_selection(&self) -> u16 { - Stream::read_at::(self.data, FS_SELECTION_OFFSET).unwrap_or(0) + Stream::read_at::(self.data, SELECTION_OFFSET).unwrap_or(0) } /// Returns style.