linebender / linebender/parley

Fontique: duplication and redundant re-scanning in load_fonts_from_paths

Open
#683 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
736
Forks
120
Avg merge
1d 3h
Merged PRs (30d)
53

Description

## Description

When using `Collection::load_fonts_from_paths` to register fonts from a directory, the resulting Collection contains duplicate entries for the same font file.

```bash
❯ cargo run --release -- a --no-system -I Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB -vv
Finished `release` profile [optimized] target(s) in 0.22s
Running `target\release\fontfor.exe a --no-system -I Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB -vv`
Font(s) support the character "a"(U+0061, 97, 0x61):
LXGW WenKai GB
LXGW WenKai GB Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Regular.ttf:0
LXGW WenKai GB Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Regular.ttf:0
LXGW WenKai GB Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Regular.ttf:0
LXGW WenKai GB Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Regular.ttf:0
LXGW WenKai GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
LXGW WenKai GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
LXGW WenKai GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
LXGW WenKai GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
LXGW WenKai GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
LXGW WenKai GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
LXGW WenKai GB Medium Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
LXGW WenKai GB Medium Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
LXGW WenKai GB Medium Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
LXGW WenKai GB Medium Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
LXGW WenKai GB Medium Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
LXGW WenKai Mono GB
LXGW WenKai Mono GB Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Regular.ttf:0
LXGW WenKai Mono GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Light.ttf:0
LXGW WenKai Mono GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Light.ttf:0
LXGW WenKai Mono GB Light Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Light.ttf:0
LXGW WenKai Mono GB Medium Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Medium.ttf:0
LXGW WenKai Mono GB Medium Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Medium.ttf:0
```

## Cause

Currently, the `load_fonts_from_path` function contains a `families` map inside it, and each time the `scan_path` callback is triggered, the `register_font_impl` it calls adds all fonts in this `families` map to `self.families`. Throughout the entire process, `families` is never cleared.

At the same time, it is quite strange that while the `scan_path` callback already returns `ScannedFont`, `register_font_impl` still uses `scan_memory` to re-process all fonts in the data. This not only causes performance issues but also leads to further font duplication when processing TTC files...

For example, when I was testing on Linux, I encountered this spectacle:

❯ cargo run --release -- a --no-system -I /usr/share/fonts

Finished `release` profile [optimized] target(s) in 0.87s
Running `target/release/fontfor a --no-system -I /usr/share/fonts`
Font(s) support the character "a"(U+0061, 97, 0x61):
Adwaita Mono with 690 styles
Adwaita Sans with 339 styles
C059 with 138 styles
Cantarell with 1065 styles
D050000L with 32 styles
Droid Sans with 323 styles
Droid Sans Devanagari with 159 styles
Droid Sans Thai with 149 styles
Font Awesome 6 Brands with 168 styles
Font Awesome 6 Free with 333 styles
Jomolhari with 79 styles
Liberation Mono with 306 styles
Liberation Sans with 290 styles
Liberation Serif with 274 styles
Madan2 with 66 styles
Nimbus Mono PS with 118 styles
Nimbus Roman with 102 styles
Nimbus Sans with 86 styles
Nimbus Sans Narrow with 70 styles
Noto Sans with 224 styles
Noto Sans CJK HK with 695 styles
Noto Sans CJK JP with 695 styles
Noto Sans CJK KR with 695 styles
Noto Sans CJK SC with 695 styles
Noto Sans CJK TC with 695 styles
Noto Sans Math with 147 styles
Noto Sans Mono with 109 styles
Noto Sans Mono CJK HK with 670 styles
Noto Sans Mono CJK JP with 670 styles
Noto Sans Mono CJK KR with 670 styles
Noto Sans Mono CJK SC with 670 styles
Noto Sans Mono CJK TC with 670 styles
Noto Sans Sinhala with 106 styles
Noto Sans Symbols with 105 styles
Noto Serif with 178 styles
Noto Serif CJK HK with 645 styles
Noto Serif CJK JP with 645 styles
Noto Serif CJK KR with 645 styles
Noto Serif CJK SC with 645 styles
Noto Serif CJK TC with 645 styles
Open Sans with 605 styles
P052 with 54 styles
Padauk with 93 styles
PakType Naskh Basic with 55 styles
PakType Naskh Basic Semi Wide with 54 styles
PakType Naskh Basic Wide with 53 styles
RIT Meera New with 52 styles
RIT Rachana with 198 styles
STIX Two Math with 45 styles
STIX Two Text with 324 styles
Standard Symbols PS with 11 styles
Symbola with 165 styles
URW Bookman with 34 styles
URW Gothic with 18 styles
Vazirmatn with 1 style
Z003 with 2 styles

I had intended to submit a PR (implementing `ScannedFont` registration directly within the `scan_path` callback) to fix this issue. However, given that the current implementation is quite messy, I am not confident that I understand the rationale behind the current design, so I have opted to submit an issue instead.

Additionally, these [two lines of code](https://github.com/linebender/parley/blob/a5ea9a77abfe34e3d3ac742e9e8bbbed0d023838/fontique/src/collection/mod.rs#L494-L495) also seem very strange and redundant. This is just an extra found and is unrelated to the issue mentioned above.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in fontique/src/collection/mod.rs, focusing on Collection::load_fonts_from_paths, the scan_path callback, ScannedFont registration, and the redundant lines at 494-495. Trace how the families map and register_font_impl interact, then verify that each font file and TTC face is registered once without re-scanning; the issue does not name a specific test.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.