typst 0.15.1.6 → 0.15.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97e4afa751e5a0bded609e423ea893b263ac5676afe79fe4bcde12761bd242dd
4
- data.tar.gz: 112c45f8dbebcdcbcec318948b879dc47f44dc5c2bd5a143e4c035928dec6473
3
+ metadata.gz: e504e7d6117a089aea226128ffb96a606d0569184d274a31b786b40323ea2459
4
+ data.tar.gz: c54e606e7ec710230a13fd418b8faeb1f427342f6533ebe0cfa1402fbb0ee327
5
5
  SHA512:
6
- metadata.gz: d825ef788371496a9b354cf1b22d3ea06c9f7fe2e3d1cc56b18310a9af1fede42fe449b23964c20f2b34df98a31155846d21750da0eaed97d146abbd4a7ad425
7
- data.tar.gz: 0c561636ed80e29170ba849853ecd0c8342cb3abc609fb1d7ffeadc466eda702d537a454e1becd36e61f7339adc320ab6177adaf84d3bd8ef048ba6e7ddab222
6
+ metadata.gz: db255e768cc4b75a8f233494478140672721c19de71b5c7a8e9f3dc48cbe89fb4a8a372f004fd5136388ba0a6c673a9e133a003ea73dfc285bab6f371108cd50
7
+ data.tar.gz: ae2a297b332214c1b83ed24a0862b5288aae8ded7a7d921b198f7777ce5ef091492ff85d4484729f171416a2ab8cd9765b4234f338e2bbd7ca3bf9c6434c315d
data/Cargo.toml CHANGED
@@ -1,3 +1,6 @@
1
1
  [workspace]
2
2
  members = ["ext/typst"]
3
- resolver = "2"
3
+ resolver = "2"
4
+
5
+ [profile.release]
6
+ strip = true
data/README.md CHANGED
@@ -269,7 +269,8 @@ clear_cache was contributed by [NRicciVestmark](https://github.com/NRicciVestmar
269
269
  CI improvements were contributed by [am1006](https://github.com/am1006)\
270
270
  Defect resolutions by [adam12](https://github.com/adam12) and [walterdavis](https://github.com/walterdavis)\
271
271
  Design suggestions by [alec-c4](https://github.com/alec-c4)\
272
- Compiler warnings were contributed by [TheSoloHacker47](https://github.com/TheSoloHacker47)
272
+ Compiler warnings were contributed by [TheSoloHacker47](https://github.com/TheSoloHacker47) \
273
+ Font optimization patches were contributed by [dmke](https://github.com/dmke)
273
274
 
274
275
  ## License
275
276
 
data/README.typ CHANGED
@@ -276,7 +276,8 @@ clear_cache was contributed by #link("https://github.com/NRicciVestmark")[NRicci
276
276
  CI improvements were contributed by #link("https://github.com/am1006")[am1006]\
277
277
  Defect resolutions by #link("https://github.com/adam12")[adam12] and #link("https://github.com/walterdavis")[walterdavis]\
278
278
  Design suggestions by #link("https://github.com/alec-c4")[alec-c4]\
279
- Compiler warnings were contributed by #link("https://github.com/TheSoloHacker47")[TheSoloHacker47]
279
+ Compiler warnings were contributed by #link("https://github.com/TheSoloHacker47")[TheSoloHacker47] \
280
+ Font optimization patches were contributed by #link("https://github.com/dmke")[dmke]
280
281
 
281
282
  == License
282
283
 
data/Rakefile CHANGED
@@ -34,6 +34,10 @@ Rake::TestTask.new do |t|
34
34
  t.verbose = true
35
35
  end
36
36
 
37
+ task 'benchmark' do |t|
38
+ sh "bundle exec ruby benchmarks/compile_pdf.rb"
39
+ end
40
+
37
41
  task 'gem:native' do |t|
38
42
  CROSS_PLATFORMS.each do |platform|
39
43
  sh "bundle exec rb-sys-dock --platform #{platform} --build"
data/ext/typst/src/lib.rs CHANGED
@@ -287,6 +287,10 @@ fn clear_cache(_ruby: &Ruby, max_age: usize) {
287
287
  comemo::evict(max_age);
288
288
  }
289
289
 
290
+ fn clear_font_cache(_ruby: &Ruby) {
291
+ world::clear_font_cache();
292
+ }
293
+
290
294
  #[magnus::init]
291
295
  fn init(ruby: &Ruby) -> Result<(), Error> {
292
296
  env_logger::init();
@@ -298,5 +302,6 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
298
302
  module.define_singleton_method("_to_html", function!(to_html, 8))?;
299
303
  module.define_singleton_method("_query", function!(query, 10))?;
300
304
  module.define_singleton_method("_clear_cache", function!(clear_cache, 1))?;
305
+ module.define_singleton_method("_clear_font_cache", function!(clear_font_cache, 0))?;
301
306
  Ok(())
302
307
  }
@@ -7,10 +7,10 @@ use chrono::{DateTime, Datelike, FixedOffset, Local};
7
7
  use typst::diag::{FileError, FileResult, StrResult};
8
8
  use typst::foundations::{Bytes, Datetime, Dict, Duration};
9
9
  use typst::syntax::{FileId, Lines, Source, VirtualPath, VirtualRoot, RootedPath};
10
- use typst::text::{Font, FontBook};
10
+ use typst::text::{Font, FontBook, FontInfo};
11
11
  use typst::utils::LazyHash;
12
12
  use typst::{Features, Library, LibraryExt, World};
13
- use typst_kit::fonts::{self, FontStore};
13
+ use typst_kit::fonts::{self, FontPath, FontStore};
14
14
  use typst_kit::packages::{FsPackages, SystemPackages, UniversePackages};
15
15
 
16
16
  /// A world that provides access to the operating system.
@@ -195,7 +195,7 @@ impl SystemWorldBuilder {
195
195
  }
196
196
 
197
197
  pub fn build(self) -> StrResult<SystemWorld> {
198
- let fonts = Arc::new(build_font_store(self.ignore_system_fonts, self.ignore_embedded_fonts, self.font_paths));
198
+ let fonts = font_store(self.ignore_system_fonts, self.ignore_embedded_fonts, self.font_paths);
199
199
 
200
200
  let package_storage = system_packages(self.package_path, self.package_cache_path);
201
201
 
@@ -217,13 +217,84 @@ impl SystemWorldBuilder {
217
217
  }
218
218
  }
219
219
 
220
+ /// Font discovery, which is far too slow to repeat on every compile.
221
+ ///
222
+ /// A full system font scan takes about 95 ms, which for a small document
223
+ /// dwarfs the compilation itself. `FontStore` cannot be cloned, so the
224
+ /// discovered fonts are kept alongside the assembled stores.
225
+ struct FontCache {
226
+ /// The locations found by walking the system font directories.
227
+ system: Option<Arc<Vec<(PathBuf, u32, FontInfo)>>>,
228
+ /// The fonts shipped with typst, already parsed.
229
+ embedded: Option<Arc<Vec<(Font, FontInfo)>>>,
230
+ /// A store per combination of the two ignore flags, for compiles that
231
+ /// bring no font paths of their own. Sharing one keeps the fonts a
232
+ /// document uses loaded between compiles and hashes the book only once.
233
+ stores: [Option<Arc<FontStore>>; 4],
234
+ }
235
+
236
+ const EMPTY_FONT_CACHE: FontCache =
237
+ FontCache { system: None, embedded: None, stores: [const { None }; 4] };
238
+
239
+ static FONT_CACHE: Mutex<FontCache> = Mutex::new(EMPTY_FONT_CACHE);
240
+
241
+ /// Forgets everything discovered so far, so that the next compile picks up
242
+ /// fonts installed or removed since.
243
+ pub fn clear_font_cache() {
244
+ *FONT_CACHE.lock().unwrap() = EMPTY_FONT_CACHE;
245
+ }
246
+
247
+ /// Reads a cache field, filling it on a miss.
248
+ ///
249
+ /// The lock is not held while building, so two threads missing at once both
250
+ /// build and one result is dropped. That wastes a scan but keeps a 95 ms
251
+ /// build off the lock.
252
+ fn cached<T>(
253
+ select: impl Fn(&mut FontCache) -> &mut Option<Arc<T>>,
254
+ build: impl FnOnce() -> T,
255
+ ) -> Arc<T> {
256
+ let hit = select(&mut FONT_CACHE.lock().unwrap()).clone();
257
+ if let Some(value) = hit {
258
+ return value;
259
+ }
260
+
261
+ let value = Arc::new(build());
262
+ *select(&mut FONT_CACHE.lock().unwrap()) = Some(value.clone());
263
+ value
264
+ }
265
+
266
+ /// Obtains a font store for the given configuration.
267
+ ///
268
+ /// Extra font paths are scanned on every compile. They are usually a
269
+ /// temporary directory written by `Typst.build_world_from_s`, so their
270
+ /// contents can change between compiles and caching on them would grow
271
+ /// without bound.
272
+ fn font_store(ignore_system_fonts: bool, ignore_embedded_fonts: bool, font_paths: Vec<PathBuf>) -> Arc<FontStore> {
273
+ if !font_paths.is_empty() {
274
+ return Arc::new(build_font_store(ignore_system_fonts, ignore_embedded_fonts, font_paths));
275
+ }
276
+
277
+ let index = usize::from(ignore_system_fonts) << 1 | usize::from(ignore_embedded_fonts);
278
+ cached(
279
+ move |cache| &mut cache.stores[index],
280
+ || build_font_store(ignore_system_fonts, ignore_embedded_fonts, Vec::new()),
281
+ )
282
+ }
283
+
220
284
  fn build_font_store(ignore_system_fonts: bool, ignore_embedded_fonts: bool, font_paths: Vec<PathBuf>) -> FontStore {
221
285
  let mut fonts = FontStore::new();
222
286
  if !ignore_system_fonts {
223
- fonts.extend(fonts::system());
287
+ let system = cached(
288
+ |cache| &mut cache.system,
289
+ || fonts::system().map(|(path, info)| (path.path, path.index, info)).collect(),
290
+ );
291
+ fonts.extend(system.iter().map(|(path, index, info)| {
292
+ (FontPath { path: path.clone(), index: *index }, info.clone())
293
+ }));
224
294
  }
225
295
  if !ignore_embedded_fonts {
226
- fonts.extend(fonts::embedded());
296
+ let embedded = cached(|cache| &mut cache.embedded, || fonts::embedded().collect());
297
+ fonts.extend(embedded.iter().cloned());
227
298
  }
228
299
  for path in font_paths {
229
300
  fonts.extend(fonts::scan(&path));
data/lib/typst.rb CHANGED
@@ -17,6 +17,12 @@ module Typst
17
17
  Typst::_clear_cache(max_age)
18
18
  end
19
19
 
20
+ # Discards the discovered system and embedded fonts, so that the next
21
+ # compile picks up fonts installed or removed since the first one.
22
+ def self.clear_font_cache
23
+ Typst::_clear_font_cache
24
+ end
25
+
20
26
  def self.build_world_from_s(main_source, **options, &blk)
21
27
  dependencies = options[:dependencies] ||= {}
22
28
  fonts = options[:fonts] ||= {}
@@ -30,16 +36,18 @@ module Typst
30
36
  File.binwrite(tmp_dep_file, dep_source)
31
37
  end
32
38
 
33
- relative_font_path = Pathname.new(tmp_dir).join("fonts")
34
- relative_font_path.mkpath
35
- fonts.each do |font_name, font_bytes|
36
- tmp_font_file = relative_font_path.join(font_name)
37
- File.binwrite(tmp_font_file, font_bytes)
39
+ unless fonts.empty?
40
+ relative_font_path = Pathname.new(tmp_dir).join("fonts")
41
+ relative_font_path.mkpath
42
+ fonts.each do |font_name, font_bytes|
43
+ tmp_font_file = relative_font_path.join(font_name)
44
+ File.binwrite(tmp_font_file, font_bytes)
45
+ end
46
+ options[:font_paths] = (options[:font_paths] || []) + [relative_font_path]
38
47
  end
39
48
 
40
49
  options[:file] = tmp_main_file
41
50
  options[:root] = tmp_dir
42
- options[:font_paths] = [relative_font_path]
43
51
 
44
52
  blk.call(options)
45
53
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typst
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1.6
4
+ version: 0.15.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Flinn
@@ -117,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
117
  - !ruby/object:Gem::Version
118
118
  version: '0'
119
119
  requirements: []
120
- rubygems_version: 4.0.19
120
+ rubygems_version: 4.0.20
121
121
  specification_version: 4
122
122
  summary: Ruby binding to typst, a new markup-based typesetting system that is powerful
123
123
  and easy to learn.