From 7ef6cb31df0fe1ebec99b1077053a586a349f530 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 30 Sep 2022 11:22:45 +0200 Subject: [PATCH] Bump ttf-parser --- Cargo.lock | 64 +++++++++++++++++++----------------- Cargo.toml | 2 +- src/export/pdf/font.rs | 5 +-- src/font/book.rs | 5 +-- src/font/mod.rs | 31 +++++++++++------ src/library/text/mod.rs | 2 +- src/library/text/shaping.rs | 4 +-- tests/ref/text/par.png | Bin 30131 -> 29339 bytes tests/typ/text/par.typ | 2 -- 9 files changed, 65 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 898df1d6f..7e45525f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,12 +196,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -369,23 +368,22 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.48" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a0714f28b1ee39ccec0770ccb544eb02c9ef2c82bb096230eefcffa6468b0" +checksum = "fd911b35d940d2bd0bea0f9100068e5b97b51a1cbe13d13382f132e0365257a0" dependencies = [ "android_system_properties", "core-foundation-sys", "js-sys", - "once_cell", "wasm-bindgen", "winapi", ] [[package]] name = "image" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30ca2ecf7666107ff827a8e481de6a132a9b687ed3bb20bb1c144a36c00964" +checksum = "bd8e4fb07cf672b1642304e731ef8a6a4c7891d67bb4fd4f5ce58cd6ed86803c" dependencies = [ "bytemuck", "byteorder", @@ -503,9 +501,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.132" +version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" [[package]] name = "lipsum" @@ -628,9 +626,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "pdf-writer" @@ -652,9 +650,9 @@ checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" [[package]] name = "pixglyph" version = "0.1.0" -source = "git+https://github.com/typst/pixglyph#f1aae13ae622f4640a1cfac231525f02978fc305" +source = "git+https://github.com/typst/pixglyph#131ea492ceada591c7e2d6dd2a5958ae325bd0d4" dependencies = [ - "ttf-parser", + "ttf-parser 0.17.0", ] [[package]] @@ -677,9 +675,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] @@ -787,11 +785,11 @@ dependencies = [ [[package]] name = "rex" version = "0.1.2" -source = "git+https://github.com/laurmaedje/ReX#6e4bada20d2b1685940e2d752630cb9ad3d797b0" +source = "git+https://github.com/laurmaedje/ReX#672c321a947f945e9ba936ae9fbd982c4e043f1c" dependencies = [ "itertools", "nom", - "ttf-parser", + "ttf-parser 0.17.0", "unicode-math", ] @@ -822,7 +820,7 @@ dependencies = [ "bitflags", "bytemuck", "smallvec", - "ttf-parser", + "ttf-parser 0.15.2", "unicode-bidi-mirroring", "unicode-ccc", "unicode-general-category", @@ -855,18 +853,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -945,9 +943,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -986,18 +984,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -1024,6 +1022,12 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" +[[package]] +name = "ttf-parser" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9146d2aaf37dc5334287712849dfbf6aecfbd97971f2e8d86c5e50ea550d71ae" + [[package]] name = "typed-arena" version = "2.0.1" @@ -1069,7 +1073,7 @@ dependencies = [ "svg2pdf", "syntect", "tiny-skia", - "ttf-parser", + "ttf-parser 0.17.0", "typed-arena", "typst-macros", "unicode-bidi", diff --git a/Cargo.toml b/Cargo.toml index 79ec772cf..aa63a4a72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ comemo = { git = "https://github.com/typst/comemo" } # Text and font handling hypher = "0.1" kurbo = "0.8" -ttf-parser = "0.15" +ttf-parser = "0.17" rustybuzz = "0.5" unicode-bidi = "0.3.5" unicode-segmentation = "1" diff --git a/src/export/pdf/font.rs b/src/export/pdf/font.rs index 446d36bc7..3398478af 100644 --- a/src/export/pdf/font.rs +++ b/src/export/pdf/font.rs @@ -45,8 +45,9 @@ pub fn write_fonts(ctx: &mut PdfContext) { // Check for the presence of CFF outlines to select the correct // CID-Font subtype. let subtype = match ttf - .table_data(Tag::from_bytes(b"CFF ")) - .or(ttf.table_data(Tag::from_bytes(b"CFF2"))) + .raw_face() + .table(Tag::from_bytes(b"CFF ")) + .or(ttf.raw_face().table(Tag::from_bytes(b"CFF2"))) { Some(_) => CidFontType::Type0, None => CidFontType::Type2, diff --git a/src/font/book.rs b/src/font/book.rs index 29190516f..d900d3c44 100644 --- a/src/font/book.rs +++ b/src/font/book.rs @@ -173,7 +173,7 @@ impl FontInfo { pub fn from_data<'a>(data: &'a [u8]) -> impl Iterator + 'a { let count = ttf_parser::fonts_in_collection(data).unwrap_or(1); (0 .. count).filter_map(move |index| { - let ttf = ttf_parser::Face::from_slice(data, index).ok()?; + let ttf = ttf_parser::Face::parse(data, index).ok()?; Self::from_ttf(&ttf) }) } @@ -239,7 +239,8 @@ impl FontInfo { // Determine whether this is a serif or sans-serif font. if let Some(panose) = ttf - .table_data(Tag::from_bytes(b"OS/2")) + .raw_face() + .table(Tag::from_bytes(b"OS/2")) .and_then(|os2| os2.get(32 .. 45)) { if matches!(panose, [2, 2 ..= 10, ..]) { diff --git a/src/font/mod.rs b/src/font/mod.rs index 2404ad326..7cddf1ea0 100644 --- a/src/font/mod.rs +++ b/src/font/mod.rs @@ -10,7 +10,7 @@ use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::sync::Arc; -use once_cell::sync::OnceCell; +use once_cell::unsync::OnceCell; use rex::font::MathHeader; use ttf_parser::{GlyphId, Tag}; @@ -33,8 +33,10 @@ struct Repr { info: FontInfo, /// The font's metrics. metrics: FontMetrics, - /// The underlying ttf-parser/rustybuzz face. - ttf: rustybuzz::Face<'static>, + /// The underlying ttf-parser face. + ttf: ttf_parser::Face<'static>, + /// The underlying rustybuzz face. + rusty: rustybuzz::Face<'static>, /// The parsed ReX math header. math: OnceCell>, } @@ -51,7 +53,8 @@ impl Font { let slice: &'static [u8] = unsafe { std::slice::from_raw_parts(data.as_ptr(), data.len()) }; - let ttf = rustybuzz::Face::from_slice(slice, index)?; + let ttf = ttf_parser::Face::parse(slice, index).ok()?; + let rusty = rustybuzz::Face::from_slice(slice, index)?; let metrics = FontMetrics::from_ttf(&ttf); let info = FontInfo::from_ttf(&ttf)?; @@ -59,8 +62,9 @@ impl Font { data, index, info, - ttf, metrics, + ttf, + rusty, math: OnceCell::new(), }))) } @@ -108,19 +112,26 @@ impl Font { find_name(&self.0.ttf, id) } - /// A reference to the underlying `ttf-parser` / `rustybuzz` face. - pub fn ttf(&self) -> &rustybuzz::Face<'_> { - // We can't implement Deref because that would leak the internal 'static - // lifetime. + /// A reference to the underlying `ttf-parser` face. + pub fn ttf(&self) -> &ttf_parser::Face<'_> { + // We can't implement Deref because that would leak the + // internal 'static lifetime. &self.0.ttf } + /// A reference to the underlying `rustybuzz` face. + pub fn rusty(&self) -> &rustybuzz::Face<'_> { + // We can't implement Deref because that would leak the + // internal 'static lifetime. + &self.0.rusty + } + /// Access the math header, if any. pub fn math(&self) -> Option<&MathHeader> { self.0 .math .get_or_init(|| { - let data = self.ttf().table_data(Tag::from_bytes(b"MATH"))?; + let data = self.ttf().raw_face().table(Tag::from_bytes(b"MATH"))?; MathHeader::parse(data).ok() }) .as_ref() diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs index 934f5e15d..c9bf2e57a 100644 --- a/src/library/text/mod.rs +++ b/src/library/text/mod.rs @@ -22,7 +22,7 @@ pub use shift::*; use std::borrow::Cow; -use ttf_parser::Tag; +use rustybuzz::Tag; use crate::font::{FontMetrics, FontStretch, FontStyle, FontWeight, VerticalFontMetric}; use crate::library::prelude::*; diff --git a/src/library/text/shaping.rs b/src/library/text/shaping.rs index 16989acf3..487b90901 100644 --- a/src/library/text/shaping.rs +++ b/src/library/text/shaping.rs @@ -1,7 +1,7 @@ use std::ops::Range; use std::str::FromStr; -use rustybuzz::{Feature, UnicodeBuffer}; +use rustybuzz::{Feature, Tag, UnicodeBuffer}; use super::*; use crate::font::{Font, FontVariant}; @@ -407,7 +407,7 @@ fn shape_segment<'a>( }); // Shape! - let buffer = rustybuzz::shape(font.ttf(), &ctx.tags, buffer); + let buffer = rustybuzz::shape(font.rusty(), &ctx.tags, buffer); let infos = buffer.glyph_infos(); let pos = buffer.glyph_positions(); diff --git a/tests/ref/text/par.png b/tests/ref/text/par.png index 471437a04f4f668eda069f9376b487f9c8b5179e..16622cc29a96843f37ebf83dcb556f9074764fd3 100644 GIT binary patch delta 8596 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 delta 9404 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

vA#Mb(eGio{XBqgxz;((XdFqNjm@xfk61> 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