Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
389
third-party/vendor/ttf-parser/tests/tables/aat.rs
vendored
Normal file
389
third-party/vendor/ttf-parser/tests/tables/aat.rs
vendored
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
use std::num::NonZeroU16;
|
||||
use ttf_parser::GlyphId;
|
||||
use ttf_parser::apple_layout::Lookup;
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
mod format0 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
let data = convert(&[
|
||||
UInt16(0), // format
|
||||
UInt16(10), // value
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(0)).unwrap(), 10);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_enough_glyphs() {
|
||||
let data = convert(&[
|
||||
UInt16(0), // format
|
||||
UInt16(10), // value
|
||||
]);
|
||||
|
||||
assert!(Lookup::parse(NonZeroU16::new(2).unwrap(), &data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn too_many_glyphs() {
|
||||
let data = convert(&[
|
||||
UInt16(0), // format
|
||||
UInt16(10), // value
|
||||
UInt16(11), // value <-- will be ignored
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(0)).unwrap(), 10);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
mod format2 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
let data = convert(&[
|
||||
UInt16(2), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(6), // segment size
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(118), // last glyph
|
||||
UInt16(118), // first glyph
|
||||
UInt16(10), // value
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(118)).unwrap(), 10);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn range() {
|
||||
let data = convert(&[
|
||||
UInt16(2), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(6), // segment size
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(7), // last glyph
|
||||
UInt16(5), // first glyph
|
||||
UInt16(18), // offset
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert!(table.value(GlyphId(4)).is_none());
|
||||
assert_eq!(table.value(GlyphId(5)).unwrap(), 18);
|
||||
assert_eq!(table.value(GlyphId(6)).unwrap(), 18);
|
||||
assert_eq!(table.value(GlyphId(7)).unwrap(), 18);
|
||||
assert!(table.value(GlyphId(8)).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
mod format4 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(6), // segment size
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(118), // last glyph
|
||||
UInt16(118), // first glyph
|
||||
UInt16(18), // offset
|
||||
|
||||
// Values [0]
|
||||
UInt16(10), // value [0]
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(118)).unwrap(), 10);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn range() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(6), // segment size
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(7), // last glyph
|
||||
UInt16(5), // first glyph
|
||||
UInt16(18), // offset
|
||||
|
||||
// Values [0]
|
||||
UInt16(10), // value [0]
|
||||
UInt16(11), // value [1]
|
||||
UInt16(12), // value [2]
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert!(table.value(GlyphId(4)).is_none());
|
||||
assert_eq!(table.value(GlyphId(5)).unwrap(), 10);
|
||||
assert_eq!(table.value(GlyphId(6)).unwrap(), 11);
|
||||
assert_eq!(table.value(GlyphId(7)).unwrap(), 12);
|
||||
assert!(table.value(GlyphId(8)).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
mod format6 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
let data = convert(&[
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(4), // segment size
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(0), // glyph
|
||||
UInt16(10), // value
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(0)).unwrap(), 10);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple() {
|
||||
let data = convert(&[
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(4), // segment size
|
||||
UInt16(3), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(0), // glyph
|
||||
UInt16(10), // value
|
||||
// Segment [1]
|
||||
UInt16(5), // glyph
|
||||
UInt16(20), // value
|
||||
// Segment [2]
|
||||
UInt16(10), // glyph
|
||||
UInt16(30), // value
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(0)).unwrap(), 10);
|
||||
assert_eq!(table.value(GlyphId(5)).unwrap(), 20);
|
||||
assert_eq!(table.value(GlyphId(10)).unwrap(), 30);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
}
|
||||
|
||||
// Tests below are indirectly testing BinarySearchTable.
|
||||
|
||||
#[test]
|
||||
fn no_segments() {
|
||||
let data = convert(&[
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(4), // segment size
|
||||
UInt16(0), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
]);
|
||||
|
||||
assert!(Lookup::parse(NonZeroU16::new(1).unwrap(), &data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignore_termination() {
|
||||
let data = convert(&[
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(4), // segment size
|
||||
UInt16(2), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(0), // glyph
|
||||
UInt16(10), // value
|
||||
// Segment [1]
|
||||
UInt16(0xFFFF), // glyph
|
||||
UInt16(0xFFFF), // value
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert!(table.value(GlyphId(0xFFFF)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_termination() {
|
||||
let data = convert(&[
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(4), // segment size
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(0xFFFF), // glyph
|
||||
UInt16(0xFFFF), // value
|
||||
]);
|
||||
|
||||
assert!(Lookup::parse(NonZeroU16::new(1).unwrap(), &data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_segment_size() {
|
||||
let data = convert(&[
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(8), // segment size <-- must be 4
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(0), // glyph
|
||||
UInt16(10), // value
|
||||
]);
|
||||
|
||||
assert!(Lookup::parse(NonZeroU16::new(1).unwrap(), &data).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
mod format8 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
let data = convert(&[
|
||||
UInt16(8), // format
|
||||
UInt16(0), // first glyph
|
||||
UInt16(1), // glyphs count
|
||||
UInt16(2), // value [0]
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(0)).unwrap(), 2);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_zero_first() {
|
||||
let data = convert(&[
|
||||
UInt16(8), // format
|
||||
UInt16(5), // first glyph
|
||||
UInt16(1), // glyphs count
|
||||
UInt16(2), // value [0]
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(5)).unwrap(), 2);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
assert!(table.value(GlyphId(6)).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
mod format10 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
let data = convert(&[
|
||||
UInt16(10), // format
|
||||
UInt16(1), // value size: u8
|
||||
UInt16(0), // first glyph
|
||||
UInt16(1), // glyphs count
|
||||
UInt8(2), // value [0]
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(0)).unwrap(), 2);
|
||||
assert!(table.value(GlyphId(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_value_size() {
|
||||
let data = convert(&[
|
||||
UInt16(10), // format
|
||||
UInt16(50), // value size <-- invalid
|
||||
UInt16(0), // first glyph
|
||||
UInt16(1), // glyphs count
|
||||
UInt8(2), // value [0]
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert!(table.value(GlyphId(0)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_value_size() {
|
||||
let data = convert(&[
|
||||
UInt16(10), // format
|
||||
UInt16(8), // value size <-- we do not support u64
|
||||
UInt16(0), // first glyph
|
||||
UInt16(1), // glyphs count
|
||||
Raw(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02]), // value [0]
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert!(table.value(GlyphId(0)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn u32_value_size() {
|
||||
let data = convert(&[
|
||||
UInt16(10), // format
|
||||
UInt16(4), // value size
|
||||
UInt16(0), // first glyph
|
||||
UInt16(1), // glyphs count
|
||||
UInt32(0xFFFF + 10), // value [0] <-- will be truncated
|
||||
]);
|
||||
|
||||
let table = Lookup::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.value(GlyphId(0)).unwrap(), 9);
|
||||
}
|
||||
}
|
||||
134
third-party/vendor/ttf-parser/tests/tables/ankr.rs
vendored
Normal file
134
third-party/vendor/ttf-parser/tests/tables/ankr.rs
vendored
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
use std::num::NonZeroU16;
|
||||
use ttf_parser::GlyphId;
|
||||
use ttf_parser::ankr::{Table, Point};
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let data = convert(&[
|
||||
UInt16(0), // version
|
||||
UInt16(0), // reserved
|
||||
UInt32(0), // offset to lookup table
|
||||
UInt32(0), // offset to glyphs data
|
||||
]);
|
||||
|
||||
let _ = Table::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
let data = convert(&[
|
||||
UInt16(0), // version
|
||||
UInt16(0), // reserved
|
||||
UInt32(12), // offset to lookup table
|
||||
UInt32(12 + 16), // offset to glyphs data
|
||||
|
||||
// Lookup Table
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(4), // segment size
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(0), // glyph
|
||||
UInt16(0), // offset
|
||||
|
||||
// Glyphs Data
|
||||
UInt32(1), // number of points
|
||||
// Point [0]
|
||||
Int16(-5), // x
|
||||
Int16(11), // y
|
||||
]);
|
||||
|
||||
let table = Table::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
let points = table.points(GlyphId(0)).unwrap();
|
||||
assert_eq!(points.get(0).unwrap(), Point { x: -5, y: 11 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_points() {
|
||||
let data = convert(&[
|
||||
UInt16(0), // version
|
||||
UInt16(0), // reserved
|
||||
UInt32(12), // offset to lookup table
|
||||
UInt32(12 + 16), // offset to glyphs data
|
||||
|
||||
// Lookup Table
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(4), // segment size
|
||||
UInt16(1), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(0), // glyph
|
||||
UInt16(0), // offset
|
||||
|
||||
// Glyphs Data
|
||||
// Glyph Data [0]
|
||||
UInt32(2), // number of points
|
||||
// Point [0]
|
||||
Int16(-5), // x
|
||||
Int16(11), // y
|
||||
// Point [1]
|
||||
Int16(10), // x
|
||||
Int16(-40), // y
|
||||
]);
|
||||
|
||||
let table = Table::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
let points = table.points(GlyphId(0)).unwrap();
|
||||
assert_eq!(points.get(0).unwrap(), Point { x: -5, y: 11 });
|
||||
assert_eq!(points.get(1).unwrap(), Point { x: 10, y: -40 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_glyphs() {
|
||||
let data = convert(&[
|
||||
UInt16(0), // version
|
||||
UInt16(0), // reserved
|
||||
UInt32(12), // offset to lookup table
|
||||
UInt32(12 + 20), // offset to glyphs data
|
||||
|
||||
// Lookup Table
|
||||
UInt16(6), // format
|
||||
|
||||
// Binary Search Table
|
||||
UInt16(4), // segment size
|
||||
UInt16(2), // number of segments
|
||||
UInt16(0), // search range: we don't use it
|
||||
UInt16(0), // entry selector: we don't use it
|
||||
UInt16(0), // range shift: we don't use it
|
||||
|
||||
// Segment [0]
|
||||
UInt16(0), // glyph
|
||||
UInt16(0), // offset
|
||||
// Segment [1]
|
||||
UInt16(1), // glyph
|
||||
UInt16(8), // offset
|
||||
|
||||
// Glyphs Data
|
||||
// Glyph Data [0]
|
||||
UInt32(1), // number of points
|
||||
// Point [0]
|
||||
Int16(-5), // x
|
||||
Int16(11), // y
|
||||
// Glyph Data [1]
|
||||
UInt32(1), // number of points
|
||||
// Point [0]
|
||||
Int16(40), // x
|
||||
Int16(10), // y
|
||||
]);
|
||||
|
||||
let table = Table::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
let points = table.points(GlyphId(0)).unwrap();
|
||||
assert_eq!(points.get(0).unwrap(), Point { x: -5, y: 11 });
|
||||
let points = table.points(GlyphId(1)).unwrap();
|
||||
assert_eq!(points.get(0).unwrap(), Point { x: 40, y: 10 });
|
||||
}
|
||||
998
third-party/vendor/ttf-parser/tests/tables/cff1.rs
vendored
Normal file
998
third-party/vendor/ttf-parser/tests/tables/cff1.rs
vendored
Normal file
|
|
@ -0,0 +1,998 @@
|
|||
// TODO: simplify/rewrite
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use ttf_parser::{cff, GlyphId, CFFError, Rect};
|
||||
|
||||
struct Builder(String);
|
||||
impl ttf_parser::OutlineBuilder for Builder {
|
||||
fn move_to(&mut self, x: f32, y: f32) {
|
||||
write!(&mut self.0, "M {} {} ", x, y).unwrap();
|
||||
}
|
||||
|
||||
fn line_to(&mut self, x: f32, y: f32) {
|
||||
write!(&mut self.0, "L {} {} ", x, y).unwrap();
|
||||
}
|
||||
|
||||
fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
|
||||
write!(&mut self.0, "Q {} {} {} {} ", x1, y1, x, y).unwrap();
|
||||
}
|
||||
|
||||
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
|
||||
write!(&mut self.0, "C {} {} {} {} {} {} ", x1, y1, x2, y2, x, y).unwrap();
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
write!(&mut self.0, "Z ").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod operator {
|
||||
pub const HORIZONTAL_STEM: u8 = 1;
|
||||
pub const VERTICAL_STEM: u8 = 3;
|
||||
pub const VERTICAL_MOVE_TO: u8 = 4;
|
||||
pub const LINE_TO: u8 = 5;
|
||||
pub const HORIZONTAL_LINE_TO: u8 = 6;
|
||||
pub const VERTICAL_LINE_TO: u8 = 7;
|
||||
pub const CURVE_TO: u8 = 8;
|
||||
pub const CALL_LOCAL_SUBROUTINE: u8 = 10;
|
||||
pub const RETURN: u8 = 11;
|
||||
pub const ENDCHAR: u8 = 14;
|
||||
pub const HORIZONTAL_STEM_HINT_MASK: u8 = 18;
|
||||
pub const HINT_MASK: u8 = 19;
|
||||
pub const COUNTER_MASK: u8 = 20;
|
||||
pub const MOVE_TO: u8 = 21;
|
||||
pub const HORIZONTAL_MOVE_TO: u8 = 22;
|
||||
pub const VERTICAL_STEM_HINT_MASK: u8 = 23;
|
||||
pub const CURVE_LINE: u8 = 24;
|
||||
pub const LINE_CURVE: u8 = 25;
|
||||
pub const VV_CURVE_TO: u8 = 26;
|
||||
pub const HH_CURVE_TO: u8 = 27;
|
||||
pub const SHORT_INT: u8 = 28;
|
||||
pub const CALL_GLOBAL_SUBROUTINE: u8 = 29;
|
||||
pub const VH_CURVE_TO: u8 = 30;
|
||||
pub const HV_CURVE_TO: u8 = 31;
|
||||
pub const HFLEX: u8 = 34;
|
||||
pub const FLEX: u8 = 35;
|
||||
pub const HFLEX1: u8 = 36;
|
||||
pub const FLEX1: u8 = 37;
|
||||
pub const FIXED_16_16: u8 = 255;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod top_dict_operator {
|
||||
pub const CHARSET_OFFSET: u16 = 15;
|
||||
pub const CHAR_STRINGS_OFFSET: u16 = 17;
|
||||
pub const PRIVATE_DICT_SIZE_AND_OFFSET: u16 = 18;
|
||||
pub const ROS: u16 = 1230;
|
||||
pub const FD_ARRAY: u16 = 1236;
|
||||
pub const FD_SELECT: u16 = 1237;
|
||||
}
|
||||
|
||||
mod private_dict_operator {
|
||||
pub const LOCAL_SUBROUTINES_OFFSET: u16 = 19;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
enum TtfType {
|
||||
Raw(&'static [u8]),
|
||||
TrueTypeMagic,
|
||||
OpenTypeMagic,
|
||||
FontCollectionMagic,
|
||||
Int8(i8),
|
||||
UInt8(u8),
|
||||
Int16(i16),
|
||||
UInt16(u16),
|
||||
Int32(i32),
|
||||
UInt32(u32),
|
||||
CFFInt(i32),
|
||||
}
|
||||
|
||||
use TtfType::*;
|
||||
|
||||
fn convert(values: &[TtfType]) -> Vec<u8> {
|
||||
let mut data = Vec::with_capacity(256);
|
||||
for v in values {
|
||||
convert_type(*v, &mut data);
|
||||
}
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
fn convert_type(value: TtfType, data: &mut Vec<u8>) {
|
||||
match value {
|
||||
TtfType::Raw(bytes) => {
|
||||
data.extend_from_slice(bytes);
|
||||
}
|
||||
TtfType::TrueTypeMagic => {
|
||||
data.extend_from_slice(&[0x00, 0x01, 0x00, 0x00]);
|
||||
}
|
||||
TtfType::OpenTypeMagic => {
|
||||
data.extend_from_slice(&[0x4F, 0x54, 0x54, 0x4F]);
|
||||
}
|
||||
TtfType::FontCollectionMagic => {
|
||||
data.extend_from_slice(&[0x74, 0x74, 0x63, 0x66]);
|
||||
}
|
||||
TtfType::Int8(n) => {
|
||||
data.extend_from_slice(&i8::to_be_bytes(n));
|
||||
}
|
||||
TtfType::UInt8(n) => {
|
||||
data.extend_from_slice(&u8::to_be_bytes(n));
|
||||
}
|
||||
TtfType::Int16(n) => {
|
||||
data.extend_from_slice(&i16::to_be_bytes(n));
|
||||
}
|
||||
TtfType::UInt16(n) => {
|
||||
data.extend_from_slice(&u16::to_be_bytes(n));
|
||||
}
|
||||
TtfType::Int32(n) => {
|
||||
data.extend_from_slice(&i32::to_be_bytes(n));
|
||||
}
|
||||
TtfType::UInt32(n) => {
|
||||
data.extend_from_slice(&u32::to_be_bytes(n));
|
||||
}
|
||||
TtfType::CFFInt(n) => {
|
||||
match n {
|
||||
-107..=107 => {
|
||||
data.push((n as i16 + 139) as u8);
|
||||
}
|
||||
108..=1131 => {
|
||||
let n = n - 108;
|
||||
data.push(((n >> 8) + 247) as u8);
|
||||
data.push((n & 0xFF) as u8);
|
||||
}
|
||||
-1131..=-108 => {
|
||||
let n = -n - 108;
|
||||
data.push(((n >> 8) + 251) as u8);
|
||||
data.push((n & 0xFF) as u8);
|
||||
}
|
||||
-32768..=32767 => {
|
||||
data.push(28);
|
||||
data.extend_from_slice(&i16::to_be_bytes(n as i16));
|
||||
}
|
||||
_ => {
|
||||
data.push(29);
|
||||
data.extend_from_slice(&i32::to_be_bytes(n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Writer {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
fn new() -> Self {
|
||||
Writer { data: Vec::with_capacity(256) }
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
fn write(&mut self, value: TtfType) {
|
||||
convert_type(value, &mut self.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn gen_cff(
|
||||
global_subrs: &[&[TtfType]],
|
||||
local_subrs: &[&[TtfType]],
|
||||
chars: &[TtfType],
|
||||
) -> Vec<u8> {
|
||||
fn gen_global_subrs(subrs: &[&[TtfType]]) -> Vec<u8> {
|
||||
let mut w = Writer::new();
|
||||
for v1 in subrs {
|
||||
for v2 in v1.iter() {
|
||||
w.write(*v2);
|
||||
}
|
||||
}
|
||||
w.data
|
||||
}
|
||||
|
||||
fn gen_local_subrs(subrs: &[&[TtfType]]) -> Vec<u8> {
|
||||
let mut w = Writer::new();
|
||||
for v1 in subrs {
|
||||
for v2 in v1.iter() {
|
||||
w.write(*v2);
|
||||
}
|
||||
}
|
||||
w.data
|
||||
}
|
||||
|
||||
const EMPTY_INDEX_SIZE: usize = 2;
|
||||
const INDEX_HEADER_SIZE: usize = 5;
|
||||
|
||||
// TODO: support multiple subrs
|
||||
assert!(global_subrs.len() <= 1);
|
||||
assert!(local_subrs.len() <= 1);
|
||||
|
||||
let global_subrs_data = gen_global_subrs(global_subrs);
|
||||
let local_subrs_data = gen_local_subrs(local_subrs);
|
||||
let chars_data = convert(chars);
|
||||
|
||||
assert!(global_subrs_data.len() < 255);
|
||||
assert!(local_subrs_data.len() < 255);
|
||||
assert!(chars_data.len() < 255);
|
||||
|
||||
let mut w = Writer::new();
|
||||
// Header
|
||||
w.write(UInt8(1)); // major version
|
||||
w.write(UInt8(0)); // minor version
|
||||
w.write(UInt8(4)); // header size
|
||||
w.write(UInt8(0)); // absolute offset
|
||||
|
||||
// Name INDEX
|
||||
w.write(UInt16(0)); // count
|
||||
|
||||
// Top DICT
|
||||
// INDEX
|
||||
w.write(UInt16(1)); // count
|
||||
w.write(UInt8(1)); // offset size
|
||||
w.write(UInt8(1)); // index[0]
|
||||
|
||||
let top_dict_idx2 = if local_subrs.is_empty() { 3 } else { 6 };
|
||||
w.write(UInt8(top_dict_idx2)); // index[1]
|
||||
// Item 0
|
||||
let mut charstr_offset = w.offset() + 2;
|
||||
charstr_offset += EMPTY_INDEX_SIZE; // String INDEX
|
||||
|
||||
// Global Subroutines INDEX
|
||||
if !global_subrs_data.is_empty() {
|
||||
charstr_offset += INDEX_HEADER_SIZE + global_subrs_data.len();
|
||||
} else {
|
||||
charstr_offset += EMPTY_INDEX_SIZE;
|
||||
}
|
||||
|
||||
if !local_subrs_data.is_empty() {
|
||||
charstr_offset += 3;
|
||||
}
|
||||
|
||||
w.write(CFFInt(charstr_offset as i32));
|
||||
w.write(UInt8(top_dict_operator::CHAR_STRINGS_OFFSET as u8));
|
||||
|
||||
if !local_subrs_data.is_empty() {
|
||||
// Item 1
|
||||
w.write(CFFInt(2)); // length
|
||||
w.write(CFFInt((charstr_offset + INDEX_HEADER_SIZE + chars_data.len()) as i32)); // offset
|
||||
w.write(UInt8(top_dict_operator::PRIVATE_DICT_SIZE_AND_OFFSET as u8));
|
||||
}
|
||||
|
||||
// String INDEX
|
||||
w.write(UInt16(0)); // count
|
||||
|
||||
// Global Subroutines INDEX
|
||||
if global_subrs_data.is_empty() {
|
||||
w.write(UInt16(0)); // count
|
||||
} else {
|
||||
w.write(UInt16(1)); // count
|
||||
w.write(UInt8(1)); // offset size
|
||||
w.write(UInt8(1)); // index[0]
|
||||
w.write(UInt8(global_subrs_data.len() as u8 + 1)); // index[1]
|
||||
w.data.extend_from_slice(&global_subrs_data);
|
||||
}
|
||||
|
||||
// CharString INDEX
|
||||
w.write(UInt16(1)); // count
|
||||
w.write(UInt8(1)); // offset size
|
||||
w.write(UInt8(1)); // index[0]
|
||||
w.write(UInt8(chars_data.len() as u8 + 1)); // index[1]
|
||||
w.data.extend_from_slice(&chars_data);
|
||||
|
||||
if !local_subrs_data.is_empty() {
|
||||
// The local subroutines offset is relative to the beginning of the Private DICT data.
|
||||
|
||||
// Private DICT
|
||||
w.write(CFFInt(2));
|
||||
w.write(UInt8(private_dict_operator::LOCAL_SUBROUTINES_OFFSET as u8));
|
||||
|
||||
// Local Subroutines INDEX
|
||||
w.write(UInt16(1)); // count
|
||||
w.write(UInt8(1)); // offset size
|
||||
w.write(UInt8(1)); // index[0]
|
||||
w.write(UInt8(local_subrs_data.len() as u8 + 1)); // index[1]
|
||||
w.data.extend_from_slice(&local_subrs_data);
|
||||
}
|
||||
|
||||
w.data
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_version() {
|
||||
let data = convert(&[
|
||||
UInt8(10), // major version, only 1 is supported
|
||||
UInt8(0), // minor version
|
||||
UInt8(4), // header size
|
||||
UInt8(0), // absolute offset
|
||||
]);
|
||||
|
||||
assert!(cff::Table::parse(&data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_default_header_size() {
|
||||
let data = convert(&[
|
||||
// Header
|
||||
UInt8(1), // major version
|
||||
UInt8(0), // minor version
|
||||
UInt8(8), // header size
|
||||
UInt8(0), // absolute offset
|
||||
|
||||
// no-op, should be skipped
|
||||
UInt8(0),
|
||||
UInt8(0),
|
||||
UInt8(0),
|
||||
UInt8(0),
|
||||
|
||||
// Name INDEX
|
||||
UInt16(0), // count
|
||||
|
||||
// Top DICT
|
||||
// INDEX
|
||||
UInt16(1), // count
|
||||
UInt8(1), // offset size
|
||||
UInt8(1), // index[0]
|
||||
UInt8(3), // index[1]
|
||||
// Data
|
||||
CFFInt(21),
|
||||
UInt8(top_dict_operator::CHAR_STRINGS_OFFSET as u8),
|
||||
|
||||
// String INDEX
|
||||
UInt16(0), // count
|
||||
|
||||
// Global Subroutines INDEX
|
||||
UInt16(0), // count
|
||||
|
||||
// CharString INDEX
|
||||
UInt16(1), // count
|
||||
UInt8(1), // offset size
|
||||
UInt8(1), // index[0]
|
||||
UInt8(4), // index[1]
|
||||
// Data
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
]);
|
||||
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let rect = table.outline(GlyphId(0), &mut builder).unwrap();
|
||||
|
||||
assert_eq!(builder.0, "M 10 0 Z ");
|
||||
assert_eq!(rect, Rect { x_min: 10, y_min: 0, x_max: 10, y_max: 0 });
|
||||
}
|
||||
|
||||
fn rect(x_min: i16, y_min: i16, x_max: i16, y_max: i16) -> Rect {
|
||||
Rect { x_min, y_min, x_max, y_max }
|
||||
}
|
||||
|
||||
macro_rules! test_cs_with_subrs {
|
||||
($name:ident, $glob:expr, $loc:expr, $values:expr, $path:expr, $rect_res:expr) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
let data = gen_cff($glob, $loc, $values);
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let rect = table.outline(GlyphId(0), &mut builder).unwrap();
|
||||
|
||||
assert_eq!(builder.0, $path);
|
||||
assert_eq!(rect, $rect_res);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_cs {
|
||||
($name:ident, $values:expr, $path:expr, $rect_res:expr) => {
|
||||
test_cs_with_subrs!($name, &[], &[], $values, $path, $rect_res);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_cs_err {
|
||||
($name:ident, $values:expr, $err:expr) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
let data = gen_cff(&[], &[], $values);
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let res = table.outline(GlyphId(0), &mut builder);
|
||||
assert_eq!(res.unwrap_err(), $err);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_cs!(move_to, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 Z ",
|
||||
rect(10, 20, 10, 20)
|
||||
);
|
||||
|
||||
test_cs!(move_to_with_width, &[
|
||||
CFFInt(5), CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 Z ",
|
||||
rect(10, 20, 10, 20)
|
||||
);
|
||||
|
||||
test_cs!(hmove_to, &[
|
||||
CFFInt(10), UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 0 Z ",
|
||||
rect(10, 0, 10, 0)
|
||||
);
|
||||
|
||||
test_cs!(hmove_to_with_width, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 20 0 Z ",
|
||||
rect(20, 0, 20, 0)
|
||||
);
|
||||
|
||||
test_cs!(vmove_to, &[
|
||||
CFFInt(10), UInt8(operator::VERTICAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 0 10 Z ",
|
||||
rect(0, 10, 0, 10)
|
||||
);
|
||||
|
||||
test_cs!(vmove_to_with_width, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::VERTICAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 0 20 Z ",
|
||||
rect(0, 20, 0, 20)
|
||||
);
|
||||
|
||||
test_cs!(line_to, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 L 40 60 Z ",
|
||||
rect(10, 20, 40, 60)
|
||||
);
|
||||
|
||||
test_cs!(line_to_with_multiple_pairs, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 L 40 60 L 90 120 Z ",
|
||||
rect(10, 20, 90, 120)
|
||||
);
|
||||
|
||||
test_cs!(hline_to, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), UInt8(operator::HORIZONTAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 L 40 20 Z ",
|
||||
rect(10, 20, 40, 20)
|
||||
);
|
||||
|
||||
test_cs!(hline_to_with_two_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), UInt8(operator::HORIZONTAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 L 40 20 L 40 60 Z ",
|
||||
rect(10, 20, 40, 60)
|
||||
);
|
||||
|
||||
test_cs!(hline_to_with_three_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), UInt8(operator::HORIZONTAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 L 40 20 L 40 60 L 90 60 Z ",
|
||||
rect(10, 20, 90, 60)
|
||||
);
|
||||
|
||||
test_cs!(vline_to, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), UInt8(operator::VERTICAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 L 10 50 Z ",
|
||||
rect(10, 20, 10, 50)
|
||||
);
|
||||
|
||||
test_cs!(vline_to_with_two_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), UInt8(operator::VERTICAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 L 10 50 L 50 50 Z ",
|
||||
rect(10, 20, 50, 50)
|
||||
);
|
||||
|
||||
test_cs!(vline_to_with_three_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), UInt8(operator::VERTICAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 L 10 50 L 50 50 L 50 100 Z ",
|
||||
rect(10, 20, 50, 100)
|
||||
);
|
||||
|
||||
test_cs!(curve_to, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), CFFInt(70), CFFInt(80),
|
||||
UInt8(operator::CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 C 40 60 90 120 160 200 Z ",
|
||||
rect(10, 20, 160, 200)
|
||||
);
|
||||
|
||||
test_cs!(curve_to_with_two_sets_of_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), CFFInt(70), CFFInt(80),
|
||||
CFFInt(90), CFFInt(100), CFFInt(110), CFFInt(120), CFFInt(130), CFFInt(140),
|
||||
UInt8(operator::CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 C 40 60 90 120 160 200 C 250 300 360 420 490 560 Z ",
|
||||
rect(10, 20, 490, 560)
|
||||
);
|
||||
|
||||
test_cs!(hh_curve_to, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), UInt8(operator::HH_CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 C 40 20 80 70 140 70 Z ",
|
||||
rect(10, 20, 140, 70)
|
||||
);
|
||||
|
||||
test_cs!(hh_curve_to_with_y, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), CFFInt(70), UInt8(operator::HH_CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 C 50 50 100 110 170 110 Z ",
|
||||
rect(10, 20, 170, 110)
|
||||
);
|
||||
|
||||
test_cs!(vv_curve_to, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), UInt8(operator::VV_CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 C 10 50 50 100 50 160 Z ",
|
||||
rect(10, 20, 50, 160)
|
||||
);
|
||||
|
||||
test_cs!(vv_curve_to_with_x, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), CFFInt(70), UInt8(operator::VV_CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], "M 10 20 C 40 60 90 120 90 190 Z ",
|
||||
rect(10, 20, 90, 190)
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn only_endchar() {
|
||||
let data = gen_cff(&[], &[], &[UInt8(operator::ENDCHAR)]);
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
assert!(table.outline(GlyphId(0), &mut builder).is_err());
|
||||
}
|
||||
|
||||
test_cs_with_subrs!(local_subr,
|
||||
&[],
|
||||
&[&[
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
UInt8(operator::RETURN),
|
||||
]],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_LOCAL_SUBROUTINE),
|
||||
UInt8(operator::ENDCHAR),
|
||||
],
|
||||
"M 10 0 L 40 40 Z ",
|
||||
rect(10, 0, 40, 40)
|
||||
);
|
||||
|
||||
test_cs_with_subrs!(endchar_in_subr,
|
||||
&[],
|
||||
&[&[
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
]],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_LOCAL_SUBROUTINE),
|
||||
],
|
||||
"M 10 0 L 40 40 Z ",
|
||||
rect(10, 0, 40, 40)
|
||||
);
|
||||
|
||||
test_cs_with_subrs!(global_subr,
|
||||
&[&[
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
UInt8(operator::RETURN),
|
||||
]],
|
||||
&[],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_GLOBAL_SUBROUTINE),
|
||||
UInt8(operator::ENDCHAR),
|
||||
],
|
||||
"M 10 0 L 40 40 Z ",
|
||||
rect(10, 0, 40, 40)
|
||||
);
|
||||
|
||||
test_cs_err!(reserved_operator, &[
|
||||
CFFInt(10), UInt8(2),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidOperator);
|
||||
|
||||
test_cs_err!(line_to_without_move_to, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::MissingMoveTo);
|
||||
|
||||
// Width must be set only once.
|
||||
test_cs_err!(two_vmove_to_with_width, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::VERTICAL_MOVE_TO),
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::VERTICAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(move_to_with_too_many_coords, &[
|
||||
CFFInt(10), CFFInt(10), CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(move_to_with_not_enought_coords, &[
|
||||
CFFInt(10), UInt8(operator::MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(hmove_to_with_too_many_coords, &[
|
||||
CFFInt(10), CFFInt(10), CFFInt(10), UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(hmove_to_with_not_enought_coords, &[
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(vmove_to_with_too_many_coords, &[
|
||||
CFFInt(10), CFFInt(10), CFFInt(10), UInt8(operator::VERTICAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(vmove_to_with_not_enought_coords, &[
|
||||
UInt8(operator::VERTICAL_MOVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(line_to_with_single_coord, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(line_to_with_odd_number_of_coord, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(hline_to_without_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
UInt8(operator::HORIZONTAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(vline_to_without_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
UInt8(operator::VERTICAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(curve_to_with_invalid_num_of_coords_1, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), UInt8(operator::CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(curve_to_with_invalid_num_of_coords_2, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(60), CFFInt(70), CFFInt(80), CFFInt(90),
|
||||
UInt8(operator::CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(hh_curve_to_with_not_enought_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), UInt8(operator::HH_CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(hh_curve_to_with_too_many_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(30), CFFInt(40), CFFInt(50),
|
||||
UInt8(operator::HH_CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(vv_curve_to_with_not_enought_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), UInt8(operator::VV_CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(vv_curve_to_with_too_many_coords, &[
|
||||
CFFInt(10), CFFInt(20), UInt8(operator::MOVE_TO),
|
||||
CFFInt(30), CFFInt(40), CFFInt(50), CFFInt(30), CFFInt(40), CFFInt(50),
|
||||
UInt8(operator::VV_CURVE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::InvalidArgumentsStackLength);
|
||||
|
||||
test_cs_err!(multiple_endchar, &[
|
||||
UInt8(operator::ENDCHAR),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::DataAfterEndChar);
|
||||
|
||||
test_cs_err!(seac_with_not_enough_data, &[
|
||||
CFFInt(0),
|
||||
CFFInt(0),
|
||||
CFFInt(0),
|
||||
CFFInt(0),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::NestingLimitReached);
|
||||
|
||||
test_cs_err!(operands_overflow, &[
|
||||
CFFInt(0), CFFInt(1), CFFInt(2), CFFInt(3), CFFInt(4), CFFInt(5), CFFInt(6), CFFInt(7), CFFInt(8), CFFInt(9),
|
||||
CFFInt(0), CFFInt(1), CFFInt(2), CFFInt(3), CFFInt(4), CFFInt(5), CFFInt(6), CFFInt(7), CFFInt(8), CFFInt(9),
|
||||
CFFInt(0), CFFInt(1), CFFInt(2), CFFInt(3), CFFInt(4), CFFInt(5), CFFInt(6), CFFInt(7), CFFInt(8), CFFInt(9),
|
||||
CFFInt(0), CFFInt(1), CFFInt(2), CFFInt(3), CFFInt(4), CFFInt(5), CFFInt(6), CFFInt(7), CFFInt(8), CFFInt(9),
|
||||
CFFInt(0), CFFInt(1), CFFInt(2), CFFInt(3), CFFInt(4), CFFInt(5), CFFInt(6), CFFInt(7), CFFInt(8), CFFInt(9),
|
||||
], CFFError::ArgumentsStackLimitReached);
|
||||
|
||||
test_cs_err!(operands_overflow_with_4_byte_ints, &[
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000), CFFInt(30000),
|
||||
], CFFError::ArgumentsStackLimitReached);
|
||||
|
||||
test_cs_err!(bbox_overflow, &[
|
||||
CFFInt(32767), UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(32767), UInt8(operator::HORIZONTAL_LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
], CFFError::BboxOverflow);
|
||||
|
||||
#[test]
|
||||
fn endchar_in_subr_with_extra_data_1() {
|
||||
let data = gen_cff(
|
||||
&[],
|
||||
&[&[
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
]],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_LOCAL_SUBROUTINE),
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
]
|
||||
);
|
||||
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let res = table.outline(GlyphId(0), &mut builder);
|
||||
assert_eq!(res.unwrap_err(), CFFError::DataAfterEndChar);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn endchar_in_subr_with_extra_data_2() {
|
||||
let data = gen_cff(
|
||||
&[],
|
||||
&[&[
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
]],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_LOCAL_SUBROUTINE),
|
||||
]
|
||||
);
|
||||
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let res = table.outline(GlyphId(0), &mut builder);
|
||||
assert_eq!(res.unwrap_err(), CFFError::DataAfterEndChar);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subr_without_return() {
|
||||
let data = gen_cff(
|
||||
&[],
|
||||
&[&[
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
UInt8(operator::ENDCHAR),
|
||||
CFFInt(30),
|
||||
CFFInt(40),
|
||||
UInt8(operator::LINE_TO),
|
||||
]],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_LOCAL_SUBROUTINE),
|
||||
]
|
||||
);
|
||||
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let res = table.outline(GlyphId(0), &mut builder);
|
||||
assert_eq!(res.unwrap_err(), CFFError::DataAfterEndChar);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursive_local_subr() {
|
||||
let data = gen_cff(
|
||||
&[],
|
||||
&[&[
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_LOCAL_SUBROUTINE),
|
||||
]],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_LOCAL_SUBROUTINE),
|
||||
]
|
||||
);
|
||||
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let res = table.outline(GlyphId(0), &mut builder);
|
||||
assert_eq!(res.unwrap_err(), CFFError::NestingLimitReached);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursive_global_subr() {
|
||||
let data = gen_cff(
|
||||
&[&[
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_GLOBAL_SUBROUTINE),
|
||||
]],
|
||||
&[],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_GLOBAL_SUBROUTINE),
|
||||
]
|
||||
);
|
||||
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let res = table.outline(GlyphId(0), &mut builder);
|
||||
assert_eq!(res.unwrap_err(), CFFError::NestingLimitReached);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursive_mixed_subr() {
|
||||
let data = gen_cff(
|
||||
&[&[
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_LOCAL_SUBROUTINE),
|
||||
]],
|
||||
&[&[
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_GLOBAL_SUBROUTINE),
|
||||
]],
|
||||
&[
|
||||
CFFInt(10),
|
||||
UInt8(operator::HORIZONTAL_MOVE_TO),
|
||||
CFFInt(0 - 107), // subr index - subr bias
|
||||
UInt8(operator::CALL_GLOBAL_SUBROUTINE),
|
||||
]
|
||||
);
|
||||
|
||||
let table = cff::Table::parse(&data).unwrap();
|
||||
let mut builder = Builder(String::new());
|
||||
let res = table.outline(GlyphId(0), &mut builder);
|
||||
assert_eq!(res.unwrap_err(), CFFError::NestingLimitReached);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_char_string_offset() {
|
||||
let data = convert(&[
|
||||
// Header
|
||||
UInt8(1), // major version
|
||||
UInt8(0), // minor version
|
||||
UInt8(4), // header size
|
||||
UInt8(0), // absolute offset
|
||||
|
||||
// Name INDEX
|
||||
UInt16(0), // count
|
||||
|
||||
// Top DICT
|
||||
// INDEX
|
||||
UInt16(1), // count
|
||||
UInt8(1), // offset size
|
||||
UInt8(1), // index[0]
|
||||
UInt8(3), // index[1]
|
||||
// Data
|
||||
CFFInt(0), // zero offset!
|
||||
UInt8(top_dict_operator::CHAR_STRINGS_OFFSET as u8),
|
||||
]);
|
||||
|
||||
assert!(cff::Table::parse(&data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_char_string_offset() {
|
||||
let data = convert(&[
|
||||
// Header
|
||||
UInt8(1), // major version
|
||||
UInt8(0), // minor version
|
||||
UInt8(4), // header size
|
||||
UInt8(0), // absolute offset
|
||||
|
||||
// Name INDEX
|
||||
UInt16(0), // count
|
||||
|
||||
// Top DICT
|
||||
// INDEX
|
||||
UInt16(1), // count
|
||||
UInt8(1), // offset size
|
||||
UInt8(1), // index[0]
|
||||
UInt8(3), // index[1]
|
||||
// Data
|
||||
CFFInt(2), // invalid offset!
|
||||
UInt8(top_dict_operator::CHAR_STRINGS_OFFSET as u8),
|
||||
]);
|
||||
|
||||
assert!(cff::Table::parse(&data).is_none());
|
||||
}
|
||||
|
||||
// TODO: return from main
|
||||
// TODO: return without endchar
|
||||
// TODO: data after return
|
||||
// TODO: recursive subr
|
||||
// TODO: HORIZONTAL_STEM
|
||||
// TODO: VERTICAL_STEM
|
||||
// TODO: HORIZONTAL_STEM_HINT_MASK
|
||||
// TODO: HINT_MASK
|
||||
// TODO: COUNTER_MASK
|
||||
// TODO: VERTICAL_STEM_HINT_MASK
|
||||
// TODO: CURVE_LINE
|
||||
// TODO: LINE_CURVE
|
||||
// TODO: VH_CURVE_TO
|
||||
// TODO: HFLEX
|
||||
// TODO: FLEX
|
||||
// TODO: HFLEX1
|
||||
// TODO: FLEX1
|
||||
555
third-party/vendor/ttf-parser/tests/tables/cmap.rs
vendored
Normal file
555
third-party/vendor/ttf-parser/tests/tables/cmap.rs
vendored
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
mod format0 {
|
||||
use ttf_parser::{cmap, GlyphId};
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
#[test]
|
||||
fn maps_not_all_256_codepoints() {
|
||||
let mut data = convert(&[
|
||||
UInt16(0), // format
|
||||
UInt16(262), // subtable size
|
||||
UInt16(0), // language ID
|
||||
]);
|
||||
|
||||
// Map (only) codepoint 0x40 to 100.
|
||||
data.extend(std::iter::repeat(0).take(256));
|
||||
data[6 + 0x40] = 100;
|
||||
|
||||
let subtable = cmap::Subtable0::parse(&data).unwrap();
|
||||
|
||||
assert_eq!(subtable.glyph_index(0), None);
|
||||
assert_eq!(subtable.glyph_index(0x40), Some(GlyphId(100)));
|
||||
assert_eq!(subtable.glyph_index(100), None);
|
||||
|
||||
let mut vec = vec![];
|
||||
subtable.codepoints(|c| vec.push(c));
|
||||
assert_eq!(vec, [0x40]);
|
||||
}
|
||||
}
|
||||
|
||||
mod format2 {
|
||||
use ttf_parser::{cmap, GlyphId};
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
const U16_SIZE: usize = std::mem::size_of::<u16>();
|
||||
|
||||
#[test]
|
||||
fn collect_codepoints() {
|
||||
let mut data = convert(&[
|
||||
UInt16(2), // format
|
||||
UInt16(534), // subtable size
|
||||
UInt16(0), // language ID
|
||||
]);
|
||||
|
||||
// Make only high byte 0x28 multi-byte.
|
||||
data.extend(std::iter::repeat(0x00).take(256 * U16_SIZE));
|
||||
data[6 + 0x28 * U16_SIZE + 1] = 0x08;
|
||||
|
||||
data.extend(convert(&[
|
||||
// First sub header (for single byte mapping)
|
||||
UInt16(254), // first code
|
||||
UInt16(2), // entry count
|
||||
UInt16(0), // id delta: uninteresting
|
||||
UInt16(0), // id range offset: uninteresting
|
||||
// Second sub header (for high byte 0x28)
|
||||
UInt16(16), // first code: (0x28 << 8) + 0x10 = 10256
|
||||
UInt16(3), // entry count
|
||||
UInt16(0), // id delta: uninteresting
|
||||
UInt16(0), // id range offset: uninteresting
|
||||
]));
|
||||
|
||||
// Now only glyph ID's would follow. Not interesting for codepoints.
|
||||
|
||||
let subtable = cmap::Subtable2::parse(&data).unwrap();
|
||||
|
||||
let mut vec = vec![];
|
||||
subtable.codepoints(|c| vec.push(c));
|
||||
assert_eq!(vec, [10256, 10257, 10258, 254, 255]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn codepoint_at_range_end() {
|
||||
let mut data = convert(&[
|
||||
UInt16(2), // format
|
||||
UInt16(532), // subtable size
|
||||
UInt16(0), // language ID
|
||||
]);
|
||||
|
||||
// Only single bytes.
|
||||
data.extend(std::iter::repeat(0x00).take(256 * U16_SIZE));
|
||||
data.extend(convert(&[
|
||||
// First sub header (for single byte mapping)
|
||||
UInt16(40), // first code
|
||||
UInt16(2), // entry count
|
||||
UInt16(0), // id delta
|
||||
UInt16(2), // id range offset
|
||||
// Glyph index
|
||||
UInt16(100), // glyph ID [0]
|
||||
UInt16(1000), // glyph ID [1]
|
||||
UInt16(10000), // glyph ID [2] (unused)
|
||||
]));
|
||||
|
||||
let subtable = cmap::Subtable2::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(39), None);
|
||||
assert_eq!(subtable.glyph_index(40), Some(GlyphId(100)));
|
||||
assert_eq!(subtable.glyph_index(41), Some(GlyphId(1000)));
|
||||
assert_eq!(subtable.glyph_index(42), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod format4 {
|
||||
use ttf_parser::{cmap, GlyphId};
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
#[test]
|
||||
fn single_glyph() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(32), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(-64), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(0x41), Some(GlyphId(1)));
|
||||
assert_eq!(subtable.glyph_index(0x42), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn continuous_range() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(32), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(73), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(-64), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(0x40), None);
|
||||
assert_eq!(subtable.glyph_index(0x41), Some(GlyphId(1)));
|
||||
assert_eq!(subtable.glyph_index(0x42), Some(GlyphId(2)));
|
||||
assert_eq!(subtable.glyph_index(0x43), Some(GlyphId(3)));
|
||||
assert_eq!(subtable.glyph_index(0x44), Some(GlyphId(4)));
|
||||
assert_eq!(subtable.glyph_index(0x45), Some(GlyphId(5)));
|
||||
assert_eq!(subtable.glyph_index(0x46), Some(GlyphId(6)));
|
||||
assert_eq!(subtable.glyph_index(0x47), Some(GlyphId(7)));
|
||||
assert_eq!(subtable.glyph_index(0x48), Some(GlyphId(8)));
|
||||
assert_eq!(subtable.glyph_index(0x49), Some(GlyphId(9)));
|
||||
assert_eq!(subtable.glyph_index(0x4A), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_ranges() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(48), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(8), // 2 x segCount
|
||||
UInt16(4), // search range
|
||||
UInt16(1), // entry selector
|
||||
UInt16(4), // range shift
|
||||
// End character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(69), // char code [1]
|
||||
UInt16(73), // char code [2]
|
||||
UInt16(65535), // char code [3]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(67), // char code [1]
|
||||
UInt16(71), // char code [2]
|
||||
UInt16(65535), // char code [3]
|
||||
// Deltas
|
||||
Int16(-64), // delta [0]
|
||||
Int16(-65), // delta [1]
|
||||
Int16(-66), // delta [2]
|
||||
Int16(1), // delta [3]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
UInt16(0), // offset [2]
|
||||
UInt16(0), // offset [3]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(0x40), None);
|
||||
assert_eq!(subtable.glyph_index(0x41), Some(GlyphId(1)));
|
||||
assert_eq!(subtable.glyph_index(0x42), None);
|
||||
assert_eq!(subtable.glyph_index(0x43), Some(GlyphId(2)));
|
||||
assert_eq!(subtable.glyph_index(0x44), Some(GlyphId(3)));
|
||||
assert_eq!(subtable.glyph_index(0x45), Some(GlyphId(4)));
|
||||
assert_eq!(subtable.glyph_index(0x46), None);
|
||||
assert_eq!(subtable.glyph_index(0x47), Some(GlyphId(5)));
|
||||
assert_eq!(subtable.glyph_index(0x48), Some(GlyphId(6)));
|
||||
assert_eq!(subtable.glyph_index(0x49), Some(GlyphId(7)));
|
||||
assert_eq!(subtable.glyph_index(0x4A), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unordered_ids() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(42), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(69), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(0), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(4), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
// Glyph index array
|
||||
UInt16(1), // glyph ID [0]
|
||||
UInt16(10), // glyph ID [1]
|
||||
UInt16(100), // glyph ID [2]
|
||||
UInt16(1000), // glyph ID [3]
|
||||
UInt16(10000), // glyph ID [4]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(0x40), None);
|
||||
assert_eq!(subtable.glyph_index(0x41), Some(GlyphId(1)));
|
||||
assert_eq!(subtable.glyph_index(0x42), Some(GlyphId(10)));
|
||||
assert_eq!(subtable.glyph_index(0x43), Some(GlyphId(100)));
|
||||
assert_eq!(subtable.glyph_index(0x44), Some(GlyphId(1000)));
|
||||
assert_eq!(subtable.glyph_index(0x45), Some(GlyphId(10000)));
|
||||
assert_eq!(subtable.glyph_index(0x46), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unordered_chars_and_ids() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(64), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(12), // 2 x segCount
|
||||
UInt16(8), // search range
|
||||
UInt16(2), // entry selector
|
||||
UInt16(4), // range shift
|
||||
// End character codes
|
||||
UInt16(80), // char code [0]
|
||||
UInt16(256), // char code [1]
|
||||
UInt16(336), // char code [2]
|
||||
UInt16(512), // char code [3]
|
||||
UInt16(592), // char code [4]
|
||||
UInt16(65535), // char code [5]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(80), // char code [0]
|
||||
UInt16(256), // char code [1]
|
||||
UInt16(336), // char code [2]
|
||||
UInt16(512), // char code [3]
|
||||
UInt16(592), // char code [4]
|
||||
UInt16(65535), // char code [5]
|
||||
// Deltas
|
||||
Int16(-79), // delta [0]
|
||||
Int16(-246), // delta [1]
|
||||
Int16(-236), // delta [2]
|
||||
Int16(488), // delta [3]
|
||||
Int16(9408), // delta [4]
|
||||
Int16(1), // delta [5]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
UInt16(0), // offset [2]
|
||||
UInt16(0), // offset [3]
|
||||
UInt16(0), // offset [4]
|
||||
UInt16(0), // offset [5]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(0x40), None);
|
||||
assert_eq!(subtable.glyph_index(0x50), Some(GlyphId(1)));
|
||||
assert_eq!(subtable.glyph_index(0x100), Some(GlyphId(10)));
|
||||
assert_eq!(subtable.glyph_index(0x150), Some(GlyphId(100)));
|
||||
assert_eq!(subtable.glyph_index(0x200), Some(GlyphId(1000)));
|
||||
assert_eq!(subtable.glyph_index(0x250), Some(GlyphId(10000)));
|
||||
assert_eq!(subtable.glyph_index(0x300), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_end_codes() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(28), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(73), // char code [0]
|
||||
// 0xFF, 0xFF, // char code [1] <-- removed
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
// 0xFF, 0xFF, // char code [1] <-- removed
|
||||
// Deltas
|
||||
Int16(-64), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
]);
|
||||
|
||||
assert!(cmap::Subtable4::parse(&data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_segment_count() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(32), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(1), // 2 x segCount <-- must be more than 1
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(-64), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
]);
|
||||
|
||||
assert!(cmap::Subtable4::parse(&data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_end_segments() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(32), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(2), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(-64), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
// Should not loop forever.
|
||||
assert_eq!(subtable.glyph_index(0x41), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_length() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(16), // subtable size <-- the size should be 32, but we don't check it anyway
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(-64), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(0x41), Some(GlyphId(1)));
|
||||
assert_eq!(subtable.glyph_index(0x42), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn codepoint_out_of_range() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(32), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(-64), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(0), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
// Format 4 support only u16 codepoints, so we have to bail immediately otherwise.
|
||||
assert_eq!(subtable.glyph_index(0x1FFFF), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(42), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(69), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(0), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(4), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
// Glyph index array
|
||||
UInt16(0), // glyph ID [0] <-- indicates missing glyph
|
||||
UInt16(10), // glyph ID [1]
|
||||
UInt16(100), // glyph ID [2]
|
||||
UInt16(1000), // glyph ID [3]
|
||||
UInt16(10000), // glyph ID [4]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(0x41), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_offset() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(42), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(69), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(65), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
// Deltas
|
||||
Int16(0), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(4), // offset [0]
|
||||
UInt16(65535), // offset [1]
|
||||
// Glyph index array
|
||||
UInt16(1), // glyph ID [0]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
assert_eq!(subtable.glyph_index(65535), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect_codepoints() {
|
||||
let data = convert(&[
|
||||
UInt16(4), // format
|
||||
UInt16(24), // subtable size
|
||||
UInt16(0), // language ID
|
||||
UInt16(4), // 2 x segCount
|
||||
UInt16(2), // search range
|
||||
UInt16(0), // entry selector
|
||||
UInt16(2), // range shift
|
||||
// End character codes
|
||||
UInt16(34), // char code [0]
|
||||
UInt16(65535), // char code [1]
|
||||
UInt16(0), // reserved
|
||||
// Start character codes
|
||||
UInt16(27), // char code [0]
|
||||
UInt16(65533), // char code [1]
|
||||
// Deltas
|
||||
Int16(0), // delta [0]
|
||||
Int16(1), // delta [1]
|
||||
// Offsets into Glyph index array
|
||||
UInt16(4), // offset [0]
|
||||
UInt16(0), // offset [1]
|
||||
// Glyph index array
|
||||
UInt16(0), // glyph ID [0]
|
||||
UInt16(10), // glyph ID [1]
|
||||
]);
|
||||
|
||||
let subtable = cmap::Subtable4::parse(&data).unwrap();
|
||||
|
||||
let mut vec = vec![];
|
||||
subtable.codepoints(|c| vec.push(c));
|
||||
assert_eq!(vec, [27, 28, 29, 30, 31, 32, 33, 34, 65533, 65534, 65535]);
|
||||
}
|
||||
}
|
||||
104
third-party/vendor/ttf-parser/tests/tables/colr.rs
vendored
Normal file
104
third-party/vendor/ttf-parser/tests/tables/colr.rs
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
use crate::{convert, Unit::*};
|
||||
use ttf_parser::colr::{self, Painter};
|
||||
use ttf_parser::{cpal, GlyphId, RgbaColor};
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let cpal_data = convert(&[
|
||||
UInt16(0), // version
|
||||
UInt16(3), // number of palette entries
|
||||
UInt16(1), // number of palettes
|
||||
UInt16(3), // number of colors
|
||||
UInt32(14), // offset to colors
|
||||
UInt16(0), // index of palette 0's first color
|
||||
UInt8(10), UInt8(15), UInt8(20), UInt8(25), // color 0
|
||||
UInt8(30), UInt8(35), UInt8(40), UInt8(45), // color 1
|
||||
UInt8(50), UInt8(55), UInt8(60), UInt8(65), // color 2
|
||||
]);
|
||||
|
||||
let colr_data = convert(&[
|
||||
UInt16(0), // version
|
||||
UInt16(3), // number of base glyphs
|
||||
UInt32(14), // offset to base glyphs
|
||||
UInt32(32), // offset to layers
|
||||
UInt16(4), // number of layers
|
||||
UInt16(2), UInt16(2), UInt16(2), // base glyph 0 (id 2)
|
||||
UInt16(3), UInt16(0), UInt16(3), // base glyph 1 (id 3)
|
||||
UInt16(7), UInt16(1), UInt16(1), // base glyph 2 (id 7)
|
||||
UInt16(10), UInt16(2), // layer 0
|
||||
UInt16(11), UInt16(1), // layer 1
|
||||
UInt16(12), UInt16(2), // layer 2
|
||||
UInt16(13), UInt16(0), // layer 3
|
||||
]);
|
||||
|
||||
let cpal = cpal::Table::parse(&cpal_data).unwrap();
|
||||
let colr = colr::Table::parse(cpal, &colr_data).unwrap();
|
||||
let paint = |id| {
|
||||
let mut painter = VecPainter(vec![]);
|
||||
colr.paint(GlyphId(id), 0, &mut painter).map(|_| painter.0)
|
||||
};
|
||||
|
||||
let a = RgbaColor::new(20, 15, 10, 25);
|
||||
let b = RgbaColor::new(40, 35, 30, 45);
|
||||
let c = RgbaColor::new(60, 55, 50, 65);
|
||||
|
||||
assert_eq!(cpal.get(0, 0), Some(a));
|
||||
assert_eq!(cpal.get(0, 1), Some(b));
|
||||
assert_eq!(cpal.get(0, 2), Some(c));
|
||||
assert_eq!(cpal.get(0, 3), None);
|
||||
assert_eq!(cpal.get(1, 0), None);
|
||||
|
||||
assert!(!colr.contains(GlyphId(1)));
|
||||
assert!(colr.contains(GlyphId(2)));
|
||||
assert!(colr.contains(GlyphId(3)));
|
||||
assert!(!colr.contains(GlyphId(4)));
|
||||
assert!(!colr.contains(GlyphId(5)));
|
||||
assert!(!colr.contains(GlyphId(6)));
|
||||
assert!(colr.contains(GlyphId(7)));
|
||||
|
||||
assert_eq!(paint(1), None);
|
||||
|
||||
assert_eq!(paint(2).unwrap(), vec![
|
||||
Command::Outline(12),
|
||||
Command::PaintColor(c),
|
||||
Command::Outline(13),
|
||||
Command::PaintColor(a),
|
||||
]);
|
||||
|
||||
assert_eq!(paint(3).unwrap(), vec![
|
||||
Command::Outline(10),
|
||||
Command::PaintColor(c),
|
||||
Command::Outline(11),
|
||||
Command::PaintColor(b),
|
||||
Command::Outline(12),
|
||||
Command::PaintColor(c),
|
||||
]);
|
||||
|
||||
assert_eq!(paint(7).unwrap(), vec![
|
||||
Command::Outline(11),
|
||||
Command::PaintColor(b),
|
||||
]);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
enum Command {
|
||||
Outline(u16),
|
||||
Foreground,
|
||||
PaintColor(RgbaColor),
|
||||
}
|
||||
|
||||
struct VecPainter(Vec<Command>);
|
||||
|
||||
impl Painter for VecPainter {
|
||||
fn outline(&mut self, glyph_id: GlyphId) {
|
||||
self.0.push(Command::Outline(glyph_id.0));
|
||||
}
|
||||
|
||||
fn paint_foreground(&mut self) {
|
||||
self.0.push(Command::Foreground);
|
||||
}
|
||||
|
||||
fn paint_color(&mut self, color: RgbaColor) {
|
||||
self.0.push(Command::PaintColor(color));
|
||||
}
|
||||
}
|
||||
83
third-party/vendor/ttf-parser/tests/tables/feat.rs
vendored
Normal file
83
third-party/vendor/ttf-parser/tests/tables/feat.rs
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
use ttf_parser::feat::Table;
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let data = convert(&[
|
||||
Fixed(1.0), // version
|
||||
UInt16(4), // number of features
|
||||
UInt16(0), // reserved
|
||||
UInt32(0), // reserved
|
||||
|
||||
// Feature Name [0]
|
||||
UInt16(0), // feature
|
||||
UInt16(1), // number of settings
|
||||
UInt32(60), // offset to settings table
|
||||
UInt16(0), // flags: none
|
||||
UInt16(260), // name index
|
||||
|
||||
// Feature Name [1]
|
||||
UInt16(1), // feature
|
||||
UInt16(1), // number of settings
|
||||
UInt32(64), // offset to settings table
|
||||
UInt16(0), // flags: none
|
||||
UInt16(256), // name index
|
||||
|
||||
// Feature Name [2]
|
||||
UInt16(3), // feature
|
||||
UInt16(3), // number of settings
|
||||
UInt32(68), // offset to settings table
|
||||
Raw(&[0x80, 0x00]), // flags: exclusive
|
||||
UInt16(262), // name index
|
||||
|
||||
// Feature Name [3]
|
||||
UInt16(6), // feature
|
||||
UInt16(2), // number of settings
|
||||
UInt32(80), // offset to settings table
|
||||
Raw(&[0xC0, 0x01]), // flags: exclusive and other
|
||||
UInt16(258), // name index
|
||||
|
||||
// Setting Name [0]
|
||||
UInt16(0), // setting
|
||||
UInt16(261), // name index
|
||||
|
||||
// Setting Name [1]
|
||||
UInt16(2), // setting
|
||||
UInt16(257), // name index
|
||||
|
||||
// Setting Name [2]
|
||||
UInt16(0), // setting
|
||||
UInt16(268), // name index
|
||||
UInt16(3), // setting
|
||||
UInt16(264), // name index
|
||||
UInt16(4), // setting
|
||||
UInt16(265), // name index
|
||||
|
||||
// Setting Name [3]
|
||||
UInt16(0), // setting
|
||||
UInt16(259), // name index
|
||||
UInt16(1), // setting
|
||||
UInt16(260), // name index
|
||||
]);
|
||||
|
||||
let table = Table::parse(&data).unwrap();
|
||||
assert_eq!(table.names.len(), 4);
|
||||
|
||||
let feature0 = table.names.get(0).unwrap();
|
||||
assert_eq!(feature0.feature, 0);
|
||||
assert_eq!(feature0.setting_names.len(), 1);
|
||||
assert_eq!(feature0.exclusive, false);
|
||||
assert_eq!(feature0.name_index, 260);
|
||||
|
||||
let feature2 = table.names.get(2).unwrap();
|
||||
assert_eq!(feature2.feature, 3);
|
||||
assert_eq!(feature2.setting_names.len(), 3);
|
||||
assert_eq!(feature2.exclusive, true);
|
||||
|
||||
assert_eq!(feature2.setting_names.get(1).unwrap().setting, 3);
|
||||
assert_eq!(feature2.setting_names.get(1).unwrap().name_index, 264);
|
||||
|
||||
let feature3 = table.names.get(3).unwrap();
|
||||
assert_eq!(feature3.default_setting_index, 1);
|
||||
assert_eq!(feature3.exclusive, true);
|
||||
}
|
||||
47
third-party/vendor/ttf-parser/tests/tables/glyf.rs
vendored
Normal file
47
third-party/vendor/ttf-parser/tests/tables/glyf.rs
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
struct Builder(String);
|
||||
|
||||
impl ttf_parser::OutlineBuilder for Builder {
|
||||
fn move_to(&mut self, x: f32, y: f32) {
|
||||
write!(&mut self.0, "M {} {} ", x, y).unwrap();
|
||||
}
|
||||
|
||||
fn line_to(&mut self, x: f32, y: f32) {
|
||||
write!(&mut self.0, "L {} {} ", x, y).unwrap();
|
||||
}
|
||||
|
||||
fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
|
||||
write!(&mut self.0, "Q {} {} {} {} ", x1, y1, x, y).unwrap();
|
||||
}
|
||||
|
||||
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
|
||||
write!(&mut self.0, "C {} {} {} {} {} {} ", x1, y1, x2, y2, x, y).unwrap();
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
write!(&mut self.0, "Z ").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn endless_loop() {
|
||||
let data = b"\x00\x01\x00\x00\x00\x0f\x00\x10\x00PTT-W\x002h\xd7\x81x\x00\
|
||||
\x00\x00?L\xbaN\x00c\x9a\x9e\x8f\x96\xe3\xfeu\xff\x00\xb2\x00@\x03\x00\xb8\
|
||||
cvt 5:\x00\x00\x00\xb5\xf8\x01\x00\x03\x9ckEr\x92\xd7\xe6\x98M\xdc\x00\x00\
|
||||
\x03\xe0\x00\x00\x00dglyf\"\t\x15`\x00\x00\x03\xe0\x00\x00\x00dglyf\"\t\x15\
|
||||
`\x00\x00\x00 \x00\x00\x00\xfc\x97\x9fmx\x87\xc9\xc8\xfe\x00\x00\xbad\xff\
|
||||
\xff\xf1\xc8head\xc7\x17\xce[\x00\x00\x00\xfc\x00\x00\x006hhea\x03\xc6\x05\
|
||||
\xe4\x00\x00\x014\x00\x00\x00$hmtx\xc9\xfdq\xed\x00\x00\xb5\xf8\x01\x00\x03\
|
||||
\x9ckEr\x92\xd7\xe6\xdch\x00\x00\xc9d\x00\x00\x04 loca\x00M\x82\x11\x00\x00\
|
||||
\x00\x06\x00\x00\x00\xa0maxp\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 name\
|
||||
\xf4\xd6\xfe\xad\x00OTTO\x00\x02gpost5;5\xe1\x00\x00\xb0P\x00\x00\x01\xf0perp%\
|
||||
\xb0{\x04\x93D\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x01\x00\x00\xe1!yf%1\
|
||||
\x08\x95\x00\x00\x00\x00\x00\xaa\x06\x80fmtx\x02\x00\x00\x00\x00\x00\x00\x00\
|
||||
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcc\xff\
|
||||
\xce\x03CCCCCCCCC\x00\x00\x00\x00\x00C\x00\x00\x00\x00\xb5\xf8\x01\x00\x00\x9c";
|
||||
|
||||
let face = ttf_parser::Face::parse(data, 0).unwrap();
|
||||
let _ = face.outline_glyph(ttf_parser::GlyphId(0), &mut Builder(String::new()));
|
||||
}
|
||||
114
third-party/vendor/ttf-parser/tests/tables/hmtx.rs
vendored
Normal file
114
third-party/vendor/ttf-parser/tests/tables/hmtx.rs
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
use std::num::NonZeroU16;
|
||||
use ttf_parser::GlyphId;
|
||||
use ttf_parser::hmtx::Table;
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
macro_rules! nzu16 {
|
||||
($n:expr) => { NonZeroU16::new($n).unwrap() };
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_case() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // advance width [0]
|
||||
Int16(2), // side bearing [0]
|
||||
]);
|
||||
|
||||
let table = Table::parse(1, nzu16!(1), &data).unwrap();
|
||||
assert_eq!(table.advance(GlyphId(0)), Some(1));
|
||||
assert_eq!(table.side_bearing(GlyphId(0)), Some(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
assert!(Table::parse(1, nzu16!(1), &[]).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_metrics() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // advance width [0]
|
||||
Int16(2), // side bearing [0]
|
||||
]);
|
||||
|
||||
assert!(Table::parse(0, nzu16!(1), &data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smaller_than_glyphs_count() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // advance width [0]
|
||||
Int16(2), // side bearing [0]
|
||||
|
||||
Int16(3), // side bearing [1]
|
||||
]);
|
||||
|
||||
let table = Table::parse(1, nzu16!(2), &data).unwrap();
|
||||
assert_eq!(table.advance(GlyphId(0)), Some(1));
|
||||
assert_eq!(table.side_bearing(GlyphId(0)), Some(2));
|
||||
assert_eq!(table.advance(GlyphId(1)), Some(1));
|
||||
assert_eq!(table.side_bearing(GlyphId(1)), Some(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_additional_side_bearings() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // advance width [0]
|
||||
Int16(2), // side bearing [0]
|
||||
|
||||
// A single side bearing should be present here.
|
||||
// We should simply ignore it and not return None during Table parsing.
|
||||
]);
|
||||
|
||||
let table = Table::parse(1, nzu16!(2), &data).unwrap();
|
||||
assert_eq!(table.advance(GlyphId(0)), Some(1));
|
||||
assert_eq!(table.side_bearing(GlyphId(0)), Some(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_metrics_than_glyphs() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // advance width [0]
|
||||
Int16(2), // side bearing [0]
|
||||
|
||||
UInt16(3), // advance width [1]
|
||||
Int16(4), // side bearing [1]
|
||||
|
||||
Int16(5), // side bearing [2]
|
||||
]);
|
||||
|
||||
let table = Table::parse(2, nzu16!(1), &data).unwrap();
|
||||
assert_eq!(table.side_bearing(GlyphId(0)), Some(2));
|
||||
assert_eq!(table.side_bearing(GlyphId(1)), Some(4));
|
||||
assert_eq!(table.side_bearing(GlyphId(2)), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glyph_out_of_bounds_0() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // advance width [0]
|
||||
Int16(2), // side bearing [0]
|
||||
]);
|
||||
|
||||
let table = Table::parse(1, nzu16!(1), &data).unwrap();
|
||||
assert_eq!(table.advance(GlyphId(0)), Some(1));
|
||||
assert_eq!(table.side_bearing(GlyphId(0)), Some(2));
|
||||
assert_eq!(table.advance(GlyphId(1)), None);
|
||||
assert_eq!(table.side_bearing(GlyphId(1)), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glyph_out_of_bounds_1() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // advance width [0]
|
||||
Int16(2), // side bearing [0]
|
||||
|
||||
Int16(3), // side bearing [1]
|
||||
]);
|
||||
|
||||
let table = Table::parse(1, nzu16!(2), &data).unwrap();
|
||||
assert_eq!(table.advance(GlyphId(1)), Some(1));
|
||||
assert_eq!(table.side_bearing(GlyphId(1)), Some(3));
|
||||
assert_eq!(table.advance(GlyphId(2)), None);
|
||||
assert_eq!(table.side_bearing(GlyphId(2)), None);
|
||||
}
|
||||
176
third-party/vendor/ttf-parser/tests/tables/main.rs
vendored
Normal file
176
third-party/vendor/ttf-parser/tests/tables/main.rs
vendored
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
#[rustfmt::skip] mod aat;
|
||||
#[rustfmt::skip] mod ankr;
|
||||
#[rustfmt::skip] mod cff1;
|
||||
#[rustfmt::skip] mod cmap;
|
||||
#[rustfmt::skip] mod colr;
|
||||
#[rustfmt::skip] mod feat;
|
||||
#[rustfmt::skip] mod glyf;
|
||||
#[rustfmt::skip] mod hmtx;
|
||||
#[rustfmt::skip] mod maxp;
|
||||
#[rustfmt::skip] mod sbix;
|
||||
#[rustfmt::skip] mod trak;
|
||||
|
||||
use ttf_parser::{fonts_in_collection, Face, FaceParsingError};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Unit {
|
||||
Raw(&'static [u8]),
|
||||
Int8(i8),
|
||||
UInt8(u8),
|
||||
Int16(i16),
|
||||
UInt16(u16),
|
||||
Int32(i32),
|
||||
UInt32(u32),
|
||||
Fixed(f32),
|
||||
}
|
||||
|
||||
pub fn convert(units: &[Unit]) -> Vec<u8> {
|
||||
let mut data = Vec::with_capacity(256);
|
||||
for v in units {
|
||||
convert_unit(*v, &mut data);
|
||||
}
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
fn convert_unit(unit: Unit, data: &mut Vec<u8>) {
|
||||
match unit {
|
||||
Unit::Raw(bytes) => {
|
||||
data.extend_from_slice(bytes);
|
||||
}
|
||||
Unit::Int8(n) => {
|
||||
data.extend_from_slice(&i8::to_be_bytes(n));
|
||||
}
|
||||
Unit::UInt8(n) => {
|
||||
data.extend_from_slice(&u8::to_be_bytes(n));
|
||||
}
|
||||
Unit::Int16(n) => {
|
||||
data.extend_from_slice(&i16::to_be_bytes(n));
|
||||
}
|
||||
Unit::UInt16(n) => {
|
||||
data.extend_from_slice(&u16::to_be_bytes(n));
|
||||
}
|
||||
Unit::Int32(n) => {
|
||||
data.extend_from_slice(&i32::to_be_bytes(n));
|
||||
}
|
||||
Unit::UInt32(n) => {
|
||||
data.extend_from_slice(&u32::to_be_bytes(n));
|
||||
}
|
||||
Unit::Fixed(n) => {
|
||||
data.extend_from_slice(&i32::to_be_bytes((n * 65536.0) as i32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_font() {
|
||||
assert_eq!(
|
||||
Face::parse(&[], 0).unwrap_err(),
|
||||
FaceParsingError::UnknownMagic
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_tables() {
|
||||
use Unit::*;
|
||||
let data = convert(&[
|
||||
Raw(&[0x00, 0x01, 0x00, 0x00]), // magic
|
||||
UInt16(0), // numTables
|
||||
UInt16(0), // searchRange
|
||||
UInt16(0), // entrySelector
|
||||
UInt16(0), // rangeShift
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
Face::parse(&data, 0).unwrap_err(),
|
||||
FaceParsingError::NoHeadTable
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tables_count_overflow() {
|
||||
use Unit::*;
|
||||
let data = convert(&[
|
||||
Raw(&[0x00, 0x01, 0x00, 0x00]), // magic
|
||||
UInt16(std::u16::MAX), // numTables
|
||||
UInt16(0), // searchRange
|
||||
UInt16(0), // entrySelector
|
||||
UInt16(0), // rangeShift
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
Face::parse(&data, 0).unwrap_err(),
|
||||
FaceParsingError::MalformedFont
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_font_collection() {
|
||||
use Unit::*;
|
||||
let data = convert(&[
|
||||
Raw(&[0x74, 0x74, 0x63, 0x66]), // magic
|
||||
UInt16(0), // majorVersion
|
||||
UInt16(0), // minorVersion
|
||||
UInt32(0), // numFonts
|
||||
]);
|
||||
|
||||
assert_eq!(fonts_in_collection(&data), Some(0));
|
||||
assert_eq!(
|
||||
Face::parse(&data, 0).unwrap_err(),
|
||||
FaceParsingError::FaceIndexOutOfBounds
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn font_collection_num_fonts_overflow() {
|
||||
use Unit::*;
|
||||
let data = convert(&[
|
||||
Raw(&[0x74, 0x74, 0x63, 0x66]), // magic
|
||||
UInt16(0), // majorVersion
|
||||
UInt16(0), // minorVersion
|
||||
UInt32(std::u32::MAX), // numFonts
|
||||
]);
|
||||
|
||||
assert_eq!(fonts_in_collection(&data), Some(std::u32::MAX));
|
||||
assert_eq!(
|
||||
Face::parse(&data, 0).unwrap_err(),
|
||||
FaceParsingError::MalformedFont
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn font_index_overflow() {
|
||||
use Unit::*;
|
||||
let data = convert(&[
|
||||
Raw(&[0x74, 0x74, 0x63, 0x66]), // magic
|
||||
UInt16(0), // majorVersion
|
||||
UInt16(0), // minorVersion
|
||||
UInt32(1), // numFonts
|
||||
UInt32(12), // offset [0]
|
||||
]);
|
||||
|
||||
assert_eq!(fonts_in_collection(&data), Some(1));
|
||||
assert_eq!(
|
||||
Face::parse(&data, std::u32::MAX).unwrap_err(),
|
||||
FaceParsingError::FaceIndexOutOfBounds
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn font_index_overflow_on_regular_font() {
|
||||
use Unit::*;
|
||||
let data = convert(&[
|
||||
Raw(&[0x00, 0x01, 0x00, 0x00]), // magic
|
||||
UInt16(0), // numTables
|
||||
UInt16(0), // searchRange
|
||||
UInt16(0), // entrySelector
|
||||
UInt16(0), // rangeShift
|
||||
]);
|
||||
|
||||
assert_eq!(fonts_in_collection(&data), None);
|
||||
assert_eq!(
|
||||
Face::parse(&data, 1).unwrap_err(),
|
||||
FaceParsingError::FaceIndexOutOfBounds
|
||||
);
|
||||
}
|
||||
65
third-party/vendor/ttf-parser/tests/tables/maxp.rs
vendored
Normal file
65
third-party/vendor/ttf-parser/tests/tables/maxp.rs
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
use std::num::NonZeroU16;
|
||||
use ttf_parser::maxp::Table;
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
#[test]
|
||||
fn version_05() {
|
||||
let table = Table::parse(&convert(&[
|
||||
Fixed(0.3125), // version
|
||||
UInt16(1), // number of glyphs
|
||||
])).unwrap();
|
||||
assert_eq!(table.number_of_glyphs, NonZeroU16::new(1).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_1_full() {
|
||||
let table = Table::parse(&convert(&[
|
||||
Fixed(1.0), // version
|
||||
UInt16(1), // number of glyphs
|
||||
UInt16(0), // maximum points in a non-composite glyph
|
||||
UInt16(0), // maximum contours in a non-composite glyph
|
||||
UInt16(0), // maximum points in a composite glyph
|
||||
UInt16(0), // maximum contours in a composite glyph
|
||||
UInt16(0), // maximum zones
|
||||
UInt16(0), // maximum twilight points
|
||||
UInt16(0), // number of Storage Area locations
|
||||
UInt16(0), // number of FDEFs
|
||||
UInt16(0), // number of IDEFs
|
||||
UInt16(0), // maximum stack depth
|
||||
UInt16(0), // maximum byte count for glyph instructions
|
||||
UInt16(0), // maximum number of components
|
||||
UInt16(0), // maximum levels of recursion
|
||||
])).unwrap();
|
||||
assert_eq!(table.number_of_glyphs, NonZeroU16::new(1).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_1_trimmed() {
|
||||
// We don't really care about the data after the number of glyphs.
|
||||
let table = Table::parse(&convert(&[
|
||||
Fixed(1.0), // version
|
||||
UInt16(1), // number of glyphs
|
||||
])).unwrap();
|
||||
assert_eq!(table.number_of_glyphs, NonZeroU16::new(1).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_version() {
|
||||
let table = Table::parse(&convert(&[
|
||||
Fixed(0.0), // version
|
||||
UInt16(1), // number of glyphs
|
||||
]));
|
||||
assert!(table.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_glyphs() {
|
||||
let table = Table::parse(&convert(&[
|
||||
Fixed(0.3125), // version
|
||||
UInt16(0), // number of glyphs
|
||||
]));
|
||||
assert!(table.is_none());
|
||||
}
|
||||
|
||||
// TODO: what to do when the number of glyphs is 0xFFFF?
|
||||
// we're actually checking this in loca
|
||||
135
third-party/vendor/ttf-parser/tests/tables/sbix.rs
vendored
Normal file
135
third-party/vendor/ttf-parser/tests/tables/sbix.rs
vendored
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
use std::num::NonZeroU16;
|
||||
use ttf_parser::{GlyphId, RasterImageFormat};
|
||||
use ttf_parser::sbix::Table;
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
#[test]
|
||||
fn single_glyph() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // version
|
||||
UInt16(0), // flags
|
||||
UInt32(1), // number of strikes
|
||||
UInt32(12), // strike offset [0]
|
||||
|
||||
// Strike [0]
|
||||
UInt16(20), // pixels_per_em
|
||||
UInt16(72), // ppi
|
||||
UInt32(12), // glyph data offset [0]
|
||||
UInt32(44), // glyph data offset [1]
|
||||
|
||||
// Glyph Data [0]
|
||||
UInt16(1), // x
|
||||
UInt16(2), // y
|
||||
Raw(b"png "), // type tag
|
||||
// PNG data, just the part we need
|
||||
Raw(&[0x89, 0x50, 0x4E, 0x47]),
|
||||
Raw(&[0x0D, 0x0A, 0x1A, 0x0A]),
|
||||
Raw(&[0x00, 0x00, 0x00, 0x0D]),
|
||||
Raw(&[0x49, 0x48, 0x44, 0x52]),
|
||||
UInt32(20), // width
|
||||
UInt32(30), // height
|
||||
]);
|
||||
|
||||
let table = Table::parse(NonZeroU16::new(1).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.strikes.len(), 1);
|
||||
|
||||
let strike = table.strikes.get(0).unwrap();
|
||||
assert_eq!(strike.pixels_per_em, 20);
|
||||
assert_eq!(strike.ppi, 72);
|
||||
assert_eq!(strike.len(), 1);
|
||||
|
||||
let glyph_data = strike.get(GlyphId(0)).unwrap();
|
||||
assert_eq!(glyph_data.x, 1);
|
||||
assert_eq!(glyph_data.y, 2);
|
||||
assert_eq!(glyph_data.width, 20);
|
||||
assert_eq!(glyph_data.height, 30);
|
||||
assert_eq!(glyph_data.pixels_per_em, 20);
|
||||
assert_eq!(glyph_data.format, RasterImageFormat::PNG);
|
||||
assert_eq!(glyph_data.data.len(), 24);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_glyph() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // version
|
||||
UInt16(0), // flags
|
||||
UInt32(1), // number of strikes
|
||||
UInt32(12), // strike offset [0]
|
||||
|
||||
// Strike [0]
|
||||
UInt16(20), // pixels_per_em
|
||||
UInt16(72), // ppi
|
||||
UInt32(16), // glyph data offset [0]
|
||||
UInt32(48), // glyph data offset [1]
|
||||
UInt32(58), // glyph data offset [2]
|
||||
|
||||
// Glyph Data [0]
|
||||
UInt16(1), // x
|
||||
UInt16(2), // y
|
||||
Raw(b"png "), // type tag
|
||||
// PNG data, just the part we need
|
||||
Raw(&[0x89, 0x50, 0x4E, 0x47]),
|
||||
Raw(&[0x0D, 0x0A, 0x1A, 0x0A]),
|
||||
Raw(&[0x00, 0x00, 0x00, 0x0D]),
|
||||
Raw(&[0x49, 0x48, 0x44, 0x52]),
|
||||
UInt32(20), // width
|
||||
UInt32(30), // height
|
||||
|
||||
// Glyph Data [1]
|
||||
UInt16(3), // x
|
||||
UInt16(4), // y
|
||||
Raw(b"dupe"), // type tag
|
||||
UInt16(0), // glyph id
|
||||
]);
|
||||
|
||||
let table = Table::parse(NonZeroU16::new(2).unwrap(), &data).unwrap();
|
||||
assert_eq!(table.strikes.len(), 1);
|
||||
|
||||
let strike = table.strikes.get(0).unwrap();
|
||||
assert_eq!(strike.pixels_per_em, 20);
|
||||
assert_eq!(strike.ppi, 72);
|
||||
assert_eq!(strike.len(), 2);
|
||||
|
||||
let glyph_data = strike.get(GlyphId(1)).unwrap();
|
||||
assert_eq!(glyph_data.x, 1);
|
||||
assert_eq!(glyph_data.y, 2);
|
||||
assert_eq!(glyph_data.width, 20);
|
||||
assert_eq!(glyph_data.height, 30);
|
||||
assert_eq!(glyph_data.pixels_per_em, 20);
|
||||
assert_eq!(glyph_data.format, RasterImageFormat::PNG);
|
||||
assert_eq!(glyph_data.data.len(), 24);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursive() {
|
||||
let data = convert(&[
|
||||
UInt16(1), // version
|
||||
UInt16(0), // flags
|
||||
UInt32(1), // number of strikes
|
||||
UInt32(12), // strike offset [0]
|
||||
|
||||
// Strike [0]
|
||||
UInt16(20), // pixels_per_em
|
||||
UInt16(72), // ppi
|
||||
UInt32(16), // glyph data offset [0]
|
||||
UInt32(26), // glyph data offset [1]
|
||||
UInt32(36), // glyph data offset [2]
|
||||
|
||||
// Glyph Data [0]
|
||||
UInt16(1), // x
|
||||
UInt16(2), // y
|
||||
Raw(b"dupe"), // type tag
|
||||
UInt16(0), // glyph id
|
||||
|
||||
// Glyph Data [1]
|
||||
UInt16(1), // x
|
||||
UInt16(2), // y
|
||||
Raw(b"dupe"), // type tag
|
||||
UInt16(0), // glyph id
|
||||
]);
|
||||
|
||||
let table = Table::parse(NonZeroU16::new(2).unwrap(), &data).unwrap();
|
||||
let strike = table.strikes.get(0).unwrap();
|
||||
assert!(strike.get(GlyphId(0)).is_none());
|
||||
assert!(strike.get(GlyphId(1)).is_none());
|
||||
}
|
||||
88
third-party/vendor/ttf-parser/tests/tables/trak.rs
vendored
Normal file
88
third-party/vendor/ttf-parser/tests/tables/trak.rs
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
use ttf_parser::trak::Table;
|
||||
use crate::{convert, Unit::*};
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let data = convert(&[
|
||||
Fixed(1.0), // version
|
||||
UInt16(0), // format
|
||||
UInt16(0), // horizontal data offset
|
||||
UInt16(0), // vertical data offset
|
||||
UInt16(0), // padding
|
||||
]);
|
||||
|
||||
let table = Table::parse(&data).unwrap();
|
||||
assert_eq!(table.horizontal.tracks.len(), 0);
|
||||
assert_eq!(table.horizontal.sizes.len(), 0);
|
||||
assert_eq!(table.vertical.tracks.len(), 0);
|
||||
assert_eq!(table.vertical.sizes.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let data = convert(&[
|
||||
Fixed(1.0), // version
|
||||
UInt16(0), // format
|
||||
UInt16(12), // horizontal data offset
|
||||
UInt16(0), // vertical data offset
|
||||
UInt16(0), // padding
|
||||
|
||||
// TrackData
|
||||
UInt16(3), // number of tracks
|
||||
UInt16(2), // number of sizes
|
||||
UInt32(44), // offset to size table
|
||||
|
||||
// TrackTableEntry [0]
|
||||
Fixed(-1.0), // track
|
||||
UInt16(256), // name index
|
||||
UInt16(52), // offset of the two per-size tracking values
|
||||
|
||||
// TrackTableEntry [1]
|
||||
Fixed(0.0), // track
|
||||
UInt16(258), // name index
|
||||
UInt16(60), // offset of the two per-size tracking values
|
||||
|
||||
// TrackTableEntry [2]
|
||||
Fixed(1.0), // track
|
||||
UInt16(257), // name index
|
||||
UInt16(56), // offset of the two per-size tracking values
|
||||
|
||||
// Size [0]
|
||||
Fixed(12.0), // points
|
||||
// Size [1]
|
||||
Fixed(24.0), // points
|
||||
|
||||
// Per-size tracking values.
|
||||
Int16(-15),
|
||||
Int16(-7),
|
||||
Int16(50),
|
||||
Int16(20),
|
||||
Int16(0),
|
||||
Int16(0),
|
||||
]);
|
||||
|
||||
let table = Table::parse(&data).unwrap();
|
||||
|
||||
assert_eq!(table.horizontal.tracks.len(), 3);
|
||||
assert_eq!(table.horizontal.tracks.get(0).unwrap().value, -1.0);
|
||||
assert_eq!(table.horizontal.tracks.get(1).unwrap().value, 0.0);
|
||||
assert_eq!(table.horizontal.tracks.get(2).unwrap().value, 1.0);
|
||||
assert_eq!(table.horizontal.tracks.get(0).unwrap().name_index, 256);
|
||||
assert_eq!(table.horizontal.tracks.get(1).unwrap().name_index, 258);
|
||||
assert_eq!(table.horizontal.tracks.get(2).unwrap().name_index, 257);
|
||||
assert_eq!(table.horizontal.tracks.get(0).unwrap().values.len(), 2);
|
||||
assert_eq!(table.horizontal.tracks.get(0).unwrap().values.get(0).unwrap(), -15);
|
||||
assert_eq!(table.horizontal.tracks.get(0).unwrap().values.get(1).unwrap(), -7);
|
||||
assert_eq!(table.horizontal.tracks.get(1).unwrap().values.len(), 2);
|
||||
assert_eq!(table.horizontal.tracks.get(1).unwrap().values.get(0).unwrap(), 0);
|
||||
assert_eq!(table.horizontal.tracks.get(1).unwrap().values.get(1).unwrap(), 0);
|
||||
assert_eq!(table.horizontal.tracks.get(2).unwrap().values.len(), 2);
|
||||
assert_eq!(table.horizontal.tracks.get(2).unwrap().values.get(0).unwrap(), 50);
|
||||
assert_eq!(table.horizontal.tracks.get(2).unwrap().values.get(1).unwrap(), 20);
|
||||
assert_eq!(table.horizontal.sizes.len(), 2);
|
||||
assert_eq!(table.horizontal.sizes.get(0).unwrap().0, 12.0);
|
||||
assert_eq!(table.horizontal.sizes.get(1).unwrap().0, 24.0);
|
||||
|
||||
assert_eq!(table.vertical.tracks.len(), 0);
|
||||
assert_eq!(table.vertical.sizes.len(), 0);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue