typst 0.14.2.3 → 0.15.1.0

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.
@@ -3,8 +3,10 @@ use ecow::{eco_format, EcoString};
3
3
  use serde::Serialize;
4
4
  use typst::diag::{bail, StrResult, Warned};
5
5
  use typst::engine::Sink;
6
- use typst::foundations::{Content, IntoValue, LocatableSelector, Scope};
7
- use typst::layout::PagedDocument;
6
+ use typst::foundations::{Content, Context, IntoValue, LocatableSelector, Scope};
7
+ use typst::introspection::{EmptyIntrospector, Introspector};
8
+ use typst::routines::SpanMode;
9
+ use typst_layout::PagedDocument;
8
10
  use typst::syntax::Span;
9
11
  use typst::syntax::SyntaxMode;
10
12
  use typst::World;
@@ -73,13 +75,15 @@ fn retrieve(
73
75
  document: &PagedDocument,
74
76
  ) -> StrResult<Vec<Content>> {
75
77
  let selector = eval_string(
76
- &typst::ROUTINES,
77
78
  world.track(),
79
+ world.library(),
78
80
  Sink::new().track_mut(),
81
+ EmptyIntrospector.track(),
82
+ Context::none().track(),
79
83
  &command.selector,
80
- Span::detached(),
84
+ SpanMode::Uniform(Span::detached()),
81
85
  SyntaxMode::Code,
82
- Scope::default(),
86
+ Scope::default()
83
87
  )
84
88
  .map_err(|errors| {
85
89
  let mut message = EcoString::from("failed to evaluate selector");
@@ -93,7 +97,7 @@ fn retrieve(
93
97
  .map_err(|e| e.message().clone())?;
94
98
 
95
99
  Ok(document
96
- .introspector
100
+ .introspector()
97
101
  .query(&selector.0)
98
102
  .into_iter()
99
103
  .collect::<Vec<_>>())
@@ -1,44 +1,34 @@
1
1
  use std::fs;
2
2
  use std::path::{Path, PathBuf};
3
- use std::sync::{Mutex, OnceLock};
3
+ use std::sync::{Arc, Mutex, OnceLock};
4
+ use std::collections::HashMap;
4
5
 
5
- use chrono::{DateTime, Datelike, Local};
6
- use ecow::eco_format;
6
+ use chrono::{DateTime, Datelike, FixedOffset, Local};
7
7
  use typst::diag::{FileError, FileResult, StrResult};
8
- use typst::foundations::{Bytes, Datetime, Dict};
9
- use typst::syntax::{FileId, Lines, Source, VirtualPath};
8
+ use typst::foundations::{Bytes, Datetime, Dict, Duration};
9
+ use typst::syntax::{FileId, Lines, Source, VirtualPath, VirtualRoot, RootedPath};
10
10
  use typst::text::{Font, FontBook};
11
11
  use typst::utils::LazyHash;
12
12
  use typst::{Features, Library, LibraryExt, World};
13
- use typst_kit::{
14
- fonts::{FontSearcher, FontSlot},
15
- package::PackageStorage,
16
- };
17
-
18
- use std::collections::HashMap;
19
-
20
- use crate::download::SlientDownload;
13
+ use typst_kit::fonts::{self, FontStore};
14
+ use typst_kit::packages::{FsPackages, SystemPackages, UniversePackages};
21
15
 
22
16
  /// A world that provides access to the operating system.
23
17
  pub struct SystemWorld {
24
18
  /// The working directory.
25
19
  workdir: Option<PathBuf>,
26
- /// The canonical path to the input file.
27
- input: PathBuf,
28
20
  /// The root relative to which absolute paths are resolved.
29
21
  root: PathBuf,
30
22
  /// The input path.
31
23
  main: FileId,
32
24
  /// Typst's standard library.
33
25
  library: LazyHash<Library>,
34
- /// Metadata about discovered fonts.
35
- book: LazyHash<FontBook>,
36
26
  /// Locations of and storage for lazily loaded fonts.
37
- fonts: Vec<FontSlot>,
27
+ fonts: Arc<FontStore>,
38
28
  /// Maps file ids to source files and buffers.
39
29
  slots: Mutex<HashMap<FileId, FileSlot>>,
40
30
  /// Holds information about where packages are stored.
41
- package_storage: PackageStorage,
31
+ package_storage: SystemPackages,
42
32
  /// The current datetime if requested. This is stored here to ensure it is
43
33
  /// always the same within one compilation. Reset between compilations.
44
34
  now: OnceLock<DateTime<Local>>,
@@ -50,7 +40,7 @@ impl World for SystemWorld {
50
40
  }
51
41
 
52
42
  fn book(&self) -> &LazyHash<FontBook> {
53
- &self.book
43
+ &self.fonts.book()
54
44
  }
55
45
 
56
46
  fn main(&self) -> FileId {
@@ -66,21 +56,30 @@ impl World for SystemWorld {
66
56
  }
67
57
 
68
58
  fn font(&self, index: usize) -> Option<Font> {
69
- self.fonts[index].get()
59
+ self.fonts.font(index)
70
60
  }
71
61
 
72
- fn today(&self, offset: Option<i64>) -> Option<Datetime> {
62
+ fn today(&self, offset: Option<Duration>) -> Option<Datetime> {
73
63
  let now = self.now.get_or_init(chrono::Local::now);
74
64
 
75
- let naive = match offset {
76
- None => now.naive_local(),
77
- Some(o) => now.naive_utc() + chrono::Duration::hours(o),
65
+ let now = match offset {
66
+ None => now.fixed_offset(),
67
+ Some(offset) => {
68
+ let seconds = offset.seconds().trunc();
69
+ if !seconds.is_finite()
70
+ || seconds < f64::from(i32::MIN)
71
+ || seconds > f64::from(i32::MAX)
72
+ {
73
+ return None;
74
+ }
75
+ now.with_timezone(&FixedOffset::east_opt(seconds as i32)?)
76
+ }
78
77
  };
79
78
 
80
79
  Datetime::from_ymd(
81
- naive.year(),
82
- naive.month().try_into().ok()?,
83
- naive.day().try_into().ok()?,
80
+ now.year(),
81
+ now.month().try_into().ok()?,
82
+ now.day().try_into().ok()?,
84
83
  )
85
84
  }
86
85
  }
@@ -122,23 +121,20 @@ impl SystemWorld {
122
121
  self.now.take();
123
122
  }
124
123
 
125
- /// Return the canonical path to the input file.
126
- pub fn input(&self) -> &PathBuf {
127
- &self.input
128
- }
129
-
130
124
  /// Lookup a source file by id.
131
125
  #[track_caller]
132
126
  pub fn lookup(&self, id: FileId) -> Lines<String> {
133
- // self.source(id)
134
- // .expect("file id does not point to any source file")
135
127
  self.slot(id, |slot| {
136
128
  if let Some(source) = slot.source.get() {
137
129
  let source = source.as_ref().expect("file is not valid");
138
130
  source.lines().clone()
139
131
  } else if let Some(bytes) = slot.file.get() {
140
132
  let bytes = bytes.as_ref().expect("file is not valid");
141
- Lines::try_from(bytes).expect("file is not valid utf-8")
133
+ Lines::new(
134
+ decode_utf8(bytes.as_slice())
135
+ .expect("file is not valid utf-8")
136
+ .to_string(),
137
+ )
142
138
  } else {
143
139
  panic!("file id does not point to any source file");
144
140
  }
@@ -151,8 +147,11 @@ pub struct SystemWorldBuilder {
151
147
  main: PathBuf,
152
148
  font_paths: Vec<PathBuf>,
153
149
  ignore_system_fonts: bool,
150
+ ignore_embedded_fonts: bool,
154
151
  inputs: Dict,
155
152
  features: Features,
153
+ package_path: Option<PathBuf>,
154
+ package_cache_path: Option<PathBuf>,
156
155
  }
157
156
 
158
157
  impl SystemWorldBuilder {
@@ -162,8 +161,11 @@ impl SystemWorldBuilder {
162
161
  main,
163
162
  font_paths: Vec::new(),
164
163
  ignore_system_fonts: false,
164
+ ignore_embedded_fonts: false,
165
165
  inputs: Dict::default(),
166
166
  features: Features::default(),
167
+ package_path: None,
168
+ package_cache_path: None,
167
169
  }
168
170
  }
169
171
 
@@ -177,6 +179,11 @@ impl SystemWorldBuilder {
177
179
  self
178
180
  }
179
181
 
182
+ pub fn ignore_embedded_fonts(mut self, ignore: bool) -> Self {
183
+ self.ignore_embedded_fonts = ignore;
184
+ self
185
+ }
186
+
180
187
  pub fn inputs(mut self, inputs: Dict) -> Self {
181
188
  self.inputs = inputs;
182
189
  self
@@ -188,33 +195,57 @@ impl SystemWorldBuilder {
188
195
  }
189
196
 
190
197
  pub fn build(self) -> StrResult<SystemWorld> {
191
- let fonts = FontSearcher::new()
192
- .include_system_fonts(!self.ignore_system_fonts)
193
- .search_with(&self.font_paths);
198
+ let fonts = Arc::new(build_font_store(self.ignore_system_fonts, self.ignore_embedded_fonts, self.font_paths));
199
+
200
+ let package_storage = system_packages(self.package_path, self.package_cache_path);
194
201
 
195
- let input = self.main.canonicalize().map_err(|_| {
196
- eco_format!("input file not found (searched at {})", self.main.display())
197
- })?;
198
202
  // Resolve the virtual path of the main file within the project root.
199
- let main_path = VirtualPath::within_root(&self.main, &self.root)
200
- .ok_or("input file must be contained in project root")?;
203
+ let main_path = VirtualPath::virtualize(&self.root, &self.main)
204
+ .map_err(|_| "input file must be contained in project root")?;
201
205
 
202
206
  let world = SystemWorld {
203
207
  workdir: std::env::current_dir().ok(),
204
- input,
205
208
  root: self.root,
206
- main: FileId::new(None, main_path),
209
+ main: RootedPath::new(VirtualRoot::Project, main_path).intern(),
207
210
  library: LazyHash::new(Library::builder().with_inputs(self.inputs).with_features(self.features).build()),
208
- book: LazyHash::new(fonts.book),
209
- fonts: fonts.fonts,
211
+ fonts,
210
212
  slots: Mutex::default(),
211
- package_storage: PackageStorage::new(None, None, crate::download::downloader()),
213
+ package_storage,
212
214
  now: OnceLock::new(),
213
215
  };
214
216
  Ok(world)
215
217
  }
216
218
  }
217
219
 
220
+ fn build_font_store(ignore_system_fonts: bool, ignore_embedded_fonts: bool, font_paths: Vec<PathBuf>) -> FontStore {
221
+ let mut fonts = FontStore::new();
222
+ if !ignore_system_fonts {
223
+ fonts.extend(fonts::system());
224
+ }
225
+ if !ignore_embedded_fonts {
226
+ fonts.extend(fonts::embedded());
227
+ }
228
+ for path in font_paths {
229
+ fonts.extend(fonts::scan(&path));
230
+ }
231
+ fonts
232
+ }
233
+
234
+ fn system_packages(
235
+ package_path: Option<PathBuf>,
236
+ package_cache_path: Option<PathBuf>,
237
+ ) -> SystemPackages {
238
+ SystemPackages::from_parts(
239
+ package_path
240
+ .map(FsPackages::new)
241
+ .or_else(FsPackages::system_data),
242
+ package_cache_path
243
+ .map(FsPackages::new)
244
+ .or_else(FsPackages::system_cache),
245
+ UniversePackages::new(crate::download::downloader()),
246
+ )
247
+ }
248
+
218
249
  /// Holds canonical data for all paths pointing to the same entity.
219
250
  ///
220
251
  /// Both fields can be populated if the file is both imported and read().
@@ -244,7 +275,7 @@ impl FileSlot {
244
275
  self.file.reset();
245
276
  }
246
277
 
247
- fn source(&mut self, root: &Path, package_storage: &PackageStorage) -> FileResult<Source> {
278
+ fn source(&mut self, root: &Path, package_storage: &SystemPackages) -> FileResult<Source> {
248
279
  let id = self.id;
249
280
  self.source.get_or_init(
250
281
  || system_path(root, id, package_storage),
@@ -260,7 +291,7 @@ impl FileSlot {
260
291
  )
261
292
  }
262
293
 
263
- fn file(&mut self, root: &Path, package_storage: &PackageStorage) -> FileResult<Bytes> {
294
+ fn file(&mut self, root: &Path, package_storage: &SystemPackages) -> FileResult<Bytes> {
264
295
  let id = self.id;
265
296
  self.file.get_or_init(
266
297
  || system_path(root, id, package_storage),
@@ -270,19 +301,21 @@ impl FileSlot {
270
301
  }
271
302
 
272
303
  /// The path of the slot on the system.
273
- fn system_path(root: &Path, id: FileId, package_storage: &PackageStorage) -> FileResult<PathBuf> {
304
+ fn system_path(root: &Path, id: FileId, package_storage: &SystemPackages) -> FileResult<PathBuf> {
274
305
  // Determine the root path relative to which the file path
275
306
  // will be resolved.
276
- let buf;
277
- let mut root = root;
278
- if let Some(spec) = id.package() {
279
- buf = package_storage.prepare_package(spec, &mut SlientDownload(&spec))?;
280
- root = &buf;
281
- }
307
+ let package_root;
308
+ let root = match id.root() {
309
+ VirtualRoot::Project => root,
310
+ VirtualRoot::Package(spec) => {
311
+ package_root = package_storage.obtain(spec)?;
312
+ package_root.path()
313
+ }
314
+ };
282
315
 
283
316
  // Join the path to the root. If it tries to escape, deny
284
317
  // access. Note: It can still escape via symlinks.
285
- id.vpath().resolve(root).ok_or(FileError::AccessDenied)
318
+ id.vpath().realize(root).map_err(Into::into)
286
319
  }
287
320
 
288
321
  /// Lazily processes data for a file.
data/lib/base.rb CHANGED
@@ -34,19 +34,28 @@ module Typst
34
34
  options[:dependencies] ||= {}
35
35
  options[:fonts] ||= {}
36
36
  options[:sys_inputs] ||= {}
37
- options[:resource_path] ||= File.dirname(__FILE__)
38
37
  options[:ignore_system_fonts] ||= false
38
+ options[:ignore_embedded_fonts] ||= false
39
+ options[:pretty] ||= false
39
40
 
40
41
  self.options = options
41
42
  end
42
43
 
44
+ def typst_options
45
+ [:file, :root, :font_paths, :ignore_system_fonts, :ignore_embedded_fonts]
46
+ end
47
+
43
48
  def typst_args
44
- [options[:file], options[:root], options[:font_paths], options[:resource_path], options[:ignore_system_fonts], options[:sys_inputs].map{ |k,v| [k.to_s,v.to_s] }.to_h]
49
+ options.values_at(*typst_options).append(options[:sys_inputs].map{ |k,v| [k.to_s,v.to_s] }.to_h)
50
+ end
51
+
52
+ def typst_pretty_args
53
+ options.values_at(*typst_options, :pretty).append(options[:sys_inputs].map{ |k,v| [k.to_s,v.to_s] }.to_h)
45
54
  end
46
55
 
47
56
  def typst_pdf_args
48
57
  options[:pdf_standards] ||= []
49
- [*typst_args, options[:pdf_standards]]
58
+ [*typst_pretty_args, options[:pdf_standards]]
50
59
  end
51
60
 
52
61
  def typst_png_args
@@ -100,6 +109,16 @@ module Typst
100
109
  self
101
110
  end
102
111
 
112
+ def pretty(pretty = true)
113
+ self.options[:pretty] = pretty
114
+ self
115
+ end
116
+
117
+ def ugly(pretty = false)
118
+ self.pretty(pretty)
119
+ self
120
+ end
121
+
103
122
  def compile(format, **options)
104
123
  raise "Invalid format" if Typst::formats[format].nil?
105
124
 
@@ -125,14 +144,14 @@ module Typst
125
144
  query_options = { field: field, one: one, format: format }
126
145
 
127
146
  if self.options.has_key?(:file)
128
- Typst::Query.new(selector, self.options[:file], **query_options.merge(self.options.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
147
+ Typst::Query.new(selector, self.options[:file], **query_options.merge(self.options.slice(:root, :font_paths, :ignore_system_fonts, :ignore_embedded_fonts, :sys_inputs)))
129
148
  elsif self.options.has_key?(:body)
130
149
  Typst::build_world_from_s(self.options[:body], **self.options) do |opts|
131
- Typst::Query.new(selector, opts[:file], **query_options.merge(opts.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
150
+ Typst::Query.new(selector, opts[:file], **query_options.merge(opts.slice(:root, :font_paths, :ignore_system_fonts, :ignore_embedded_fonts, :sys_inputs)))
132
151
  end
133
152
  elsif self.options.has_key?(:zip)
134
153
  Typst::build_world_from_zip(self.options[:zip], **self.options) do |opts|
135
- Typst::Query.new(selector, opts[:file], **query_options.merge(opts.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
154
+ Typst::Query.new(selector, opts[:file], **query_options.merge(opts.slice(:root, :font_paths, :ignore_system_fonts, :ignore_embedded_fonts, :sys_inputs)))
136
155
  end
137
156
  else
138
157
  raise "No input given"
@@ -2,7 +2,7 @@ module Typst
2
2
  class HtmlExperimental < Base
3
3
  def initialize(*options)
4
4
  super(*options)
5
- @compiled = HtmlExperimentalDocument.new(Typst::_to_html(*self.typst_args))
5
+ @compiled = HtmlExperimentalDocument.new(Typst::_to_html(*self.typst_pretty_args))
6
6
  end
7
7
  end
8
8
  class HtmlExperimentalDocument < Document
data/lib/formats/svg.rb CHANGED
@@ -2,7 +2,7 @@ module Typst
2
2
  class Svg < Base
3
3
  def initialize(*options)
4
4
  super(*options)
5
- @compiled = SvgDocument.new(Typst::_to_svg(*self.typst_args))
5
+ @compiled = SvgDocument.new(Typst::_to_svg(*self.typst_pretty_args))
6
6
  end
7
7
  end
8
8
  class SvgDocument < Document
data/lib/query.rb CHANGED
@@ -2,9 +2,9 @@ module Typst
2
2
  class Query < Base
3
3
  attr_accessor :format
4
4
 
5
- def initialize(selector, input, field: nil, one: false, format: "json", root: ".", font_paths: [], resource_path: ".", ignore_system_fonts: false, sys_inputs: {})
5
+ def initialize(selector, input, field: nil, one: false, format: "json", root: ".", font_paths: [], ignore_system_fonts: false, ignore_embedded_fonts: false, sys_inputs: {})
6
6
  self.format = format
7
- @result = Typst::_query(selector, field, one, format, input, root, font_paths, resource_path, ignore_system_fonts, sys_inputs)
7
+ @result = Typst::_query(selector, field, one, format, input, root, font_paths, ignore_system_fonts, ignore_embedded_fonts, sys_inputs)
8
8
  end
9
9
 
10
10
  def result(raw: false)
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.14.2.3
4
+ version: 0.15.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Flinn
@@ -18,7 +18,7 @@ dependencies:
18
18
  version: '0.9'
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.9.124
21
+ version: 0.9.128
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -28,7 +28,7 @@ dependencies:
28
28
  version: '0.9'
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: 0.9.124
31
+ version: 0.9.128
32
32
  - !ruby/object:Gem::Dependency
33
33
  name: rubyzip
34
34
  requirement: !ruby/object:Gem::Requirement
@@ -71,41 +71,15 @@ dependencies:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
73
  version: '3.6'
74
- - !ruby/object:Gem::Dependency
75
- name: os
76
- requirement: !ruby/object:Gem::Requirement
77
- requirements:
78
- - - "~>"
79
- - !ruby/object:Gem::Version
80
- version: '1.1'
81
- type: :development
82
- prerelease: false
83
- version_requirements: !ruby/object:Gem::Requirement
84
- requirements:
85
- - - "~>"
86
- - !ruby/object:Gem::Version
87
- version: '1.1'
88
- - !ruby/object:Gem::Dependency
89
- name: pngcheck
90
- requirement: !ruby/object:Gem::Requirement
91
- requirements:
92
- - - "~>"
93
- - !ruby/object:Gem::Version
94
- version: '0.3'
95
- type: :development
96
- prerelease: false
97
- version_requirements: !ruby/object:Gem::Requirement
98
- requirements:
99
- - - "~>"
100
- - !ruby/object:Gem::Version
101
- version: '0.3'
102
74
  email: flinn@actsasflinn.com
103
75
  executables: []
104
76
  extensions:
105
77
  - ext/typst/extconf.rb
106
78
  extra_rdoc_files: []
107
79
  files:
80
+ - Cargo.lock
108
81
  - Cargo.toml
82
+ - LICENSE
109
83
  - README.md
110
84
  - README.typ
111
85
  - Rakefile
@@ -113,27 +87,12 @@ files:
113
87
  - ext/typst/extconf.rb
114
88
  - ext/typst/src/compiler.rs
115
89
  - ext/typst/src/download.rs
116
- - ext/typst/src/fonts.rs
117
90
  - ext/typst/src/lib.rs
118
91
  - ext/typst/src/package.rs
119
92
  - ext/typst/src/query.rs
120
93
  - ext/typst/src/world.rs
121
94
  - lib/base.rb
122
95
  - lib/document.rb
123
- - lib/fonts/DejaVuSansMono-Bold.ttf
124
- - lib/fonts/DejaVuSansMono-BoldOblique.ttf
125
- - lib/fonts/DejaVuSansMono-Oblique.ttf
126
- - lib/fonts/DejaVuSansMono.ttf
127
- - lib/fonts/LinLibertine_R.ttf
128
- - lib/fonts/LinLibertine_RB.ttf
129
- - lib/fonts/LinLibertine_RBI.ttf
130
- - lib/fonts/LinLibertine_RI.ttf
131
- - lib/fonts/NewCM10-Bold.otf
132
- - lib/fonts/NewCM10-BoldItalic.otf
133
- - lib/fonts/NewCM10-Italic.otf
134
- - lib/fonts/NewCM10-Regular.otf
135
- - lib/fonts/NewCMMath-Book.otf
136
- - lib/fonts/NewCMMath-Regular.otf
137
96
  - lib/formats/html_experimental.rb
138
97
  - lib/formats/pdf.rb
139
98
  - lib/formats/png.rb
@@ -158,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
117
  - !ruby/object:Gem::Version
159
118
  version: '0'
160
119
  requirements: []
161
- rubygems_version: 4.0.4
120
+ rubygems_version: 4.0.15
162
121
  specification_version: 4
163
122
  summary: Ruby binding to typst, a new markup-based typesetting system that is powerful
164
123
  and easy to learn.
@@ -1,86 +0,0 @@
1
- use std::cell::OnceCell;
2
- use std::fs::{self};
3
- use std::path::PathBuf;
4
-
5
- use fontdb::{Database, Source};
6
- use typst::font::{Font, FontBook, FontInfo};
7
-
8
- /// Searches for fonts.
9
- pub struct FontSearcher {
10
- // Metadata about all discovered fonts.
11
- pub book: FontBook,
12
- /// Slots that the fonts are loaded into.
13
- pub fonts: Vec<FontSlot>,
14
- }
15
-
16
- /// Holds details about the location of a font and lazily the font itself.
17
- pub struct FontSlot {
18
- /// The path at which the font can be found on the system.
19
- path: PathBuf,
20
- /// The index of the font in its collection. Zero if the path does not point
21
- /// to a collection.
22
- index: u32,
23
- /// The lazily loaded font.
24
- font: OnceCell<Option<Font>>,
25
- }
26
-
27
- impl FontSlot {
28
- /// Get the font for this slot.
29
- pub fn get(&self) -> Option<Font> {
30
- self.font
31
- .get_or_init(|| {
32
- let data = fs::read(&self.path).ok()?.into();
33
- Font::new(data, self.index)
34
- })
35
- .clone()
36
- }
37
- }
38
-
39
- impl FontSearcher {
40
- /// Create a new, empty system searcher.
41
- pub fn new() -> Self {
42
- Self {
43
- book: FontBook::new(),
44
- fonts: vec![],
45
- }
46
- }
47
-
48
- /// Search everything that is available.
49
- pub fn search(&mut self, font_dirs: &[PathBuf], font_files: &[PathBuf]) {
50
- let mut db = Database::new();
51
-
52
- // Font paths have highest priority.
53
- for path in font_dirs {
54
- db.load_fonts_dir(path);
55
- }
56
-
57
- // System fonts have second priority.
58
- db.load_system_fonts();
59
-
60
- for path in font_files {
61
- let _ret = db.load_font_file(path).ok();
62
- }
63
-
64
- for face in db.faces() {
65
- let path = match &face.source {
66
- Source::File(path) | Source::SharedFile(path, _) => path,
67
- // We never add binary sources to the database, so there
68
- // shouln't be any.
69
- Source::Binary(_) => continue,
70
- };
71
-
72
- let info = db
73
- .with_face_data(face.id, FontInfo::new)
74
- .expect("database must contain this font");
75
-
76
- if let Some(info) = info {
77
- self.book.push(info);
78
- self.fonts.push(FontSlot {
79
- path: path.clone(),
80
- index: face.index,
81
- font: OnceCell::new(),
82
- });
83
- }
84
- }
85
- }
86
- }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file